セレクトボックスの選択肢を連動させる(改)

以前の[id:Mug:20060414#1145023696]において作成していたスクリプトを改造しました。
デフォルト選択について、次のようなロジックを入れました。

  1. 指定された値をデフォルト選択可能にした。
  2. 指定が無い場合は、現在の値をなるだけ引き継ぐようにした。

Select.js(Shift_JIS)


/**
 * 選択肢クラス
 * @param parentValue 親の値(null:いつでも表示)
 * @param text 表示テキスト
 * @param value 値
 * @param style CSS(省略可)
 */
function SelectOption(parentValue, text, value, style) {
  
  this.parentValue = parentValue;
  
  this.setOption = function() {
    this.text = text;
    this.value = value;
    if(style) {
      this.style.cssText = style;
    }
  };
  
  return this;
}

/**
 * セレクトボックスクラス
 * @param id セレクトボックスID
 */
function SelectBox(id) {
  
  /**
   * IDに対応オブジェクトを取得
   * @return オブジェクトorNULL
   */
  function getObject() {
    var obj = document.getElementById(id);
    if(!obj.options && ( (typeof obj.length) == "number") ) {
      if(obj.length > 0) {
        obj = obj[0];
      } else {
        obj = null;
      }
    }
    return obj;
  }
  
  // オプションのリスト
  var options = [];
  
  /**
   * オプション登録
   * @param condition 表示条件
   */
  this.registOption = function(option) {
    options[options.length] = option;
  };
  
  // 子のオブジェクト
  var child = null;
  
  /**
   * 子のオブジェクトを設定する
   * @param childObj 子のオブジェクト
   */
  this.setChild = function(childObj) {
    child = childObj;
  };
  
  /**
   * オプション反映
   * @param parentValue 親の値(null:全部表示)
   *        ※比較に==を使っているのでundefinedもnullと等しく扱われる。
   * @params [defaultValues] 自身以下のデフォルト値(配列または可変数引数)
   *        例えば自身から孫までの値を設定するならば、
   *        xxx.make(null, ["自身の値", "子の値", "孫の値"]);  でもよいし、
   *        xxx.make(null,  "自身の値", "子の値", "孫の値" );  でもよい。
   */
  this.make = function(parentValue, defaultValues) {
    var obj = getObject();
    if(obj) {
      // デフォルト値調整
      var defVals;
      switch(arguments.length) {
      case 0:
      case 1:
        defVals = [];
        break;
      case 2:
        if(defaultValues instanceof Array) {
          defVals = defaultValues;
        } else if(defaultValues && ( (typeof defaultValues) == "object") && ( (typeof defaultValues.length) == "number") ) {
          defVals = defaultValues;
        } else {
          defVals = [defaultValues];
        }
        break;
      default:
        defVals = Function.prototype.call.apply(function() { return arguments; }, arguments);
      }
      // 選択すべき値
      var vals = {};
      if(defVals.length > 0) {
        vals[ defVals[0] ] = true;
        defVals = Function.prototype.call.apply(function() { return arguments; }, defVals);
      } else {
        for(var i = 0; i < obj.options.length; i++) {
          if(obj.options[i].selected) {
            vals[obj.options[i].value] = true;
          }
        }
      }
      // 選択肢削除
      obj.options.length = 0;
      // 表示すべき選択肢抽出
      var opt = (parentValue != null) ? [] : options;
      if(parentValue != null) {
        for(var i = 0; i < options.length; i++) {
          if( (options[i].parentValue == null) || (options[i].parentValue == parentValue) ) {
            opt[opt.length] = options[i];
          }
        }
      }
      // 選択肢反映
      obj.options.length = opt.length;
      for(var i = 0; i < opt.length; i++) {
        opt[i].setOption.call(obj.options[i]);
        obj.options[i].selected = (vals.hasOwnProperty(obj.options[i].value) && vals[obj.options[i].value]);
      }
      // 子のオブジェクトにも連鎖反映
      if(child) {
        child.make(obj.value, defVals);
      }
    }
  };
  
  return this;
}

HTMLファイル(使用例)

<html>
<head>
<title>セレクトボックス親子関係</title>
<script type="text/javascript" src="Select.js" charset="Shift_JIS"></script>
<script type="text/javascript"><!--

var box1 = new SelectBox("sb1");
box1.registOption(new SelectOption(null, "都道府県", "0", "color:gray;"));
box1.registOption(new SelectOption(null, "東京都"  , "1"));
box1.registOption(new SelectOption(null, "神奈川県", "2"));
box1.registOption(new SelectOption(null, "埼玉県"  , "3"));
box1.registOption(new SelectOption(null, "千葉県"  , "4"));

var box2 = new SelectBox("sb2");
box2.registOption(new SelectOption(null, "区市町村", "0", "color:gray;"));
box2.registOption(new SelectOption("1" , "千代田区", "1"));
box2.registOption(new SelectOption("1" , "中央区"  , "2"));
box2.registOption(new SelectOption("2" , "横浜市"  , "3"));
box2.registOption(new SelectOption("2" , "川崎市"  , "4"));
box2.registOption(new SelectOption("3" , "与野市"  , "5"));
box2.registOption(new SelectOption("4" , "千葉市"  , "6"));

var box3 = new SelectBox("sb3");
box3.registOption(new SelectOption(null, "詳細"    , "0", "color:gray;"));
box3.registOption(new SelectOption("1" , "一番町"  , "1"));
box3.registOption(new SelectOption("3" , "みなとみらい", "2"));
box3.registOption(new SelectOption("6" , "マリンスタジアム", "3"));

box1.setChild(box2);
box2.setChild(box3);

window.onload = function() {
  box1.make(null, "2", "3");
};

//--></script>
</head>
<body>
<form>
<select id="sb1" onchange="box2.make(this.value);"></select>
<select id="sb2" onchange="box3.make(this.value);"></select>
<select id="sb3"></select>
</form>
</body>
</html>

このように、boxObj.make(親の値, 自身の値, 子の値, 孫の値, ...);とすることで、デフォルト値を設定可能としました。