SQLの窓

2018年07月31日


HTA (または IE11) で フォルダ選択ダイアログからフォルダとファイルの一覧


IE11 での実行には設定が必要です => HTA(HTMLアプリケーション) のコードを html として IE11 でデバッグする方法
※ newObject 関数は、hta.js で定義しています。 ▼ BrowseForFolder メソッド
var objFolder = objShell.BrowseForFolder( 0, "フォルダ選択", 1, 0 );
フォルダ参照 第1引数は、本来はウインドウハンドルを渡すものですが、こでは 0 を設定します。 第2引数は、タイトルの下に表示される文字列です。 第3引数は、BROWSEINFO structure の ulFlags の内容ですが実際はここに書いてある通りになはならないので試してみる他ありません。ここでは、1 を渡しており、意味は( Only return file system directories. If the user selects folders that are not part of the file system, the OK button is grayed ) です。=> ファイルシステム以外だと OK ボタンが 灰色になって使用できません 第4引数は、ShellSpecialFolderConstants のフォルダを渡して、そのフォルダを一番上のフォルダにします。=> ここでは、0 なのでデスクトップです。 一覧作成 フォルダオブジェクトを取得して、Items メソッドで下位のファイルとフォルダのコレクション( FolderItems オブジェクト )を取得します。 さらに、FolderItems オブジェクト の Item メソッドFolderItem オブジェクトを取得します。 IsFolder プロパティName プロパティを使用して一覧を作成します Name プロパティは、配列にセットして sort メソッドでソートしてから、区切りとルートフォルダのパスをセットしてテーブル要素に表示します Self プロパティは 仕様上は Folder2 オブジェクトとなります ▼ HTA(HTML アプリケーション) : pcname-from-stdout.hta ▼ IE11 : pcname-from-stdout.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8"><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script src="https://winofsql.jp/hta.js"></script>

<script>

	// ウインドウの位置とサイズ
	centerWindow( 1100, 600 );

	// Windows Shaell
	var objShell = newObject("Shell.Application");

	$(function(){
	
		// ***************************
		// ボタン表示位置微調整
		// ***************************
		$( ".btn" ).css({
			"margin-top": "-4px"
		});
	
		// ***************************
		// フォルダの選択後
		// フォルダ内の一覧
		// ***************************
		$("#act1").on("click", function(){

			// 1:0固定, 2:タイトル, 3:ファイルシステムのみ, 4:ルートがデスクトップ
			var objFolder = objShell.BrowseForFolder( 0, "フォルダ選択", 1, 0 );
			if ( objFolder == null ) {
				alert("フォルダの選択がキャンセルされました");
				return;
			}
			if ( !objFolder.Self.IsFileSystem ) {
				alert("ファイルシステムではありません");
				return;
			}
			
			var objFolderItems = objFolder.Items();
			
			var arrData = [];

			var nFiles = objFolderItems.Count;
			for( i = 0; i < nFiles; i++ ) {
				var objItem = objFolderItems.Item(i)
				if ( objItem.isFolder ) {
					arrData.push( " [" + objItem.Name +"]" );
				}
				else {
					arrData.push( objItem.Name );
				}
			}

			arrData.sort();
			arrData.unshift("-------------------------------------------------------------");
			arrData.unshift(objFolder.Self.Path);
			
			loadTable( arrData );

		});

	});

</script>

<style>
html,body {
	height: 100%;
}

body {
	margin: 0;
}

/* ブロックを左右に表示  */
.ttl {
	display: inline-block;
	width: 120px;
	vertical-align: top;
}
.entry {
	display: inline-block;
}
.line {
	margin-bottom: 0;
}

#head {
	padding: 16px;
}

/* IFRAMEコントロール用  */
#head {
	padding: 16px;
	width: 100%;
	height: 120px;
	background-color: #e0e0e0;
}
#extend {
	padding: 4px 16px;
	display: block;
	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );
	height: calc( 100% - 120px - 2px );
	border: solid 2px #c0c0c0;
	overflow: scroll;
}
.row_data td {
	cursor: default!important;
}

</style>

</head>
<body>
<div id="head">

	<p class="ttl">
		処理
	</p>
	<p class="entry">

		<input
			id="act1"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="フォルダ選択(Shell.Application)">

	</p>
	<p class="line"></p>

	<h4 class="text-danger"></h4>

</div>
<div id="extend">
	<table class="table table-hover">
		<tbody id="tbl">
		</tbody>
	</table>
<br>
</div>

</body>
</html>


hta.js




posted by lightbox at 2018-07-31 20:03 | HTA ( HTMLアプリケーション ) | このブログの読者になる | 更新情報をチェックする

2018年07月28日


HTA (または IE11) で hostname を実行して標準出力からPC名の取得


IE11 での実行には設定が必要です => HTA(HTMLアプリケーション) のコードを html として IE11 でデバッグする方法
コマンドプロンプトベースのアプリケーションを実行するので、一瞬コマンドプロンプトが現れます。その後、コマンドプロンプトに表示された内容を取得する方法です。 ※ StdOut は、TextStream オブジェクトのメソッドで処理に該当するものが使えます。 ※ WshScriptExec オブジェクト ▼ HTA(HTML アプリケーション) : pcname-from-stdout.hta ▼ IE11 : pcname-from-stdout.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script src="hta.js"></script>

<script>

	// ウインドウの位置とサイズ
	centerWindow( 1100, 600 );

	// WSH 標準
	var WshShell = newObject("WScript.Shell");

	$(function(){
	
		// ***************************
		// ボタン表示位置微調整
		// ***************************
		$( ".btn" ).css({
			"margin-top": "-4px"
		});
	
		// ***************************
		// hostname を実行して
		// 結果を取得する
		// ***************************
		$("#act1").on("click", function(){

			var oExec = WshShell.Exec("hostname");
			var str = "";
			str += oExec.StdOut.ReadAll();

			var arrData = [ str ];
			loadTable( arrData );

		});


	});

</script>

<style>
html,body {
	height: 100%;
}

body {
	margin: 0;
}

/* ブロックを左右に表示  */
.ttl {
	display: inline-block;
	width: 120px;
	vertical-align: top;
}
.entry {
	display: inline-block;
}
.line {
	margin-bottom: 0;
}

#head {
	padding: 16px;
}

/* IFRAMEコントロール用  */
#head {
	padding: 16px;
	width: 100%;
	height: 120px;
	background-color: #e0e0e0;
}
#extend {
	padding: 4px 16px;
	display: block;
	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );
	height: calc( 100% - 120px - 2px );
	border: solid 2px #c0c0c0;
	overflow: scroll;
}
.row_data td {
	cursor: default!important;
}

</style>

</head>
<body>
<div id="head">

	<p class="ttl">
		処理
	</p>
	<p class="entry">

		<input
			id="act1"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="hostname を実行して標準出力からPC名の取得">

	</p>
	<p class="line"></p>

	<h4 class="text-danger"></h4>

</div>
<div id="extend">
	<table class="table table-hover">
		<tbody id="tbl">
		</tbody>
	</table>
<br>
</div>

</body>
</html>


hta.js
// *************************************
// ウインドウの位置とサイズ
// *************************************
function baseWindow( x, y, w, h ) {

	top.moveTo( x, y );
	top.resizeTo( w, h );

}

// *************************************
// デスクトップ中央
// *************************************
function centerWindow( w, h ) {

	// ウインドウの位置とサイズ
	top.resizeTo( w, h );
	top.moveTo((screen.width-w)/2, (screen.height-h)/2 )

}

// *************************************
// CreateObject
// *************************************
function newObject( className ) {

	var obj;

	try {
		obj = new ActiveXObject( className );
	}
	catch (e) {
		obj = null;
	}

	return obj;

}

// *************************************
// テーブル作成
// *************************************
function loadTable( arrayData ) {

	var row_data = "";

	// テーブル表示リセット
	$("#tbl .row_data").remove();
	
	var len = arrayData.length;
	for( i = 0; i < len; i++ ) {
		row_data = $("<tr></tr>")
			.addClass("row_data")
			.appendTo( "#tbl" );

		$("<td></td>")
			.text(arrayData[i])
			.appendTo( row_data );
	
	}

}





posted by lightbox at 2018-07-28 22:28 | HTA ( HTMLアプリケーション ) | このブログの読者になる | 更新情報をチェックする

2018年07月24日


HTA : 『x-frame-options: SAMEORIGIN』の設定されていないページの情報を IFRAME 内に表示して jQuery で取り出す / iframe内 参照と .clone() と .end()

レスポンスヘッダーに x-frame-options: SAMEORIGIN が設定されているとそのページは同一ドメインでないと IFRAME に読み込んで表示する事ができません。

さらに、x-frame-options: SAMEORIGIN が設定されていなくても、通常のブラウザであれば表示する事はできても、JavaScript でアクセスする事ができません。

IFRAME 内に x-frame-options: SAMEORIGIN の設定されていない WEB ページを表示してかつ、JavaScript で値を取り出せるのは HTA だけです。





<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script>
// *************************************
// デスクトップ中央
// *************************************
function centerWindow( w, h ) {

	// ウインドウの位置とサイズ
	top.resizeTo( w, h );
	top.moveTo((screen.width-w)/2, (screen.height-h)/2 )

}
</script>

<script>

	// ウインドウの位置とサイズ
	centerWindow( 860, 600 );

	// テーブルの行作成用
	var row_data = "";

	$(function(){

		// レジストリキーの値一覧
		$("#act").on("click", function(){
		
			var domdoc = $("iframe[name='extend']").get(0).contentWindow.document;

			$(domdoc).find("#datalist p").each( function(idx){
			
				row_data = $("<tr></tr>")
					.addClass("row_data")
					.appendTo( "#tbl" );

				// 複製を取得して複製内の span を削除して
				// .end() で参照を p_clone に戻す
				var p_clone = $(this).clone().find("span").remove().end();
				// 複製内の span を削除 
				
				// p 内にある span のテキスト
				$("<td></td>")
					.text($(this).find("span").text())
					.appendTo( row_data );

				// span が削除された p 内のテキスト
				$("<td></td>")
					.text(p_clone.text())
					.appendTo( row_data );

			});

		});

		// 再表示
		$("#view").on("click", function(){
			location.reload(true);
		});

		// IE のドキュメントモードを表示
		$("<div></div>")
			.text( document.documentMode )
			.css( { "float" : "right", "color": "#808080", "font-size": "8px" } )
			.insertBefore( $("p").eq(0) );
			

		// ボタン表示位置微調整
		$( ".btn" ).css({
			"margin-top": "-4px"
		});
			
		
	});

</script>

<style>
/* ブロックを左右に表示  */
.ttl {
	display: inline-block;
	width: 230px;
	vertical-align: top;
}
.entry {
	display: inline-block;
}
.line {
	margin-bottom: 0;
}

#head {
	padding: 16px;
}

/* DIV を Window 下部にフィット  */
html,body {
	height: 100%;
}

body {
	margin: 0;
}
#head {
	padding: 16px;
	width: 100%;
	height: 120px;
	background-color: #e0e0e0;
}
.extend {
	padding: 4px 16px;
	display: block;
	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );
	height: calc( 100% - 120px - 2px );
	border: solid 2px #c0c0c0;
	overflow: scroll;
}

/* テーブルのカーソル用  */
.row_data td, .row_data th {
	cursor: default!important;
	white-space: pre;
}

</style>
</head>
<body>
<div id="head">

	<p class="ttl">
		外部IFRAMEの内容を取り出す
	</p>

	<p class="entry">
		<input
			id="act"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="一覧表示">

		<input
			class="ml-4 btn btn-info btn-sm"
			id="view"
			type="button"
			value="再表示">
	</p>
	<p class="line"></p>

	<h4 class="text-danger"></h4>

</div>
<div class="extend">
	<table class="table table-hover">
		<tbody id="tbl">
		</tbody>
	</table>
<br>
</div>

<iframe class="extend" name="extend" APPLICATION="yes" src="https://lightbox.sakura.ne.jp/demo/iframe_target.html"></iframe>

</body>
</html>


jQuery でテキストノードの文字列を取り出す

以下のような HTML では、テキスト がテキストノードにあたります。テキスト2 はテキストノードでは無いので、a に対するセレクタで取得できますが、テキストと同様の方法で取り出します。

参考 : [Javascript] jQueryでテキストノードを選択するにはどうすればよいですか?
<div id="datalist">
	<p><span>18/07/23</span>テキスト</p>
	<p><span>18/07/22</span>テキスト</p>
	<p><span>18/07/18</span>テキスト</p>
	<p><span>18/07/16</span><a href="URL">テキスト2</a></p>
	<p><span>18/07/15</span><a href="URL">テキスト2</a></p>
	<p><span>18/07/15</span><a href="URL">テキスト2</a></p>
</div></body>


IFRAME 内のドキュメント参照と .clone() と .end()

1) var domdoc = $("iframe[name='extend']").get(0).contentWindow.document で、DOM として IFRAME 内の document を取得します

2) テキストノードを取得する為に span を削除する必要があるので、clone() で同じものを作成してその中から span を削除します

3) 削除した段階で、参照が span に移行しているので、end() で一つ前に戻って、そこから text() でデータを取得します
var domdoc = $("iframe[name='extend']").get(0).contentWindow.document;

$(domdoc).find("#datalist p").each( function(idx){

	row_data = $("<tr></tr>")
		.addClass("row_data")
		.appendTo( "#tbl" );

	// 複製を取得して複製内の span を削除して
	// .end() で参照を p_clone に戻す
	var p_clone = $(this).clone().find("span").remove().end();
	// 複製内の span を削除 
	
	// p 内にある span のテキスト
	$("<td></td>")
		.text($(this).find("span").text())
		.appendTo( row_data );

	// span が削除された p 内のテキスト
	$("<td></td>")
		.text(p_clone.text())
		.appendTo( row_data );

});


WEB ページのデータを HTA で自動的に取得したい場合、x-frame-options: SAMEORIGIN がなければそのまま使えます。しかし、一般的には欲しいページをダウンロードしてローカルに置いて読み込めば全てのページのデータをある程度自動取得できます。




posted by lightbox at 2018-07-24 23:57 | HTA ( HTMLアプリケーション ) | このブログの読者になる | 更新情報をチェックする

無料SSL(Let's Encrypt) : [さくらインターネット]SSLサーバ証明書発行のお知らせ

https://winofsql.jp/info.php


さくらインターネットやその他のレンタルサーバで、無料SSL が使用可能である事を知り、インストールしました。インストール後、[さくらインターネット]SSLサーバ証明書発行のお知らせ というメールが来ましたが、手順はほぼボタンをクリックするだけです。

【無料SSL】サーバコントロールパネルからの導入手順

最初に、さくらインターネットで取得・管理しているドメインを利用する他社で取得・管理しているドメインを利用するを確認します。

自分は、さくらインターネットで取得・管理しているドメインを利用しています。

▼ 確認事項

さくらインターネットにて2004年7月15日以降に取得・移管された独自ドメインに限る。
( 会員メニューの契約情報の下のほうにある サービス利用期間 で確認できます )

さくらインターネットのネームサーバを利用する事
プライマリネームサーバ:ns1.dns.ne.jp
セカンダリネームサーバ:ns2.dns.ne.jp
対象となるドメインのAレコードの値がさくらのレンタルサーバに向いている必要がある。

以上の情報は、会員メニュー > ドメインメニュー > ゾーン編集 で確認できます。
( エントリ名 が @ の部分で確認ができます / ドメインで ping を実行して取得できた IP が A レコードに対応 )

おそらく、たいていの場合は問題無く、そのまま SSL の設定手順に基づいてクリックしていくだけです。

設定・お申し込み手順

1) SSL設定を有効にする

2) 確認

2) の確認は要するにまず、http:// ではなく https:// で表示されるかどうかです。

▼ ページの編集

問題は、そのページから読み込んでいる、.css .js 及び 画像が https:// でアクセスされていないと、Google Chrome の場合 URL の左に『保護された通信』と表示されません。

css 内に記述されている URL や、js 内より動的に作成されるものも全て変更する必要があります。特に、画像類も全て対象になるので細かくチェックします( ファイル名や画像名は、F12 のデベロッパーツールのコンソールで確認できます )

▼ 変更が不十分だとこうなります


▼ 証明書の更新について

メールの中に以下のように書かれています
今回お申し込みいただいた無料SSLについては証明書は有効期間が90日となりますが、サーバで自動更新いたしますので今後更新作業を行う必要はございません。ご利用を停止したい場合は「秘密鍵を含む設定の削除」から証明書を削除してください。
※ レンタルサーバ側で自動更新してくれるので、特別な配慮は不必要のようです。 http から https へのリダイレクトについて 暗号化(SSL)を有効としている場合、暗号化しているページへ誘導したい に以下のような .htaccess 用の記述が書かれています。
SetEnvIf REDIRECT_HTTPS (.*) HTTPS=$1 
<IfModule mod_rewrite.c>
RewriteEngine on 
RewriteCond %{ENV:HTTPS} !on 
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 
</IfModule>
ですが、自分はすでに .htaccess を配置していろいろやっているので、該当するフォルダ内の .htaccess の最後に以下を追加しました。
RewriteEngine on 
RewriteCond %{ENV:HTTPS} !on 
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 
※ もう少しきちんと記述方法を調べれば、もっと限定した処理も書けると思います ▼ 昔設置した、小文字から大文字のリダイレクト
RewriteEngine On
RewriteBase /
RewriteRule va003334/(.*) VA003334/$1 [R,L]
posted by lightbox at 2018-07-24 21:53 | WEBサービス | このブログの読者になる | 更新情報をチェックする

HTA (HTMLアプリケーション) で JavaScript と VBScript を混在させる手法 / GetObject を VBScript 側で使用する



▼ HTA


▼ IE11


ドキュメントモードは IE10 で
<meta http-equiv="x-ua-compatible" content="ie=10" />
JavaScript だけで処理できる場合は、ie="edge" で最新のドキュメントモードで動作します。しかし、VBScript を使う場合は ie="10" でないと動作してくれないので注意が必要です。(省略するとドキュメントモードは 5 のようです) IE11 でも、信頼するサイトに http://localhost を登録して、レベルのカスタマイズで『スクリプトを実行しても安全だとマークされていないActiveX コントロールの初期化とスクリプトの実行』を『有効』にすれば .hta を .html に変更して動作可能です。 SCRIPT 要素の language="VBScript"
<script language="VBScript">
</script>
主体が JavaScript の場合は、VBScript を記述する場所は language="VBScript" を記述する必要があります。但し、ページ上で最初に現れるスクリプトは JavaScript である必要があります。先に、VBScript が定義されていると VBScript がデフォルトの言語になってしまいます。( 一般要素にインラインのイベントで VBScript を書く場合も language="VBScript" が必要です ) WMI を使用する為に GetObject が必要です この為に VBScript が必要になる場合と、JavaScript では Windows で用意されたオブジェクトからの値をうまく取得できない場合もあるので、VBScript を要所に設置する必要があります。このサンプルでは、GetObject で WMI のレジストリ処理を可能にする為に使っているのと、メソッドに変数を渡して戻ってくる値を使えるようにする為に使用しています。 ▼ レジストリのエントリ名の一覧を JavaScript の配列に変換する為の流れ JavaScript から呼び出し => VBScript で処理 => VBArray を引数で JavaScript に引き渡す => JavaScript の配列にする VBArray の扱い Microsoft のドキュメントではピンと来ないのですが、結果的に オブジェクトとのやり取りする場合、配列はほぼ全て safeArray だと思われます。そして、JavaScript 内で受け取った時点で既に、VBArray のようなので、そのまま toArray() で配列化します。( VBScript が JavaScript の関数に引数として渡しても、JavaScript 側では VBArray のようです )
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=10" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<script src="hta.js"></script>

<script language="VBScript">
' *****************************************
' VBScript を使用するには、
' x-ua-compatible で、ie=10 です
' *****************************************

' オブジェクトの取得
Set objRegistry = GetObject("Winmgmts:root\default:StdRegProv")
' *****************************************
' VBScript の関数
' *****************************************
Function GetObjectArray(RegPath)

	Dim aNames,aTypes

	on error resume next
	WMIRet = objRegistry.EnumValues( &H80000002, RegPath, aNames, aTypes )
	if Err.Number <> 0 then
		alert( Err.Description )
		GetObjectArray = False
		Exit Function
	end if
	if WMIRet <> 0 then
		alert( "処理に失敗しました" )
		GetObjectArray = False
		Exit Function
	end if
	on error goto 0
	
	if IsNull( aNames ) then
		alert( "データがありません" )
		GetObjectArray = False
		Exit Function
	end if

	Call setObjRegistry( aNames )

	GetObjectArray = True

End Function
</script>
<script>

	// ウインドウの位置とサイズ
	centerWindow( 1100, 600 );

	// テーブルの行作成用
	var row_data = "";

	// Microsoft Windows 標準オブジェクト作成
	var WshShell = newObject("WScript.Shell");
	var objShell = newObject("Shell.Application");

	$(function(){

		// レジストリキーの値一覧
		$("#act").on("click", function(){

			if ( GetObjectArray( $("#regkey").val() ) == 0 ) {
				return;
			}
			
			// テーブル表示リセット
			$("#tbl .row_data").remove();
			
			// 配列より一覧作成
			var len = regArray.length;
			for( i = 0; i < len; i++ ) {
				row_data = $("<tr></tr>")
					.addClass("row_data")
					.appendTo( "#tbl" );

				$("<td></td>")
					.text(regArray[i])
					.appendTo( row_data );
			
			}

		});

		// 実行
		$("#run").on("click", function(){

			WshShell.Run("ms-settings:windowsupdate");

		});

		// 管理者実行
		$("#admin_run").on("click", function(){

			objShell.ShellExecute("cmd.exe", "", "", "runas", 1);

		});

		// 再表示
		$("#view").on("click", function(){
			location.reload(true);
		});

		// IE のドキュメントモードを表示
		$("<div></div>")
			.text( document.documentMode )
			.css( { "float" : "right", "color": "#808080", "font-size": "8px" } )
			.insertBefore( $("p").eq(0) );

		// 表示位置微調整
		$( ".btn,#regkey" ).css({
			"margin-top": "-4px"
		});
		
	});

</script>

<style>
/* ブロックを左右に表示  */
.ttl {
	display: inline-block;
	width: 300px;
	vertical-align: top;
}
.entry {
	display: inline-block;
}
.line {
	margin-bottom: 0;
}

#head {
	padding: 16px;
}

/* DIV を Window 下部にフィット  */
html,body {
	height: 100%;
}

body {
	margin: 0;
}
#head {
	padding: 16px;
	width: 100%;
	height: 180px;
	background-color: #e0e0e0;
}
#extend {
	padding: 4px 16px;
	display: block;
	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );
	height: calc( 100% - 180px - 2px );
	border: solid 2px #c0c0c0;
	overflow: scroll;
}

/* テーブルのカーソル用  */
.row_data td, .row_data th {
	cursor: default!important;
	white-space: pre;
}

</style>
</head>
<body>
<div id="head">

	<p class="ttl">
		HKEY_LOCAL_MACHINE レジストリキー
	</p>
	<p class="entry">
		<input
			id="regkey"
			type="text"
			style="width:600px;"
			value="SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers">
	</p>
	<p class="line"></p>

	<p class="ttl">
	</p>

	<p class="entry">
		<input
			id="act"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="一覧表示">

		<input
			id="run"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="実行">

		<input
			id="admin_run"
			class="ml-4 btn btn-outline-primary"
			type="button"
			value="管理者実行">

		<input
			class="ml-4 btn btn-info btn-sm"
			id="view"
			type="button"
			value="再表示">
	</p>
	<p class="line"></p>

	<h4 class="text-danger"></h4>

</div>
<div id="extend">
	<table class="table table-hover">
		<tbody id="tbl">
		</tbody>
	</table>
<br>
</div>

</body>
</html>

※ 画面上右端に、IE のドキュメントモードを表示するようにしました


// IE のドキュメントモードを表示
$("<div></div>")
	.text( document.documentMode )
	.css( { "float" : "right", "color": "#808080", "font-size": "8px" } )
	.insertBefore( $("p").eq(0) );


サンプルとして、外部アプリケーションの二つの実行方法を記述しています。( Shell.Application では管理者権限での実行が可能です )


hta.js

newObject 関数は、VBScript の CreateObject ライクに使えるようにしたので、取得に失敗すると戻り値は null が返ります。
// *************************************
// ウインドウの位置とサイズ
// *************************************
function baseWindow( x, y, w, h ) {

	top.moveTo( x, y );
	top.resizeTo( w, h );

}

// *************************************
// デスクトップ中央
// *************************************
function centerWindow( w, h ) {

	// ウインドウの位置とサイズ
	top.resizeTo( w, h );
	top.moveTo((screen.width-w)/2, (screen.height-h)/2 )

}

// *************************************
// CreateObject
// *************************************
function newObject( className ) {

	var obj;

	try {
		obj = new ActiveXObject( className );
	}
	catch (e) {
		obj = null;
	}

	return obj;

}

// *************************************
// VB より呼びだされる
// VBArray を JS 配列に変換する関数
// *************************************
function setObjRegistry( vbArray ) {

	window.regArray = vbArray.toArray()
	window.regArray.sort();

}

※ window.regArray は、JavaScript でグローバル変数(と同等?)の保存をする為の手法です。

※ 2列以上のデータセット個別の列でソートするには、ADODB.Recordset を使用します。


関連する記事

HTA + Basp21 + jQuery + twitter-bootstrap(4.1.1) でメール受信ツール




posted by lightbox at 2018-07-24 12:56 | HTA ( HTMLアプリケーション ) | このブログの読者になる | 更新情報をチェックする

2018年07月23日


Python + MySQL + IFRAME + Bootstrap : 問い合せ WEB アプリテンプレート





JavaScript は jQuery を使用します。

テンプレート構造

IFRAME 内の処理( req フォルダ内 )が実際の問い合わせ処理になります。メインページの下部に CSS の calc 関数を使用してフィットさせています。



メインの control.py( エントリポイント )

Python の import は PHP の require( または include ) や Ruby の require と違って モジュールを利用する為のメモリ空間の利用方法が厳格です。PHP の require は、単純にソースコードの外部読みこみで、Ruby の require は、仕様としてライブラリを読み込むようになっているのですが、現実としてソースコードレベルの読み込みと考えて問題は無いようです( グローバル変数がソース間で使用可能 )

Python ではソース間のグローバル変数は存在せず、モジュール内の変数を読みこむ側がいかに参照するかというアプローチになります。これに関してもエントリポイントの開始ソースとその他のソースの場合ではモジュール変数の扱いが微妙に違うので注意が必要です( from モジュール import * の動作 )

from settings import * の * で全ての内容をインポートする方法は、Python では推奨されていませんが、ここでは必ずすべて必要になるテンプレートとしての仕様に基づいて使用しています。
import cgitb
cgitb.enable()

# **************************************
# 共有メソッド
# **************************************
from settings import *
set( "base_name", __file__ )

# **************************************
# CGI 初期処理
# **************************************
cgi_init()

import view

settings.py ( 共通処理 )

Python ではソース単位で必要なモジュールは常に import する必要があります。ただ、最終的に実行単位のメモリ空間では同じモジュールは各ソースで共有されるようです。

単純なグローバル変数が使用できないので、settings モジュールに val デイクショナリを作成しておいて、get/set メソッドで値の操作を可能にしてグローバル変数代わりに使用しています。

settings で定義された変数は、settings 内で定義されている メソッド内で global キーワードを使用して参照可能になります( PHP と類似 )

log と pplog はデバッグ用のメソッドで、テキストフアイルに出力する為に使用します。
import cgi
import sys
import io
import pprint

# **************************************
# デバッグログの初期化
# **************************************
with open('debug.log', 'w') as f:
	print("開始",end='\n',file=f)

# **************************************
# グローバル変数
# **************************************
pp = None

# **************************************
# 共有ディクショナリ
# **************************************
val = {}
val["pass"] = "1"
val["check_message"] = ""
val["lines"] = ""

# **************************************
# フォーム用変数
# **************************************
fld_names = {}
form = {}
form_data = {}

# **************************************
# CGI 初期処理
# **************************************
def cgi_init():

	global pp
	global form

	sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
	 
	print("Content-Type: text/html; charset=utf-8")
	print( "Expires: Thu, 19 Nov 1981 08:52:00 GMT" )
	print( "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" )
	print( "Pragma: no-cache" )
	print()

	pp = pprint.PrettyPrinter(indent=4)

	form = cgi.FieldStorage()

# **************************************
# データの整形表示
# **************************************
def print_r(data):

	global pp

	print("<pre>")
	pp.pprint(data)
	print("</pre>")

# **************************************
# フォームデータの取得
# **************************************
def forms(target, set_data=None):

	global fld_names
	global form

	if set_data is not None:
		form_data[fld_names[target]] = set_data
		return

	result = ""

	if form_data.get(fld_names[target]) is not None:
		return( form_data[fld_names[target]] )

	if not fld_names[target] not in form:
		result = form[fld_names[target]].value

	return(result)

# **************************************
# フォームフィールド名取得
# **************************************
def fields(target):

	return(fld_names[target])

# **************************************
# フォームフィールドセット設定
# **************************************
def set_field_names( field_set ):

	global fld_names

	fld_names = field_set


# **************************************
# ディクショナリ : set & get
# **************************************
def set( my_key, my_val ):

	global val
	val[my_key] = my_val

def get( my_key ):

	global val
	return( val[my_key] )

# **************************************
# ログ出力
# **************************************
def log( message ):
	with open('debug.log', 'a') as f:
		print(message,end='\n',file=f)
	
# **************************************
# ログ出力( pprint )
# **************************************
def pplog( obj ):

	with open("debug.log", "a") as f:
		pprint.pprint(obj, stream=f)




view.py ( メイン画面定義 )

画面定義は、三重クオート文字列と f-string を使用して PHP のヒアドキュメント的に行っています( 変数のパースは {メソッドまたは変数} です )

JavaScript の外部ファイルの読み込み時のキャッシュ制御を行う為、ページが表示された時間を URL に付加しています。
import os
from settings import *
# **************************************
# js 選択
# **************************************
js = "entry.js";
#js = "entry-json.js";

# **************************************
# js キャッシュ用
# **************************************
from datetime import datetime
tm = datetime.now().strftime("%Y%m%d%H%M%S")

# **************************************
# 画面定義
# **************************************
out_client = f"""<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />

<script src="{js}?{tm}"></script>

<link rel="stylesheet" href="entry.css?{tm}">
</head>
<body>

<div id="head">
	<p class="ttl">
		氏名で検索
	</p>
	<p class="entry">
		<input
			id="cond"
			type="text">
		<input
			class="ml-4 btn btn-success"
			id="btn"
			type="button"
			value="問合せ">

		<a
			class="ml-4 btn btn-info btn-sm"
			href="{os.path.basename(get("base_name"))}">GET 再読み込み</a>	
	</p>
	<p class="line"></p>

	<h4 class="text-danger">{get("check_message")}</h4>

</div>

<iframe id="extend" name="extend" class="iframe-option" src="req/control.py"></iframe>

</body>
</html>"""


print(out_client)


entry.js

1) Bootstrap のボタンの表示位置の調整を行っています。
2) 問い合わせの条件を JavaScript 側で作成して IFRAME の src にセットしています。
$(function(){
	// ***************************
	// ボタン表示位置微調整
	// ***************************
	$( ".btn" ).css({
		"margin-top": "-4px"
	});

	// ***************************
	// IFRAME に問合せを表示
	// ***************************
	$( "#btn" ).click(function() {
		$("#extend").prop("src","req/control.py?nm=" + encodeURIComponent($("#cond").val()));
	});


});


entry.css

Python では、CSS 内に書く記述が一部文字列内でエラーになったので .css として利用しています。
/* ブロックを左右に表示  */
.ttl {
	display: inline-block;
	width: 150px;
}
.entry {
	display: inline-block;
}
.line {
	margin-bottom: 0;
}

/* IFRAMEコントロール用  */
html,body {
	height: 100%;
}

body {
	margin: 0;
}

/* IFRAMEコントロール用  */
#head {
	padding: 16px;
	width: 100%;
	height: 100px;
	background-color: #e0e0e0;
}
iframe {
	display: block;
	margin-left: auto;
	margin-right: auto;
	width: calc( 100% - 3px );
	height: calc( 100% - 100px - 2px );
	border: solid 2px #c0c0c0;
}

control.py ( 問い合わせのエントリポイント )

単独で動作する問い合わせアプリケーションです。GET メソッドで QueryString を受け取って内部の SQL 処理に引き渡します。セキュリティ上の文字列の処理は省略しています。

mysql.connector は、Oracle が提供している Connector/Python を使用します( インストールが必要です ) 
※ autocommit がデフォルトで False なので接続時に True に設定しています

set_field_names メソッドは、settings モジュールで定義されており、画面のフィールド名やフィールド値を参照する為の日本語の定義となります。

sys.path.append('..') は、親フォルダにあるモジュールをインポートするパスをシステムに追加しています。
# **************************************
# 親ディレクトリに参照パス追加
# **************************************
import sys
sys.path.append('..')

# **************************************
# CGI
# **************************************
import cgitb
cgitb.enable()
# **************************************
# MySQL
# **************************************
import mysql.connector

# **************************************
# アプリケーションメソッド
# **************************************
from model import *

# **************************************
# 共有メソッド
# **************************************
from settings import *
set( "base_name", __file__ )

# **************************************
# CGI 初期処理
# **************************************
cgi_init()

# **************************************
# フォームフィールドセット設定
# **************************************
set_field_names( {
	"条件" : "nm",
	"送信ボタン" : "send"
})

# **************************************
# 接続 / 更新兼用
# **************************************
cnn = mysql.connector.connect(
	host='localhost',
	port=3306,
	db='lightbox',
	user='root',
	passwd='',
	charset="utf8",
	autocommit='True')

build_table( cnn )

# **************************************
# 接続解除
# **************************************
cnn.close()

import view


view.py ( 問い合わせ用画面 )

table 部分の行データの埋め込み部分に tbody を明示しているのは、行を jQuery で動的に作成した時に tbody が無いと Bootstrap の css が動作しないからです( 他のテンプレートと差異を少なくする為 )。

一番最後に pplog で、ディクショナリの内容を出力していますが、control.py はエントリポイントなので 変数の参照ができないので、処理の最後として view.py の最後で参照しています( エントリポイントでは、エントリポイントのメモリ空間に最初に使った変数が割り付けられるようです / それ以外の場合は from モジュール import * で直接モジュール変数の参照が可能です )
# **************************************
# 親ディレクトリに参照パス追加
# **************************************
import sys
sys.path.append('..')

#import os
# **************************************
# 共有メソッド
# **************************************
from settings import *
# **************************************
# js 選択
# **************************************
js = "entry.js";
#js = "entry-json.js";

# **************************************
# js キャッシュ用
# **************************************
from datetime import datetime
tm = datetime.now().strftime("%Y%m%d%H%M%S")

# **************************************
# 画面定義
# **************************************
out_client = f"""<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.css" />

<script src="{js}?{tm}"></script>

<link rel="stylesheet" href="entry.css?{tm}">
</head>
<body>

	<table class="table table-hover">
		<tbody id="tbl">
			{get("lines")}
		</tbody>
	</table>

</body>
</html>"""


print(out_client)

pplog(fld_names)
pplog(val)

entry.css

テーブル表示時のカーソルを常にデフォルトに固定して、テーブルのデータが折り返さないように以下の CSS が追加定義されています
td,th {
	cursor: default!important;
	white-space: pre;
}

body {
	margin: 0;
	padding: 16px;
}


model.py ( テーブル作成部分 )

1) 列データの文字列をまずループで作成しています( SQLを変更するだけで違った問い合わせを表現できます )
2) 列データが完成する毎に、行データを作成して全体の文字列に追加していきます。
3) cnn.cursor(dictionary=True) で、結果をディクショナリ(PHP:連想配列/Ruby:ハッシュ)
import mysql.connector
from settings import *

# ***************************
# テーブル作成
# ***************************
def build_table( cnn ):

	cursor = cnn.cursor(dictionary=True)

	sql = f"""select
		社員コード,
		氏名,
		フリガナ,
		所属,
		性別,
		作成日,
		更新日,
		給与,
		手当,
		管理者,
		DATE_FORMAT(生年月日,'%Y/%m/%d') as 生年月日
		from 社員マスタ
		where 氏名 like '%{forms("条件")}%'"""

	# デバッグ
	log(sql)

	cursor.execute(sql)

	lines  = ""
	for row in cursor:

		if lines == "":
			# タイトル
			for col in row.keys():
				lines += f"<th>{col}</th>"

		cells  = ""
		for col in row.values():
			if col is None:
				cells += f"<td></td>"
			else:
				cells += f"<td>{col}</td>"
	
		lines += f"<tr>{cells}</tr>"
	
	cursor.close()

	set("lines",lines)




関連する記事

Ruby + MySQL + IFRAME + Bootstrap : 問い合せ WEB アプリテンプレート

PHP + MySQL + IFRAME + Bootstrap : 問い合せ WEB アプリテンプレート

CSS の calc 関数を使って、IFRAME を画面下半分にフィットさせる





posted by lightbox at 2018-07-23 10:32 | Python | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり