今回は、シビアな業務用システムにJavaScriptを
使う場合のテクニックにフォーカスしてみた。
一般のWebページと業務用アプリでは普通はユーザーが
異なっている。たとえば、Webページでは世界中のあらゆ
るマシンのユーザーから閲覧される可能性があるのに対し
て、業務用アプリでは、ユーザーあるいは入力オペレータ
はあらかじめ限定されている場合が多い。したがって、
Webページでクロスブラウザが要求されるのは必然だが、
業務用アプリではむしろブラウザの種類はあらかじめ1つ
あるいは数種を限定することで安定的な運用を目指すこ
とも少なくない。
業務用のプログラムはWebに比べるときわめてシビアな
ハードルを要求される世界だ。誤入力防止の仕掛けなどは
当然のことだし、入力スピードの向上といったらミリ秒単
位の違いでも生産性に大きな影響を及ぼすことがあるから
だ。
今回用意したサンプルは業務用ということでサーバー
サイドのPHP/PerlやDBなども利用している。それらのプロ
グラムへデータを渡す前に、クライアントサイドのJavaScript
で何をしているのかをみてほしい。ただ、すべてのソース
を記事内では解説できないので、是非Web(http://book.mycom.co.jp/wd/)
上のサンプルを開いてソースを開いてみることをお勧めする。
今回のテーマのポイント
1.業務用の専用ウインドウを作る方法
2.「改行キーで項目移動」による入力スピードアップ
3.簡易Webメモシステムに入力補助スクリプトを仕込む
位置やサイズetc...を指定して入力用ウインドウを開く
サブウインドウにオプションを指定して入力専用のダイアログとして利用する
■入力用ウインドウを自由に整形する
まず、入力のためのフォームを用意しよう。
業務用だからブラウザのツールバーやロケ−
ションバ−などは必要ない。むしろ誤入力の
もとでもあるからそれらの無いプレーンなウ
インドウをJavaScriptで指定する。
この時、すでに開いているウィンドウのバ
ー類を取り去ることはセキュリティ上の制約
があるため新しいサブウインドウを開くこと
にしよう。ウインドウサイズや画面上の位置
などもこの時指定するのが便利だ。
この時サブウインドウを開いた親ウインド
ウは閉じる必要があるがこれもセキュリティ
上の制約があるのでちょっとしたテクニック
が必要だ。
それでは、サンプルを使って順番にみてい
こう。サンプルの関数は入力用ウインドウを
開くための処理を使いやすいようにまとめて
ある。基本的には、window.open()メソッドを
利用して思い通りのサブウインドウを開くと
いうものだ。open()の書式は次のようになっ
ている。
open("URL", "target名", "window機能")
引数"URL"は、指定したURLが開いたウイン
ドウに読み込まれる。"target名"に指定した
名前はいわゆるAタグなどでおなじみのター
ゲット名だ。Aタグのターゲット名としてこ
のウインドウのtarget名を指定すれば、Aタ
グをクリックした時にリンク先はこのウイン
ドウへ読み込まれる。サンプルをみてみよう。
【./sample/f1/f1.htm】
<script type="text/javascript">
<!--
window.open("test0.htm", "test", "width=200,height=400")
//-->
</script>
<a href="test1.htm" target="test">test1</a><br>
<a href="test2.htm" target="test">test2</a><br>
<a href="test3.htm" target="test">test3</a><br>
↑このスクリプトサンプル ./sample/f1/f1.htm
【f1.htmの動作ブラウザ】
win mac linux
n4 n6 n7 m1 e5 e6 o7 n4 n6 n7 m1 e5 s1 n4 n6 n7 m1 k3
○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
*表にはないがこのスクリプトはJavaScriptの最初のバージョンからの実装なの
n2,n3,n4,e3などでも動作する。
そして、次の"window機能"の部分にウイン
ドウの位置や幅などの機能が指定されるのだ
が、この部分は指定しやすいようにここでは
関数内で少し手を入れてある。
関数の中のwidth、height、left、topとい
った変数の値を好きなピクセル数に書き換え
ればウインドウの幅、高さ、位置を指定して
開くことができ、toolbar、loction以下の変
数はそれぞれコメントに書いてある機能を指
定するものだ。たとえば、toolbarを表示した
ければ1、表示したくなければ0を指定すると
いった具合だ。
入力用のウインドウにtoolbarなどは普通
はいらないからこのサンプルでは0に設定し
てある。また、コメントにもあるとおり
left,topを少しいじってやるとウインドウを
スクリーンの中央で開くようにすることも
可能だ。
【./sample/form/index.htm】
<html>
<head>
<title>業務用入力フォーム-フォームウインドウオープン</title>
<script>
<!--
/***********************************************************
業務用入力フォーム-フォームウインドウオープン
*/
//--入力用ファイル名
var fileName = 'input.htm'
//--入力フォームウインドウオープン
function subWindowOpen(url,targetName){
var width = 600 //サブウインドウ横幅のピクセル数
var height = 400 //サブウインドウ高さのピクセル数
var left = 170 //スクリ−ン左端からのピクセル数
var top = 180 //スクリ−ン上端からのピクセル数
var toolbar = 0 //ツ−ルバ−を付けるなら1
var loction = 0 //ロケ−ションバ−を付けるなら1
var directories = 0 //directoriesボタンを付けるなら1
var status = 0 //ステ−タス行を付けるなら1
var menubar = 0 //メニュ−バ−を付けるなら1
var scrollbars = 0 //スクロ−ルバ−を付けるなら1
var resizable = 1 //リサイズ可能にするなら1
win =
window.open('',targetName,
'left='+left+',top='+top+
',screenX='+left+',screenY='+top+
',toolbar='+toolbar+',loction='+loction+
',directories='+directories+',status='+status+
',menubar='+menubar+',scrollbars='+scrollbars+
',resizable='+resizable+
',width='+width+
',height='+height
)
/*--たとえば、上のleft,topを次のように指定すれば
スクリーンの中央で開きます。
var left = ( screen.availWidth - width )/2
var top = ( screen.availHeight - height )/2
*/
win.location.href = url; //入力用ファイルを読み込む
win.focus(); //入力フォームウインドウへフォーカス
self.opener=self; //親ウインドウクローズのおまじない
self.close(); //親ウインドウクローズ
}
//--起動
subWindowOpen( fileName , targetName )
/***********************************************************/
//-->
</script>
</head>
<body bgcolor="#ffffff">
</body>
</html>
↑このスクリプトサンプル ./sample/form/index.htm
【./sample/form/index.htmの動作ブラウザ】 ←動作ブラウザ表は記事に入れたい
win mac linux
n4 n6 n7 m1 e5 e6 o7 n4 n6 n7 m1 e5 s1 n4 n6 n7 m1 k3
○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
*表にはないがこのスクリプトはJavaScriptの最初のバージョンからの実装なの
n2,n3,n4,e3などでも動作する。
入力のスピードアップ
改行キーで移動するなど入力サポートをJavaScriptで強化する
前ページで用意したサブウインドウへ入力用
フォームの.htmlを読み込んでみよう。
サンプルとして簡単な顧客データの入力を
作ってみた(実際のサンプルはCSSとテーブル
で修飾していますのでWeb上で確認しよう)。
ポイントは改行キーで次の入力フィールド
へ移動するなど入力のスピードアップを意識
していることだ。
実際に入力してみるとカーソルで移動する
のに比べると格段にスムーズな入力になって
いるはずだ。Webではそれほど気にならない
こんなことも業務では要注意だ。もし1データ
10項目で入力に0.5秒/項目のロスが出るなら
10万件の入力で139時間つまり8時間労働とし
て実に17日ものロスが生まれる。納期に追い
かけられている現場では1秒も無駄にはでき
ないのだ。
【./sample/f2/f2.htm】
<script type="text/javascript">
<!--
//最初の入力エレメントを設定してください
var startElement = "document.test.a1"
var next = null // 項目の移動先
var submitFlg = false // 送信許可フラグ(初期値は不可)
//ブラウザチェック
var moz = navigator.userAgent.indexOf('Gecko')!=-1 //moz
var n4 = !!document.layers //n4
//Webぺージを読み込んだ後にestart()を実行
window.onload=estart
//onload後に最初に実行する関数
function estart()
{
self.focus() //入力用ウインドウへフォーカスする
setNext(eval(startElement)) //次のフィールドをセット
next.focus() //最初の入力エレメントへフォーカスする
// キーが入力された場合はfocusToNext()を実行
document.onkeypress = focusToNext
if (document.layers) document.captureEvents(Event.KEYPRESS) // N4用
}
//次のフィールドをセット
function setNext(oj,nextName)
{
if(!!arguments[1])next = oj.form.elements[nextName]
else next = oj
hoverInputBgcl(oj,"#ffff00")
}
//ホーバー時の背景色変更
function hoverInputBgcl(oj,color)
{
oj.style.backgroundColor=color
}
//改行キーで次のフィールドへ移動
function focusToNext(e){
if(getKEYCODE(e)==13){
next.focus()
setSubmitFlg(e)
}
}
//--押されたキ−コードを返す
function getKEYCODE(e){
var ua = navigator.userAgent
if(ua.search('opera(\ |\/)6')!=-1) //o6不可
return null
else if(document.layers) //n4用
return e.which
else if(document.all) //e4,e5,e6,o7,s1用
return event.keyCode
else if(document.getElementById) //n6,n7,moz用
return e.which
else return null //上記以外
}
//送信許可フラグのセット
function setSubmitFlg(e)
{
if((moz||n4?e.target:event.srcElement).type=='submit')
submitFlg= true
else submitFlg= false
}
//誤送信防止用送信確認ダイアログ
function submitchk()
{
if( confirm('入力OKですか? OKなら送信します。') )
{
document.test.submit() //送信
} else {
eval(startElement).focus() //最初の入力エレメントへフォーカス
}
}
//-->
</script>
<form name="test"
action="http://game.gr.jp/buffer.cgi"
onsubmit="return submitFlg">
id :
<input type = "text" name = "a1" style = "ime-mode:disabled"
onfocus = "setNext(this,'a2')"
onblur = "hoverInputBgcl(this,'#ffcc33')"
tabindex= "0"><br>
なまえ :
<input type = "text" name = "a2" style = "width:200px;ime-mode:active"
onfocus = "setNext(this,'a3')"
onblur = "hoverInputBgcl(this,'#ffcc33')"
tabindex= "1"><br>
:
略
:
TEL :
<input type = "text" name = "a6" style = "ime-mode:disabled"
onfocus = "setNext(this,'sub')"
onblur = "hoverInputBgcl(this,'#ffcc33')"
tabindex= "5"><br>
<input type = "button" name = "sub" value = "登録"
style = "background-color:orange;color:#000000"
onfocus = "hoverInputBgcl(this,'#ff6600')"
onblur = "hoverInputBgcl(this,'orange')"
tabindex= "6"
onClick = "submitchk()"><br>
</form>
* 入力後、Enter(return)キーでカーソル移動します
↑このスクリプトサンプル ./sample/f2/f2.htm
【./sample/f2/f2.htmの動作ブラウザ】 ←動作ブラウザ表は記事に入れたい
win mac linux
n4 n6 n7 m1 e5 e6 o7 n4 n6 n7 m1 e5 s1 n4 n6 n7 m1 k3
× ○ ○ ○ ○ ○ ○ × ○ ○ ○ ○ × × ○ ○ ○ ×
*IMEモードの自動変換はwin-e5以上のみ
*o7は親ウインドウの自動クローズは不可
いろいろな入力補助
日付入力補助や確認ダイアログ、オプションの動的切り替えなど
入力を補助するテクニックはいくつもあるが
ここではいくつかまとめて組み合わせたサン
プル【./sample/f3/f3.htm】を紹介しよう。前ページ
と同様に専用のサブウインドウを開いて読み込
んでいる。
このサンプルでは日付入力補助や確認ダイア
ログ、オプションの動的切り替えといったテク
ニックが使われている。
まず、日付入力補助は以前にも紹介している
が筆者が提供している日付をカレンダーレイヤ
ーから選択しクリックするだけで入力できると
いうスクリプトだ。(スクリプト配布元 http://game.gr.jp/cal/ )
.js外部ファイルになっており簡単に使いまわ
すことができるので人気の高いツールのひとつだ。
次に、このサンプルではデータを削除するため
のボタンをクリックすると「削除するならOKボタ
ンを押してくれ」という誤削除防止のための確認
関数が仕込まれている。2箇所あるがdeldata()と
delall()の二つの関数がそれだ。
要するに、ボタンをクリックするとconfirm
ダイアログが開き、そこで「OK」が押されれば
location.hrefプロパティに設定した処理が読み
込まれ、「キャンセル」なら何も起こらないと
いうわけだ。
ここでは、データ削除はdelete.php、全削除
はdeleteall.phpという処理プログラムに実行
させて、処理後元のページを再読み込みして戻
ってくるという仕組みになっている。(サーバー
サイドについての説明は省略)
また、このサンプルにはオプションの動的切
り替えも使ってみている。たとえば試しに「大
分類」の「JavaScript」や「DHTML」を選択して
みて欲しい。「中分類」の選択肢が自動的に書
き換わるのだ。
この仕組みはaddOp()とdelOp()という二つの
関数で行っている。delOpでオプションを全て
削除し、addOpで必要なオプションを追加する
という仕掛けだ。
<!-- カレンダーによる日付入力スクリプト(レイヤー版)読み込み -->
<script src="calendarlay.js" language="JavaScript"></script>
<script type="text/javascript">
<!--
//データ削除確認関数
function deldata(id,pid)
{
if(confirm('pid'+pid+'番を削除するならOKを押してください'))
{
location.href='delete.php?id='+id+'&pid='+pid
}
}
//全データ削除確認関数
function delall(id)
{
if(confirm('データを全部削除しまっせ。\n良ければOKを押してください'))
{
location.href='deleteall.php?id='+id
}
}
//オプション追加関数
function addOp(oj,text,value)
{
oj.options[oj.length]=new Option(text,value)
}
//オプション全削除関数
function delOp(oj){
var optionIndex = oj.options.length
for ( i=0 ; i <= optionIndex ; i++ ){
oj.options[0]=null
}
}
//送信確認関数
function submitchk(oj)
{
if( confirm('入力OKですか? OKなら送信します。') )
{
oj.form.submit(); //送信
} else {
}
}
//-->
</script>
<body>
<form name="test" method="post"
action="update.php?id=1">
予定日:
<input type="text" name="sdate"
tabindex="0"
onfocus="wrtCalendarLay(this,event)">
<br>大分類:
<input type="radio" name="memo1"
value="その他" onclick="delOp(this.form.memo2);
addOp(this.form.memo2,'etc...','etc...');
" checked>その他
<input type="radio" name="memo1"
value="JavaScript" onclick="delOp(this.form.memo2);
addOp(this.form.memo2,'window','window');
addOp(this.form.memo2,'document','document');
addOp(this.form.memo2,'form','form');
addOp(this.form.memo2,'date','form');
">JavaScript
<input type="radio" name="memo1"
value="DHTML" onclick=" delOp(this.form.memo2);
addOp(this.form.memo2,'cross','cross');
addOp(this.form.memo2,'layer','layer');
addOp(this.form.memo2,'all','all');
addOp(this.form.memo2,'getElementById','getElementById');
">DHTML
<input type="radio" name="memo1"
value="PHP" onclick=" delOp(this.form.memo2);
addOp(this.form.memo2,'file','file');
addOp(this.form.memo2,'array','array');
addOp(this.form.memo2,'string','string');
addOp(this.form.memo2,'database','database');
">PHP
<input type="radio" name="memo1"
value="MySQL" onclick=" delOp(this.form.memo2);
addOp(this.form.memo2,'select','select');
addOp(this.form.memo2,'insert','insert');
addOp(this.form.memo2,'update','update');
addOp(this.form.memo2,'delete','delete');
">MySQL
<br>中分類:
<select name="memo2"
mltiple
size="4"
tabindex="2">
<option value="etc...">etc...</option>
</select>
<br>Memo:
<textarea name="memo3" rows="3" cols="20
tabindex="3"></textarea>
<br><br>
<input type="button" name="sbm" value="登録"
tabindex="4"
onclick="if( confirm('入力OKですか? OKなら送信します。') )
{
this.form.submit(); //送信
}">
* 登録はMax20件までです。<br>
* 20件を超えたら削除して試してね(^^;;<br><br>
<input type="button"
onclick="delall('')"
value="全部削除"><br>
</form>
</body>
↑このスクリプトサンプル ./sample/f3/f3.htm
【./sample/f3/f3.htmの動作ブラウザ】 ←動作ブラウザ表は記事に入れたい
win mac linux
n4 n6 n7 m1 e5 e6 o7 n4 n6 n7 m1 e5 s1 n4 n6 n7 m1 k3
○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ △
*k3はカレンダー以外が動作する
////////////////////////////////////////////////////////////////////
*上記サンプルの動作環境は各サンプルをご確認ください
====================================================================
凡例
Win
n3 -- NetscapeNavogator 3.x
n4 -- NetscapeNavogator 4.x
n6 -- NetscapeNavogator 6.x
n7 -- NetscapeNavogator 7.x
m1 -- Mozilla1.x
e4 -- Internet Explorer 4.x
e5 -- Internet Explorer 5.x
e6 -- Internet Explorer 6.x
o6 -- Opera 6.0
o7 -- Opera 7.0
Mac
n3 -- NetscapeNavogator 3.x
n4 -- NetscapeNavogator 4.x
n6 -- NetscapeNavogator 6.x
n7 -- NetscapeNavogator 7.x
m1 -- Mozilla1.x
e4.5 -- Internet Explorer 4.5
e5 -- Internet Explorer 5.0 または 5.1
s1 -- Safari
Linux
n3 -- NetscapeNavogator 3.x
n4 -- NetscapeNavogator 4.x
n6 -- NetscapeNavogator 6.x
n7 -- NetscapeNavogator 7.x
m1 -- Mozilla1.x
k3 -- Konqueror 3.x
--------------------------------------------------------------------
|