[ページ遷移しないWebシステム] JavaScriptによるWindow Framework

　Webアプリケーションを構築するにあたって、ユーザインタフェイスの作成は苦労する部分です。現在の一般的な開発手法においては、サーバサイドからHTMLデータを送信することによって、表示部分の書き換えを行っています。そのたびにページ遷移が起こり、ユーザの体験を著しく損なっているのが現状です。

　それを回避手段はJavaScriptによってクライアント側でページの書き換えを行うことです。しかしサーバサイド側のプログラム言語とクライアントのJavaScriptを連携させるのは、システムの複雑化を招き開発を困難にします。

　これらの問題点を解決する方法として以下の二点を提示します

１　サーバサイドはデータ管理のみに集中し、表示に関するデータを送らない
２　クライアントサイドは表示とユーザの入出力を能動的に管理し、必要に応じてサーバ側とデータのやりとりを行う

　今回は２の部分に着目して必要なものを用意します。それがJavaScriptによる「Window Framework」です。フレームワークと名乗るからには、サーバサイドも包括するべきなのでしょうが、そちらはまだ中途半端な状態です。きちんと作ったら紹介したいと思います。



<h1>Window Frameworkの紹介</h1>
　そもそもWebにおいてページ遷移が多発してしまうのは、リッチなようで足りていないHTMLの仕様にあります。Ajaxにより非同期のデータ入出力はサポートされています。しかし標準的なコンポーネントは、非同期入力をユーザ体験を損なわない形で実現するようには出来ていません。たとえばBBSに書き込もうと思ったら、どこかに張り付いている入力ボックスを探しに行かなければなりません。

　ネイティブアプリならウインドウをポンと出すところです。しかしブラウザの標準機能でウインドウを出そうと思ったら、ポップアップ扱いでブロックされるのがオチです。今となっては誰も使いません。だったらJavaScriptでウインドウシステムを作れば良いのです。

　ということで、実装したものを紹介したいと思います。行き当たりばったりで実装しているので、ソース中に実験の痕跡が大量に残っているのはご容赦ください。ソースの利用に関しては自由ですが、何の保証も無いことはご理解ください。

サンプルページ https://mofon001.github.io/JGUI/
ソースコード   https://github.com/mofon001/JGUI
これを使って実装しているBlog https://croud.jp/

<h2>０．サンプルの基本HTMLファイル</h2>
```index.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8"/>
	<link rel="stylesheet" href="../../css/Gui.css"/>
	<script type="text/javascript" src="../../script/Gui.js"></script>
	<script type="text/javascript" src="Main.js"></script>
	<title>JavaScriptによるWindowフレームワーク</title>
</head>
<body>
</body>
</html>
```
　フレームワークを利用するに当たって、必要なのはGui.cssとGui.jsだけです。余計なものは一切使用していません。
　bodyタグの中には何も書きません。書いたら負けです。どうしてもというのなら書いても良いですが、ウインドウは上に乗ります。
　Main.jsを、以降で紹介するファイルに置き換えることによって、簡単にウインドウ表示を可能とします。




<h2>１．フレームウインドウテスト</h2>
```Sample01.js
(function(){
SCRIPT_URL = "./";
document.addEventListener("DOMContentLoaded",onLoad);

function onLoad(){
	var win = GUI.createFrameWindow();				//フレームウインドウの作成
	win.setTitle("ウインドウフレームワークテスト");		//タイトル設定
	win.setPos();									//中央へ移動
	//HTMLを直接設定
	win.getClient().innerHTML = "<H1>テスト</H1>HTMLの設定テスト";
}

})();
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/f1ef5bf6-62e4-7ff8-165a-cc2cae051453.png)

　ブラウザ上にウインドウを出現させます。
　最大化や最小化、フレームをドラッグしてのサイズ変更は標準対応です。

<h2>複合ウインドウテスト</h2>
```Sample02.js
(function(){
SCRIPT_URL = "./";
document.addEventListener("DOMContentLoaded",onLoad);

function onLoad(){
	for(var j=0;j<10;j++){
		var parent = GUI.createFrameWindow();	//フレームウインドウの作成
		parent.setTitle("Window"+j);			//タイトル設定	
		parent.setPos(j*30,j*30);				//位置設定
		for(var i=0;i<3;i++){
			var win = GUI.createFrameWindow();
			win.setTitle("Window"+j+":"+i);
			win.setSize(200,150);
			parent.addChild(win);				//親ウインドウの設定
			win.setPos(i*40,i*40);
		}
	}
}

})();
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/8ffd5ea3-a2b1-557a-ce48-64c725c86a64.png)

　複数のウインドウを表示するサンプルです。
　もちろんウインドウの中にウインドウを作ることも可能です。

<h2>２．セパレータ</h2>
```Sample03.js
(function(){
SCRIPT_URL = "./";
document.addEventListener("DOMContentLoaded",onLoad);

function onLoad(){
	var win = GUI.createFrameWindow();				//フレームウインドウの作成
	win.setTitle("ウインドウフレームワークテスト");		//タイトル設定
	win.setPos();									//中央へ移動
	
	var sep = GUI.createSeparate();					//セパレータの作成	
	win.addChild(sep,"client");						//親ウインドウの指定

	sep.getChild(0).getClient().innerHTML = "領域1";
	sep.getChild(1).getClient().innerHTML = "領域2";
}

})();
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/91d4281b-c3a2-db1b-3645-676aa6c43cf4.png)

　昔懐かしのframesetのような感覚で利用できます。
　上下分割も可能です。

<h2>３．リストビュー</h2>
```Sample04.js
(function(){
SCRIPT_URL = "./";
document.addEventListener("DOMContentLoaded",onLoad);

function onLoad(){
	var win = GUI.createFrameWindow();				//フレームウインドウの作成
	win.setTitle("ウインドウフレームワークテスト");		//タイトル設定
	win.setPos();									//中央へ移動
	
	var list = GUI.createListView();					//リストビューの作成	
	win.addChild(list,"client");						//親ウインドウの指定
	
	//ヘッダの設定
	list.addHeader("ID",50);
	list.addHeader("武器",300);
	list.addHeader("攻撃力",100);
	list.addHeader("価格",100);

	//アイテムの設定
	var values = [[1,"ひのきの棒",5,10],[2,"たけやり",8,15],[3,"こんぼう",40,20]];
	values.forEach(function(value){
		var index = list.addItem(value[0]);
		list.setItem(index,1,value[1]);
		list.setItem(index,2,value[2]);
		list.setItem(index,3,value[3]);
	});

	//アイテムクリックイベント
	var mLastIndex = [];
	list.addEvent("itemClick",function(e){
		var index = e.itemIndex;
		var subIndex = e.itemSubIndex;
		//同じ箇所をクリックしたら編集モード
		if(subIndex > 0 && mLastIndex[0] == index && mLastIndex[1] == subIndex){
			var edit = list.editText(index,subIndex);
			edit.addEvent("enter",function(e){
				list.setItem(index,subIndex,e.value);	//編集データを確定
			});
		}
		//前回のクリック番号を保存
		mLastIndex[0] = index;
		mLastIndex[1] = subIndex;
	});
}

})();
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/1d1b6639-9a83-04f5-c79e-72d345306635.png)

　WindowsのListViewコントロールのような動きをします。
　もちろんヘッダサイズは可変です。
　実は作ってみると、スクロールがらみでとても面倒くさいです。
　同じ場所を二回クリックすると、内容の編集が可能です。

<h2>４．ツリービュー</h2>
```Sample05.js
(function(){
SCRIPT_URL = "./";
document.addEventListener("DOMContentLoaded",onLoad);

function onLoad(){
	var win = GUI.createFrameWindow();				//フレームウインドウの作成
	win.setTitle("ウインドウフレームワークテスト");		//タイトル設定
	win.setPos();									//中央へ移動
	
	var tree = GUI.createTreeView();				//ツリービューの作成
	win.addChild(tree,"client");					//親ウインドウへ追加

	//アイテムを追加
	for(var j=0;j<5;j++){
		var item = tree.addItem("アイテム"+j);
		for(i=0;i<5;i++)
			item.addItem("サブアイテム"+j+"-"+i,false);
	}

	//選択時のイベント処理
	tree.addEvent("select",function(e){
		//選択項目の取得
		var name = tree.getSelectItem().getItemText();
		//メッセージボックスの表示
		GUI.createMessageBox("選択",name+"が選択されました",["OK"]);
	});

}

})();
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/4f4f9cc2-eb9a-fa0f-74b7-ccae1d9e8a13.png)

　簡単に実装できる割には、使い勝手は良いです。

<h1>終わりに</h1>
　ページ遷移を駆逐するフレームワークを目指して、サーバサイドを含めた上で、オープンソースで開発していきたいと思っています。既存のものが使いにくいなら自分で作れの精神です。

　実は10年以上も前に、似たようなライブラリを開発していました。それを自分の個人サイトと職場の内部システムに使っていました。特に公開しなかったのは、どうせもっと良い物が出るだろうと思っていたからです。しかし座すこと10年、世の中のWebシステムが一向に改善されていません。

　ページ遷移を誹毀する風潮が時流として広まれば、もっと優秀な人間が、もっと素晴らしいものを作ってくれるはずです。その時はRなフレームワークやCなフレームワークが、過去の遺物として忘れられることでしょう。そんな日が来ることを願って、今後も頑張っていきます。