WSH JScriptで入力ダイアログにIEを使う方法

このエントリーでは、WSH(Windows based Script Host)環境のJScriptで入力ダイアログを実現するのにIEを利用する方法を紹介します

# 入力ダイアログの実現方法

入力ダイアログを表示する方法には、JavaScriptの**prompt**関数や**VBScript**の**InputBox**関数を利用する方法とここで紹介するIEを利用する方法があります。その他に実現方法があれば、ぜひご教授ください

## 一般的なJavaScriptの実現方法

**prompt**関数を利用します。以下のようなコードで実現できます。これは当然ながらHTMLファイルの内の**Script**タグ内に実装します。拡張子は**html**となります

```HTML:InputDialog.html
<script language="JavaScript">
  var input = prompt( "Please Input your age ...." );
  alert( input );
</script>
```

## WSH JScriptでの実現方法
### VBScriptの助けを借りる方法
一般的には、というか、もっともネット上で紹介されているのが**VBScript**の**InputBox**関数を利用するというものです。この方法ではソースコード内に**JavaScript**と**VBScript**のScriptタグを実装し、拡張子を**wsf**とする必要があります。以下のようなコードで実現します

```HTML:InputDialog.wsf
<script language="JavaScript">
 var yourName = vbInputBox("What's your name?");
 WScript.Echo( yourName );
</script>
<script language="VBScript">
 function vbInputBox( prpmpt )
    vbInputBox = InputBox( prpmpt )
 end function
</script>
```

## IEを利用する方法

ここで私が紹介するのが、VBScriptの助けを借りない方法です。IEを起動し、HTMLコードを流し込んで入力ダイアログを実現する方法です。拡張子を**js**とすることで実現することができます

### メリット

JavaScriptやVBScriptで用意されている定型の入力ダイアログでなく、HTMLを実装することにより自由にニーズにあった入力ダイアログを実現することができます。以下に実現方法を具体的に説明いたします

### 入力ダイアログ表示クラス
まず入力ダイアログ表示クラス**DialogClass**を実装します。ここではIEに流し込むHTMLを実装します

```JavaScript:showInputDaialog.js＜入力ダイアログ表示クラスDialogClass＞
function DialogClass(){
  this.IE = null;
  this.createHtml = function( yyyyMM ){
    var html = ( function(){/*
      <html lang="ja">
        <head>
          <style>
            body{ background : #eee;  }
            div#button{ margin-top : 20px; }
            input#yyyyMM{ margin-top : 20px; background: #ffb; }
            input#OK{ margin-left : 10px; background: #efe; }
            input#OK:hover{ background: #bfb; }
            input#Cancel{ margin-left : 10px; background: #fee; }
            input#Cancel:hover{ background: #fbb; }
          </style>
        </head>
        <body>
          <div>年月を入力してください</div>
          <form name="form">
            <input id="yyyyMM" name="yyyyMM" type="text" value="%yyyyMM%" />
            <div id="button">
              <input type="hidden" name="OkCancel" value=-99 />
              <input id="OK" type="button" value="OK" 
                     onClick="document.form.OkCancel.value=1;" />
              <input id="Cancel" type="button" value="キャンセル"
                     onClick="document.form.OkCancel.value=0;" />
            </div>
          </form>
        </body>
      </html>
    */} ).toString().replace( "%yyyyMM%", yyyyMM )
         .split( "\n" ).slice( 1, -1 ).join( "\n" );
    return( html );
  };

  this.showInputDialog = function( yyyyMM ){
    if( this.IE == null ) this.IE = new IEClass();

    with( this.IE ){
      open();
      insertHtml( this.createHtml( yyyyMM ), "対象年月入力", 270, 170 );
    }
  };

  this.clickOKButton = function(){
    with( this.IE.objIE ){
      with( document ){
        while( getElementsByName( "OkCancel" ).item( 0 ).value < 0 ){
          WScript.Sleep( 500 );
        }
        var OkCancel = form.OkCancel.value;
        var inputString = getElementsByName( "yyyyMM" ).item( 0 ).value;
      }
      Quit();

      if( OkCancel == 1 ) return( inputString );
      else if( OkCancel == 0 )  WScript.Quit();
    }
  };
}
```

実現するためにはまず、入力フィールドとボタンを持った**入力ダイアログHTML**を実装し、このHTMLからの戻り値を一定間隔で入手します。具体的には以下の**1.**から**6.**の手順となります

#### 1.HTML内　入力フィールド

値を入力してもらうための**type**プロパティが**text**の**input**フィールドを実装します

```HTML:DialogClassクラスcreateHtml()メソッド内
<input id="yyyyMM" name="yyyyMM" type="text" value="%yyyyMM%" />
```

#### 2.HTML内　hiddenフィールド
**name**プロパティが**form**の**form**タグ内に、例えば、初期値が**-99**で、**name**プロパティが**OkCancel**のhiddenフィールドを実装します

```HTML:DialogClassクラスcreateHtml()メソッド内
<form name="form">
  <input type="hidden" name="OkCancel" value=-99 />
</form>
```
#### 3.HTML内　buttonのonClickプロパティ
**OK**ボタンと**キャンセル**ボタンがクリックされたときに実行される**onClick**プロパティをそれぞれ以下のように実装します

+ OKボタン
  + document.form.OkCancel.value=1;
+ キャンセルボタン
  + document.form.OkCancel.value=0;

これらはそれぞれ、hiddenフィールドの**value**プロパティを変更しています

```HTML:DialogClassクラスcreateHtml()メソッド内
<input id="OK" type="button" value="OK" 
  onClick="document.form.OkCancel.value=1;" />
<input id="Cancel" type="button" value="キャンセル"
  onClick="document.form.OkCancel.value=0;" />
```

#### 4. HTMLのIEへの流し込み

新しいIEを起動し、作成したHTMLを流し込みます

```JavaScript:DialogClassクラスshowInputDialog()メソッド内
if( this.IE == null ) this.IE = new IEClass();

with( this.IE ){
  open();
  insertHtml( this.createHtml( yyyyMM ), "対象年月入力", 270, 170 );
}
```

#### 5. 入力値の取得

**name**プロパティが**OkCancel**のhiddenフィールドを一定間隔500msecごとに得て、**OK**ボタンまたは**キャンセル**ボタンが押された場合には、hiddenフィールドの値**form.OkCancel.value**と、入力フィールドの値**getElementsByName( "yyyyMM" ).item( 0 ).value**を得ます。

```JavaScript:DialogClassクラスclickOKButton()メソッド内
while( getElementsByName( "OkCancel" ).item( 0 ).value < 0 ){
   WScript.Sleep( 500 );
}
var OkCancel = form.OkCancel.value;
var inputString = getElementsByName( "yyyyMM" ).item( 0 ).value;
```

#### 6.入力値の戻し

hiddenフィールドの**value**プロパティで**OK**ボタンが入力されたら、入力フィールドに入力された値を戻します

```JavaScript:DialogClassクラスclickOKButton()メソッド内
if( OkCancel == 1 ) return( inputString );
```

### IE操作クラス

次にIE操作クラス**IEClass**を実装します

IE操作クラス**IEClass**を入力ダイアログ表示クラス**DialogClass**でインスタンス化して利用します。このIE操作クラスは、ごく一般的なWSH JScriptやVBAからIEを操作する方法です。ネット上に豊富に実現方法が紹介されていますので、ここでは細かな説明は割愛いたします

```JavaScript:showInputDaialog.js＜IE操作クラスIEClass＞
function IEClass(){
  this.objIE = null;
  this.STATUS = { READYSTATE_COMPLETE: 4 }

  this.open = function(){
    if( this.objIE == null ){
      this.objIE = WScript.CreateObject("InternetExplorer.Application");
    }
    this.objIE.Visible = true;
    this.objIE.navigate("about:blank");
    this.wait();
  };

  this.insertHtml = function( html, titleStr, widthSize, heightSize ){
    with( this.objIE ){
      with( document ){
        all( 0 ).innerHTML = html;
        title = titleStr;
      }
      top = 0;  left = 0;
      width = widthSize;  height = heightSize;
      statusBar = false;  addressBar = false;
    }
    this.wait();
  };

  this.wait = function(){
    with( this.objIE ){
      while( busy || readystate != this.STATUS.READYSTATE_COMPLETE ){
        WScript.Sleep( 400 );
      }
    }
  };
}
```

#### 入力ダイアログHTMLの流し込み

**all( 0 ).innerHTML**プロパティに入力ダイアログ表示クラス**DialogClass**で作成した入力ダイアログ用のHTMLを代入して、IEに流し込みます

```JavaScript:IEClassクラスinsertHtml()メソッド内
with( document ){
  all( 0 ).innerHTML = html;
  title = titleStr;
}
```

### 利用方法

たとえば、処理クラス**ProcessClass**内に入力ダイアログ表示クラス**DialogClass**を仕込んで利用する場合には、以下のように実装します

```JavaScript:showInputDaialog.js＜利用方法＞
var process = new ProcessClass();
process.inputYearMonth();
```
```JavaScript:showInputDaialog.js＜処理クラスProcessClass＞
function ProcessClass(){
  this.inputYearMonth = function(){
    var dialog = new DialogClass();
    dialog.showInputDialog( "201808" );
    WScript.Echo( "「" + dialog.clickOKButton() + "」が入力されました");
  };
}
```

### 入力ダイアログ
こんな風に表示されます。カスタマイズはHTMLですので自由にできます
![InputDailog.PNG](https://qiita-image-store.s3.amazonaws.com/0/124810/f968bea3-9b74-2ac3-12f2-dc7c58f721df.png)
### 入力ダイアログで入力された値の表示
こんな風に確かに入力された値を受け取っているのがわかります
![AafteInputDialg.PNG](https://qiita-image-store.s3.amazonaws.com/0/124810/987655cb-d017-a288-633a-039da50bd58c.png)

### 全ソースコード

念のため、全ソースコードを示します。**showInputDaialog.js**アイコンをWindowsのデスクトップなどに置いておくと、対話型のWindowsアプリケーションとして利用できます

```JavaScript:showInputDaialog.js

var process = new ProcessClass();
process.inputYearMonth();

function ProcessClass(){
  this.inputYearMonth = function(){
    var dialog = new DialogClass();
    dialog.showInputDialog( "201808" );
    WScript.Echo( "「" + dialog.clickOKButton() + "」が入力されました");
  };
}

function DialogClass(){
  this.IE = null;
  this.createHtml = function( yyyyMM ){
    var html = ( function(){/*
      <html lang="ja">
        <head>
          <style>
            body{ background : #eee;  }
            div#button{ margin-top : 20px; }
            input#yyyyMM{ margin-top : 20px; background: #ffb; }
            input#OK{ margin-left : 10px; background: #efe; }
            input#OK:hover{ background: #bfb; }
            input#Cancel{ margin-left : 10px; background: #fee; }
            input#Cancel:hover{ background: #fbb; }
          </style>
        </head>
        <body>
          <div>年月を入力してください</div>
          <form name="form">
            <input id="yyyyMM" name="yyyyMM" type="text" value="%yyyyMM%" />
            <div id="button">
              <input type="hidden" name="OkCancel" value=-99 />
              <input id="OK" type="button" value="OK" 
                     onClick="document.form.OkCancel.value=1;" />
              <input id="Cancel" type="button" value="キャンセル""
                     onClick="document.form.OkCancel.value=0;" />
            </div>
          </form>
        </body>
      </html>
    */} ).toString().replace( "%yyyyMM%", yyyyMM )
         .split( "\n" ).slice( 1, -1 ).join( "\n" );
    return( html );
  };

  this.showInputDialog = function( yyyyMM ){
    if( this.IE == null ) this.IE = new IEClass();

    with( this.IE ){
      open();
      insertHtml( this.createHtml( yyyyMM ), "対象年月入力", 270, 170 );
    }
  };

  this.clickOKButton = function(){
    with( this.IE.objIE ){
      with( document ){
        while( getElementsByName( "OkCancel" ).item( 0 ).value < 0 ){
          WScript.Sleep( 500 );
        }
        var OkCancel = form.OkCancel.value;
        var inputString = getElementsByName( "yyyyMM" ).item( 0 ).value;
      }
      Quit();

      if( OkCancel == 1 ) return( inputString );
      else if( OkCancel == 0 )  WScript.Quit();
    }
  };
}

function IEClass(){
  this.objIE = null;
  this.STATUS = { READYSTATE_COMPLETE: 4 }

  this.open = function(){
    if( this.objIE == null ){
      this.objIE = WScript.CreateObject("InternetExplorer.Application");
    }
    this.objIE.Visible = true;
    this.objIE.navigate("about:blank");
    this.wait();
  };

  this.insertHtml = function( html, titleStr, widthSize, heightSize ){
    // WScript.Echo(html);
    with( this.objIE ){
      with( document ){
        all( 0 ).innerHTML = html;
        title = titleStr;
      }
      top = 0;  left = 0;
      width = widthSize;  height = heightSize;
      statusBar = false;  addressBar = false;
    }
    this.wait();
  };

  this.wait = function(){
    with( this.objIE ){
      while( busy || readystate != this.STATUS.READYSTATE_COMPLETE ){
        WScript.Sleep( 400 );
      }
    }
  };
}
```