Corredor

ウェブ、プログラミングの勉強メモ。

アンケートサイトで使える!性別のラジオボタンを自動選択するブックマークレット

アンケートサイトで使えそうなブックマークレット、第4弾。「あなたの性別を選択してください」といった設問で、ラジオボタンを自動選択するブックマークレットを作った。

サンプル

サンプルは以下の CodePen より、「Select Gender」を操作してみてほしい。

See the Pen Survey Helpers by Neos21 (@Neos21) on CodePen.

ブックマークレットコード

ブックマークレット用のコードは以下。

javascript:((G,L,A)=>{A=[],Array.prototype.forEach.call(document.querySelectorAll('input[type="radio"]'),(e,n,r,o)=>{if(!A.includes(e.name))for(n=e,r=!1,o=L;o--;)r||((n=n.parentNode).innerHTML.includes(G?'女':'男')?r=!0:n.innerHTML.includes(G?'男':'女')&&(e.checked=!0,r=!0,A.push(e.name)))})})(!1,3);

末尾の (!1,3) 部分がユーザ設定項目。!1 と書くと false の意味になるので、「女性」ラジオボタンを選択する。!0 だと true の意味になるので、「男性」ラジオボタンを選択する。選択したい方の性別にあった Boolean 値を設定する。

3 は、テキストボックスの周辺を探索する範囲を指定するモノ。前回の記事で触れたのと同じ仕組みで、対象のラジオボタンからどれだけ親要素に遡って探索するか、という指定。上手くラジオボタンが選択できないようであれば、3〜10くらいの間で数値を増やしていってもらえれば上手く行くかと。

ソースコード

元のコードは以下のとおり。

/**
 * 任意の性別のラジオボタンを選択する
 * 
 * @param gender true で男・false で女を選択する
 * @param loop 親要素を遡るループ回数。テキストボックスを起点に、親要素に遡って innerHTML に「歳 or 才」の字がないか探すので、
 *             対象のページ構造に合わせてループ回数を指定しておく。大体 3〜5 階層くらいで良いかと
 */
function selectGender(gender, loop, ARRAY) {
  // 引数 ARRAY は引数としては利用せず、ローカル変数の宣言回避のために引数の形を取っている
  ARRAY = [];
  
  Array.prototype.forEach.call(document.querySelectorAll('input[type="radio"]'), (radio, parent, finished, i) => {
    if(!ARRAY.includes(radio.name)) {
      parent = radio;
      finished = false;
      for(i = loop; i--;) {  // 親要素を遡る
        if(!finished) {
          parent = parent.parentNode;
          
          if(parent.innerHTML.includes(gender ? '女' : '男')) {
            // 選択した方と逆の性別が含まれている場合
            // このラジオボタンを起点とした探索を終わらせる
            finished = true;
          }
          else if(parent.innerHTML.includes(gender ? '男' : '女')) {
            // 選択した方の性別が含まれている場合
            radio.checked = true;
            finished = true;
            // 一度選択したラジオボタン群を無視するため、ラジオボタンの名前を控えておく
            ARRAY.push(radio.name);
          }
        }
      }
    }
  });
}

基本的なやり方は前回の「年齢自動入力ブックマークレット」と同様。input[type="radio"] な要素を取得し、その親要素に遡って innerHTML を調べた時に、'男''女' の文言を含んでいれば、それを性別選択のラジオボタンと認識して操作する、というモノ。

今回はラジオボタンなので、同じ name 属性を持つ input[type="radio"] が最低2つは登場することになるであろう。そのため、操作したラジオボタンの name 属性を控えておき、一度操作したラジオボタン群は次以降無視するようにした。

単純に親要素に遡って innerHTML を見ていく関係上、選択したい性別とは別の項目まで調べてしまうことがあったので、その解決にちょっと手間取った。

どういうことかというと、例えば、性別選択ラジオボタンは以下のような HTML 構造になっていることが多いであろう。

<ul>
  <li><input type="radio" name="gender" value="1"> 男性</li>
  <li><input type="radio" name="gender" value="2"> 女性</li>
</ul>

ココで「女性を選択したい」とする。input[type="radio"] を順に取得するので、最初は value="1"、つまり「男性」用のラジオボタンを取得する。このラジオボタンを起点に親要素に遡っていくと、「」の文字が見つからないので ul 要素まで遡る。そうすると ul 要素の innerHTML から「女性」の文言が拾えてしまい、男性用のラジオボタンを間違って選択してしまうのである。

コレを回避するため、「選択していない性別が出てきたら、そのラジオボタンに対する処理を止める」という作りにした。つまり、「女性」を選択した時に、そのラジオボタンの近くに「男性」の文言が見つかったら、そのラジオボタンの処理を中断し、次のラジオボタンの探索に移る。そして2つ目のラジオボタンの周辺から「女性」を見つけたら、処理を中断しつつ、「操作済みのラジオボタン」として配列に name 属性を控えておくのである。こうしておけば、性別選択の中に「その他」などがあっても無視できる、というワケ。

やっていることは些細なことだが、コレでラジオボタンをイチイチポチポチしなくて良くなった。

入門者のJavaScript (ブルーバックス)

入門者のJavaScript (ブルーバックス)