「JavaScriptの“window.open”を使ってみた。」の記事を書こうとしたが、いや途中まで書いていたが、ドラフト保存がぶっ飛んだので不貞寝したのは昨日の話。

改めて、今日は“メモ帳”にしっかり下書きしたうえで(笑)この記事を書いてます。

“ボウリングの紆余曲折”の“スコア分析”ページ拡充計画が遅々として進まないが、今日は一歩前進した。

これまで、最初に“投球者の選択”をしてから分析・閲覧画面へ進むように構成していたが、途中で投球者を変更したい時に、いちいち最初のページへ戻らなくてはならなかった。

これを、分析・閲覧途中でも投球者を変更できるようにした。

具体的には次の通り。

まず、“投球者の変更”をクリックすると新規ポップアップウィンドウが立ち上がるようにした。ポップアップウィンドウに関しては次のサイトを参考にさせていただいた。

window.open()で小窓
http://amenti.usamimi.info/windowopen.html

JavaScript用外部ファイルに、以下のように記述した。

function newWindow(url,windowname,width,height) {
  var features = "location=no, menubar=no, status=no, scrollbars=no, resizable=yes, toolbar=no";
  if(width){
    if(window.screen.width > width){
      features += ", left="+(window.screen.width-width)/2;
    }else{
      width = window.screen.width;
    }
    features += ", width="+width;
  }
  if(height){
    if(window.screen.height > height){
      features+=", top="+(window.screen.height-height)/2;
    }else{
      height=window.screen.height;
    }
    features+=", height="+height;
  }
  window.open(url,windowname,features);
}

上記サイトの著者様は、ご丁寧に新規ウィンドウが画面中央に配置されるようにしてくれている。

window.openの第2引数“windowname”は文字通り「ウィンドウ名」であり、これは省略してもかまわないということがいくつかのサイトで散見されたが、chromeの「設定(レンチのアイコン)」⇒「オプション」⇒「高度な設定」⇒「プライバシー」⇒「コンテンツの設定」⇒「すべてのサイトのポップアップ表示を許可しない(推奨)」”にチェックが入っている場合、これを省略すると新規ポップアップウィンドウではなく“新しいタブ”が開いてしまった

他のブラウザ(IE、firafox、safari、opera)でも同様のことが起こったため、「ウィンドウ名」が必要ない場合は第2引数に“null”と記述しておくべきであろう。

また、第2引数に“半角英数以外”の文字を使うとIEでエラーが出るとの報告も多数みられたので注意。

んで、html(phpで記述)には次のようなコードを記述した。

print "⇒ <a href=\"{$dirPath}change.php?from={$thisfile}&amp;length={$length}&amp;order={$order}\" 
onclick=\"newWindow(this.href,null,300,200); return false;\">投球者を変更する</a>)</p>\n";

※2011/11/18 追記
その後、lengthとorderは$_SESSIONを使用することとしたため、getで渡す変数(?以降fromも含めて)は削除した。

href属性に直接“href="javascript:void(0);"”とやっちまうとAnother HTML-lint gateway様に忠告を受けるということは10/31の記事に書いたとおり。

要は、“JavaScript無効の場合はどうすんのよ?”ということ。

従って、href属性にはリンク先のURIを記述しておき、window.open()の第一引数には this.hrefを渡し、そして、window.open()の後にreturn false;と記述することでhref属性へのイベントを抑制する。

そうすることでJavaScriptが有効の場合は新規ポップアップウィンドウが開き、無効の場合は普通のハイパーリンクとして記述されたURIにリンクされる。

一方、change.php(投球者変更画面)には、以下のように記述する(一部抜粋)。

// 【※1】
require ('www/bowling/files/player.inc');

// 【※2】
$clean = array();
($_POSTと$_GETをフィルタリングして$cleanに格納する処理)

$gvalue = ($clean['length'] != "" && $clean['order'] != "") ? "?length={$clean['length']}&order={$clean['order']}" : "";

if(isset($clean['player'])){
  $player = $clean['player'];
  $_SESSION['player'] = "";
}else{  
  $player = $_SESSION['player'];
}

if(!isset($clean['playerChange']) || $player == ""){

  print "<form method=\"post\" action=\"{$dirPath}{$thisfile}\">\n";
  print "<select name=\"player\">\n";
  print "  <option value=\"\" selected=\"selected\">↓</option>\n";
  foreach($playerList as $key => $val){
    // 【※3】
    if($player != $key) print "  <option value=\"{$key}\">{$val['playerName']}</option>\n";
  }
  print "</select>\n";
  print "<input type=\"hidden\" name=\"from\" value=\"{$clean['from']}\" />\n";
  print "<input type=\"hidden\" name=\"length\" value=\"{$clean['length']}\" />\n";
  print "<input type=\"hidden\" name=\"order\" value=\"{$clean['order']}\" />\n";
  print "<input type=\"submit\" name=\"playerChange\" value=\"投球者を変更\" />\n";
  print "</form>\n";

}else{
  // 【※4】
  $_SESSION['player'] = $player;
  $_SESSION['tableName'] = $playerList[$player]['tableName'];
  $_SESSION['playerName'] = $playerList[$player]['playerName'];

  print "<script type=\"text/javascript\">\n";
  print "  window.close();\n";
  // 【※5】
  print "  window.opener.location.href = \"{$dirPath}{$clean['from']}{$gvalue}\";\n";
  print "</script>\n";

}

※2011/11/18 追記
上記の通り、lengthとorderは$_SESSIONを使用することとしたため、8行目および27~29行目全て削除し、42行目をwindow.opener.location.reload();に変更した。

“ボウリングスコア閲覧・分析”ページでは投球者の情報を番号としてセッションで管理し、
必要に応じてplayer.incファイルに記述された2次元配列$playerListから投球者名およびmySQLのテーブル名を参照している。
(参考:“インクルードファイルをrequireしてひと工夫”)【※1】

変数lengthと変数orderはそれぞれ閲覧画面での表示件数、昇順/降順をあらわすものである。

ここでは、その情報を保ったまま投球者の変更を行いたかったため、元のページから$_GETでchange.phpに渡した。

$_GETもしくは$_POSTの値は適切なフィルタリング処理をし(当サイトのセキュリティに関わるため詳細は割愛)、それぞれの値を$clean配列に格納する。【※2】

投球者変更プルダウンメニューに、現在選択されている投球者は表示しないようにしたのもちょっとしたポイント。【※3】

投球者変更ボタンを押された後は、$_SESSIONを一旦空にした後新たな情報を格納する。【※4】

最後にwindow.close()でこのウィンドウを閉じて元のページへ戻るのだが、戻ったページ先では当然変更内容が反映されていなければならない。

つまりページをリロードする必要があるのだがその方法の1つは“window.opener.location.reload();”である。

これはサブウィンドウから親ウィンドウをリロードするJavaScriptのコードであるが、この場合だと単に“リロード”されるだけになってしまい、変数lengthと変数orderを元のページに渡せない。

従って、ここでは“window.opener.location.href = URL;”を使うこととした。【※5】

サブウィンドウから親ウィンドウのページURLを変更するコードだが、このときにgetで上記変数をURLに埋め込むことで元のページに変数を渡すことができる。

※2011/11/18 追記
上記の通り、lengthとorderは$_SESSIONを使用することとしたため、元のページに変数を渡す必要がなくなり、window.opener.location.reload();を使用することにした。

以上で、投球者変更画面の作成は完了。

ボウリングスコア閲覧・分析”でお試しあれ。

ほな、寝る。