Windows サイドバー ガジェット 作成者の為の Tips

Windows サイドバー ガジェット を作成する際に役立ちそうな小技(Tips)についてです。

スクリプトのエンコード

Windows サイドバー ガジェットの作成には、ガジェットにさまざまな機能を盛り込む為にスクリプト言語の使用が欠かせません。ところが、スクリプトの記述内容は単なるテキストとして保存される以上、その内容は作成者の本意の反して、第三者にソースコードを流用されてしまう可能性があります。つまり、スクリプトに含まれている知的所有権を保護する手立てがないのがスクリプトを使用する場合の欠点です。

Windows サイドバー ガジェットに限らず Windows 上での実行を前提とした ASPWSH [WSH] 等のようにスクリプト(Microsoft JScrip [JScript], Microsoft VBScript [VBScript] )の内容を含むファイルでは、Microsoft スクリプト エンコーダ [ScriptEncoder] を使用できます。スクリプト エンコーダ [ScriptEncoder] は、シンプルなコマンドラインツールです。このツールを使用すると、作成したスクリプトをエンコードし、スクリプトのソースコードが第三者の目に触れるのを防ぐことができます

注釈

  • スクリプト エンコーダ [ScriptEncoder] によるエンコードは、コードの安易な表示を防ぐことが目的であり、コードを解析不能にするものではありません。
  • エンコードされたスクリプトは、エンコード前の状態へは戻すことができません。入力ファイルを出力ファイルで上書きしてしまわない様にご注意下さい。
  • HTML ファイルに添付するスクリプトにエンコードを実行すると、script 要素の language 属性(推奨しない)、又は type 属性で指定する言語指定子が変更されることに注意してください。JScript の場合 JScript から JScript.Encode、VBScript の場合 VBScript から VBScript.Encode になります。
  • ファイル拡張子が .js.vbs のスクリプトファイルをエンコードすると、それぞれ拡張子が .jse および .vbe に変わります。

メッセージボックス

JavaScript [JavaScript] 及び Microsoft JScript [JScript] には、ユーザからの入力を受け取るためのメッセージボックス(警告の alert メソッド、確認の confirm メソッド、入力の prompt メソッド、何れもインターフェイスとなる window オブジェクトのメソッド)があります。然しならが、Windows サイドバー ガジェットの UI となる HTML ファイルに添付するスクリプトでは、理由は分かりませんが alert メソッドと confirm メソッドは使用できません。

Windows サイドバー ガジェットでメッセージボックスを使用する場合には、Microsoft VBScript [VBScript] の MsgBox 関数や Windows Script Host [WSH] の WshShell オブジェクトの Popup メソッドを使用します。この他にも、MSIE 独自拡張の HTML ダイアログ(window オブジェクトの showModalDialog メソッド及び showModelessDialog メソッド)も使用することができます。

JScriptでVBScript(或いはその逆)を実行する

MSIE 独自拡張の execScript メソッドを使用すると、当該スクリプトの言語とは異なる言語のコードを実行することができます。

例えば、Microsoft JScript [JScript] を主体にスクリプトを設計するが Microsoft VBScript [VBScript] の機能を一部取り入れたいといった場面で使用すると良いでしょう。

構文
vReturn = window.execScript(sExpression, sLanguage)
引数
sExpression
引数sLanguageで実行されるスクリプトのコードを文字列で指定する。この引数は必須である。
sLanguage
引数sExpressionのコードが実行される言語を文字列で指定する。初期値はJScript。この引数は必須である。
戻り値
このメソッドは、常に null の値を返す。
記述例 [JScript]
<script type="text/jscript">
//<![CDATA[
  var aExpression = []; // 配列数=行数
  aExpression.push('Dim MyVar');
  aExpression.push('MyVar = MsgBox ("Hello World!", 65, "MsgBox の例")');
  window.execScript(aExpression.join("\n"), "VBScript");
  // 変数 MyVar の値は、MsgBox 関数の戻り値になります。
//]]>
</script>

ガジェットの表示形態によりスタイルシートを切り替える

注釈

私が作成/配布しているガジェットで行っている方法のヒント(文面)です。サンプルは一部のみ記載しています。しかし DOM [DOM] 及び Dynamic HTML [DHTML] の知識が多少あれば、難なく取り込める方法だと思います。

一部記載しているサンプルのスクリプトのコードについては、実際には、クロージャを使った階層構造で定義しているので、私が実際に使用している記述内容とは異なります。

X/HTML [X/HTML] では、代替スタイルシートと呼ばれる、相互に排他的なスタイルシートを多数指定(また、選択して適用)することができます。そして、代替スタイルシート群の1つを優先スタイルシートに指定できます。

Windows サイドバー ガジェットでは、ガジェットの表示形態(System.Gadget.docked プロパティが返す真偽値)が異なっても、ガジェット本体であり UI となる HTML ファイルは単一なので、スタイル情報が変化することもありません。ガジェットの表示形態によりスタイルシートを切り替えるには、優先スタイルシートと代替スタイルシート(また、固定スタイルシート)をガジェット本体であり UI となる HTML ファイルに指定し、スクリプトで DOM [DOM] を利用して、onDockonUndock イベントが発生する度にスタイルシートを切り替えれば良い訳です。具体的には、外部スタイルシート(document.styleSheets で得られる StyleSheetList オブジェクト)と style 要素による指定の全てに対して disabled プロパティの真偽値を切り替えます。

次の例は、スタイルシートの切り替えを行う JavaScript の例を示す。

<script type="text/javascript">
//<![CDATA[
  function selectStyleSheet(styleName) {
    // 外部スタイルシート
    var Sheets = document.styleSheets;
    for (var i=0; i<Sheets.length; i++)
      if (Sheets[i].title != "") {
        Sheets[i].disabled = (Sheets[i].title != styleName);
        Sheets[i].rel = (Sheets[i].title == styleName) ? "stylesheet" : "alternate stylesheet";
      }
    // ヘッダスタイル
    var style = document.getElementsByTagName('STYLE');
    for (var j=0; j<style.length; j++)
      if (style[j].title != "")
        style[j].disabled = (style[j].title != styleName);
  }
//]]>
</script>

X/HTML 文書では、当該文書の優先スタイルシートを meta 要素によっても指定できます。 例えば、スタイルシートの名称が "compact" のスタイルシートを優先スタイルシートにするには、次のような meta 要素を X/HTML 文書 の head 要素に含めることができます。

<meta http-equiv="Default-Style" content="compact" />

http-equiv 属性は、本来 HTTP で取得される際に特別な意味を持ちますが、ガジェットでは無意味です。Default-Style プロパティが意味を持ったとしても、ガジェットの表示形態ごとの優先スタイルシートを指定するプロパティが必要です。そこで、この手法を応用した meta 要素を用いて、ガジェットの表示形態ごとの優先スタイルシートを定義しておけば、スタイルシートの名称が固定とは限らない場合にも、DOM [DOM] を用いて meta 要素を探れば適切なスタイルシートを選択することができます。つまり、スクリプトの補助を行う為の meta 要素を示しておく訳です。

例えば、次の例では、meta 要素の name 属性値がガジェットの表示形態(二通り)のスタイルプロパティを示し、content 属性値がそのプロパティの値(その表示形態で優先するスタイルシートの名称)を指定している。

<meta name="Gadget-Docked-Style" content="Docked Mode" />
<meta name="Gadget-UnDocked-Style" content="UnDocked Mode" />

続いて、X/HTML 文書でのスタイルシートの指定例を示す。次の例では、"Docked Mode" と "UnDocked Mode" と命名した2つのスタイルシート(上記の meta 要素にそれぞれ対応する)を指定している。

<link rel="stylesheet" type="text/css" href="docked.css" title="Docked Mode" />
<link rel="alternate stylesheet" type="text/css" href="undocked.css" title="UnDocked Mode" />

更に、優先スタイルシートのスタイル名称を返す JavaScript の例を示す。

<script type="text/javascript">
//<![CDATA[
  function prefStyleSheet() {
    var prefStyle = "";
    var refHead = document.getElementsByTagName("head").item(0);
    var refMetas = refHead.getElementsByTagName("meta");
    for (var i=0; i<refMetas.length; i++) {
      var preferred = System.Gadget.docked ? "Gadget-Docked-Style" : "Gadget-UnDocked-Style";
      if (refMetas[i].getAttribute("http-equiv") == "Default-Style" || refMetas[i].getAttribute("name") == preferred)
        prefStyle = refMetas[i].getAttribute("content");
    }
    return prefStyle;
  }
//]]>
</script>

上記例の JavaScript を使用する際の例である。onDockonUndock イベント [GadgetAPI]、それぞれのハンドラ関数に次の様な記述を追加して使用する。

<script type="text/javascript">
//<![CDATA[
...
  var prefStyle = prefStyleSheet();
  if (prefStyle != "")
    selectStyleSheet(prefStyle);
...
//]]>
</script>

以上がスタイルシートの選択方法なのですが、しかし、ただ単にスタイルシートを切り替えただけでは、body 要素にマッチする CSS セレクタで定義される内容は正しく適用されません。body 要素の背景のプロパティや内容領域の幅/高さのプロパティ等は、最初に適用されたスタイルシートのままなので、その対処が必要になります。

ところで、Windows Vista に初めからインストールされているガジェットのスクリプトを眺めてみると、ガジェットの表示形態が変化する時に Dynamic HTML [DHTML] のダイナミックスタイル(DOM CSS の CSS2Properties (DOM2 Style [DOM2-Style]) と同等)の手法で、ただ単純に body 要素の背景や内容領域の幅/高さを変更しています。恐らく、ガジェット作成者の多くはこの方法を実践していることでしょう。然しながら、この方法では、スタイルシートを使用する利点が最大限に生かされていません。

先述した、body 要素に必要になる対処方法についてですが、DOM CSS の CSSRule (DOM2 Style [DOM2-Style]) を用いれば、スタイルシートのスタイル規則を個別に得ることができます。然しながら、残念なことに MSIE はこの仕様に未対応です。ですが、ガジェットでは MSIE 独自拡張の rules メソッドで代用できます。これにより、StyleSheetList オブジェクトから body 要素にマッチする CSS セレクタを漏れなく探し出し、スタイルシートの設定値が正しく反映されるように設定し直します。具体的には、繰り返し処理によって selectorText プロパティの値とマッチするセレクタのスタイル規則を得ます。この時、簡略化プロパティによる指定も考慮すべきです。また、スタイルシート内に @import 規則がある時を考慮する場合には、それなりの工夫が更に必要になります。

ざっとでしたが、以上に書き記した方法により、ガジェット本体であり UI となる HTML ファイルからスタイルシートを切り離す利点を最大限に生かしつつ、スタイルシートの切り替えが行えます。設定機能と併用すれば、謂わば、よくあるスキン選択機能を複数のスタイルシートにより提供することも可能です。勿論、ガジェットの表示形態ごとにスタイルシートを切り替える必要が無い場合にも有効な方法だと思います。