やっと(1157010937)の複数対応版ができた

完成しました。はてなは「はてな表記法」のエスケープ処理がたいへんなため、以下のリンク先に置きます。
以前の記事でソースの一部(ScriptLoaderクラス)を出していますが、今回はそれも含んでいますので、完成品としては下記参照先のもので1そろいとなります。

http://www2.u-netsurf.ne.jp/~mug/utility/souvenir/ScriptNodeWriter/
http://www2.u-netsurf.ne.jp/~mug/hatena/20061022/ScriptNodeWriter/


ちなみに、以前のFireFoxで動かない原因は、IEFireFoxでのノードの考え方の違いによるものでした。
document.body.previousSiblingとすれば、すぐにheadタグが取れるとは限らないわけですよね。

HTAでDBアクセスツール作り

相変わらず家に帰ると0時過ぎで、なんだかなぁ〜というお仕事ですが、
仕事の待ち時間にHTAでDBアクセスするツールを作っています。
なんていうか、その時間が満足です。ついついそっちに気が行ってしまいます。

HTAJScriptを使い、

  • Scripting.FileSystemObject
  • MSXML2.DOMDocument
  • ADODB.Stream
  • ADODB.Connection
あたりを使ってDBアクセス(参照・編集・更新)と、XMLファイルの入出力ツールを作っています。
テスト用なんですけれども。

今日は、上記の機能を使うときに参考にしたサイトをメモっときます。

http://msdn.microsoft.com/library/ja/jpado260/htm/mdmscadoapireference.asp
http://www.hawk.34sp.com/stdpls/dwsh/charset_adodb.html
http://www.happy2-island.com/vbs/cafe02/capter00601.shtml

JSDコンパイラがまともな結果を出すようになってきた

JSD*1コンパイル結果がまともなものになってきました。
ウェブアプリ作成のお仕事では、JSはJAVAjavadocのように納品物を作成しづらいのですが、これがあれば・・・と思っています。

http://www2.u-netsurf.ne.jp/~mug/utility/4creator/ClassPackagingTool/jsd_sample/frame.html

ちなみに、67クラスのコンパイルから書き込みまでを約5分で行います。
最初にコンパイル条件などを入力後、全自動で行います。

*1:JavaScriptDocumentの略で、javadocJavaScript

外部JSファイルのダイナミックロードクラス(1157010937)

とりあえず、
◆外部JSファイルのダイナミックロードクラス
└◆document.writeができるようにしたサブクラス
という継承構造のクラス2つで外部JSファイルのロード部分にしようかと思います。

スーパークラス側は汎用的にしておいて、サブクラスでdocument.writeに対応させることにしようかと思います。

このうち、スーパークラス側を作ってみました。
Gecko系ブラウザでは正しく動作しない可能性があります。2006/10/22で修正して(ここはそのまま)います。*1


/**
 * JavaScriptの外部ファイルをロードする。
 */
var ScriptLoader = (function() {
  
  /**
   * スクリプトファイル(1つ)のロードを実行する
   * @param fileUrl ファイル名
   * @param encoding ファイルの文字コード
   * @param type MIMEタイプ
   * @param lang スクリプト言語
   */
  function load(fileUrl, encoding, type, lang) {
    // documentがない(WSH?)→ActiveXで読み込んでeval
    if( (typeof document) == "undefined") {
      var reader = new ActiveXObject("ADODB.Stream");
      if(encoding && ( (typeof encoding) == "string") ) {
        switch(encoding.toLowerCase() ) {
          case "euc_jp":
          case "euc-jp":
          case "eucjp":
            encoding = "x-euc-jp";
            break;
          case "jis":
            encoding = "iso-2022-jp";
            break;
          default:
        }
        reader.charset = encoding;
      } else {
        reader.charset = "_autodetect";
      }
      reader.type = 2;  // このtypeはMIMEタイプではなく、バイナリ(1)かテキスト(2)かである。
      reader.Open();
      reader.LoadFromFile(fileUrl);
      var source = reader.ReadText();
      reader.Close();
      (function() {
        var load   = undefined;
        var reader = undefined;
        var source = undefined;
        var tag    = undefined;
        var tags   = undefined;
        var Class  = undefined;
        eval(arguments[0]);
      })(source);
    }
    // bodyがある(=読み込み後かも)→headに追加
    else if(document.body) {
      var tag = document.createElement("script");
      if(encoding && ( (typeof encoding) == "string") ) {
        tag.charset = encoding;
      }
      if(type && ( (typeof type) == "string") ) {
        tag.type = type;
      }
      if(lang && ( (typeof lang) == "language") ) {
        tag.language = lang;
      }
      tag.src = fileUrl;
      document.body.previousSibling.appendChild(tag);
    }
    // bodyがない(=head読み込み中)→直接書き込み
    else {
      var tags = '<script';
      if(encoding && ( (typeof encoding) == "string") ) {
        tags += ' charset="' + encoding + '"';
      }
      if(type && ( (typeof type) == "string") ) {
        tags += ' type="' + type + '"';
      }
      if(lang && ( (typeof lang) == "language") ) {
        tags += ' language="' + lang + '"';
      }
      tags += ' src="' + fileUrl + '">';
      tags += '</' + 'script>';
      document.writeln(tags);
    }
  }
  
  /**
   * スクリプトファイルのローダークラス
   * @param fileUrl ファイル名またはその配列
   * @param encoding ファイルの文字コード
   * @param type MIMEタイプ
   * @param lang スクリプト言語
   */
  function Class(fileUrl, encoding, type, lang) {
    
    if(!(this instanceof Class) ) {
      return new Class(fileUrl, encoding, type, lang);
    }
    
    this.load = function() {
      if( (typeof fileUrl) == "string") {
        load(fileUrl, encoding, type, lang);
      } else if(fileUrl instanceof Array) {
        for(var i = 0; i < fileUrl.length; i++) {
          if( (typeof fileUrl[i]) == "string") {
            load(fileUrl[i], encoding, type, lang);
          }
        }
      }
    };
    
    return this;
  }
  
  return Class;
})();

参考にしたサイト
以下の検索結果のうち一部(いろいろ)
http://www.google.co.jp/search?num=50&hl=ja&q=JavaScript+%E3%83%AD%E3%83%BC%E3%83%89&lr=
http://www.google.co.jp/search?hl=ja&q=ADODB.Stream&lr=

*1:2006/10/22追記

基本的な処理方針(1157010937)

※この記事はhttp://d.hatena.ne.jp/Mug/20060903の改修案件です。
後から見づらいと思うのでタグをつけました。1157010937では長いので、下3桁で937とします。
この記事以前の投稿は、時系列(上から下へ)下記のものです。

  1. 元はこの質問でした。
    http://q.hatena.ne.jp/1157010937
  2. 私の回答です。
    http://d.hatena.ne.jp/Mug/20060903
  3. 今後&複数対応どうするか。
    http://d.hatena.ne.jp/Mug/20060915

最初に、まずは細かいところはどうでもよく、アルゴリズムから考え直します。

JS外部ファイルの動的ロード方法
⇒以前の通りで、scriptタグをdocument.createElementする。(参考:Ajaxでは別サーバーに対応できない。)
読み込んだ外部JSファイルのdocument.writeを救う方法
⇒これも以前の通り。ネイティブのdocument.writeを詐称する。
外部JSファイルのロードタイミングについて
⇒1件ずつ順番に行う。以前のようにパラレルだとどのJSファイルからdocument.writeなのか判別不能のため。
document.writeを戻すタイミングについて
⇒おおよそ以前の方法と同じ。外部JSファイルの実行完了はキャッチできない*1ので、その外部JSファイルで最初のdocument.writeで戻し関数をタイマーセット(0秒)し、JSのスレッド終了時点で戻し関数を発動させる。
document.writeを戻すタイムアウト*2について
⇒以前と同じ構造。外部JSファイルをロードするときに戻し関数をタイムアウト秒数後に発動するようにする。ただし、外部JSファイルの最初のdocument.writeが早かった場合、これを解除する。
document.writeされた内容の処遇(案)
⇒【これは案です】変数に溜めておいて、予め指定された関数に引数として渡す…かな。
正直、ここまでが1つの単位(クラスとか何かの単位)になると思っています。
つまり、元の質問では動的に生成した文字列の中にscriptタグがあったのですが、そことは切り離して別機能としようと思います。

…最初の基本方針としては以上のような感じでしょうか。

*1:方法がわからないだけかも?!

*2:外部JSファイルにdocument.writeがなかった場合の対応

はてな質問に対する回答のその後について

http://q.hatena.ne.jp/1157010937での回答で、何か書くと言った分の投稿です。

【結論】
このブログ上で、考えて、修正していこうかと思います。*1

【理由】
時間がないから。
タクシーor徹夜はギリギリ防いでいるけれど、毎日ほぼ終電&休日出勤当たり前の状態があと1ヶ月くらいは続きそうなので。
しかにも(この間の回答の)ソースコードを修正すべき点が多く、アルゴリズムから考え直さねばならないようです。

【方法】
気が付いたことやアイデア等をこのブログ上でメモしていきます。
ブログのサブタイトルには“(1157010937)”を入れることにします。

*1:何の話かははてなの質問を見てください。