Now browsing the SCRAPBLOG weblog archives.

非同期ループ処理 (2)

開始処理~処理~終了処理という形で見やすく切り分けた方法。

var simpleAsyncProcessor = {

    _array : [],

    start : function(aArray)
    {
        // 開始処理
        dump("start
");
        // 初期化
        this._array = aArray;
        this._process();
    },

    _process : function()
    {
        var elt = this._array.shift();
        if ( !elt ) {
            simpleAsyncProcessor._finish();
            return;
        }
        // 処理
        dump("processing... " + elt + "
");
        // 次の処理へ
        setTimeout(function(){ simpleAsyncProcessor._process(); }, 500);
    },

    _finish : function()
    {
        // 終了処理
        dump("finish
");
    },

};

simpleAsyncProcessor.start(['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']);

TOP

非同期ループ処理 (1)

要素数が多い配列に対して順番に処理を行うような場合に、 for や while で単純にループさせると、処理が終わるまでに一時的な無応答状態に陥ってしまう、あるいは時間がかかりすぎてスクリプトを続行するかどうかの警告が表示されてしまうことがある。

そこで、setTimeoutを連発してこれを防ぐ。

まずは、対象となる配列を引数に再帰的に関数を呼び出す方法。
なお、下記の例では確認しやすいように500ミリ秒後に次の処理へ進むが、実際は0ミリ秒で構わない。

function processRecursive(aArray)
{
    var elt = aArray.shift();
    if ( elt ) {
        // 処理
        dump("processing... " + elt + "
");
        setTimeout(function(){ processRecursive(aArray); }, 500);
    } else {
        // 終了処理
        dump("finish
");
    }
}

processRecursive(['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']);

TOP

ユーザ名とパスワードを入力するプロンプト

ユーザ名とパスワードを入力するプロンプトはわざわざ自前で作らなくても nsIPromptService で可能。なお、 promptUsernameAndPassword メソッドの6,7番目の引数を利用してチェックボックス付きのプロンプトにすることもできる。

var user = { value : "" }, pass = { value : "" };
var promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"]
                .getService(Ci.nsIPromptService);
var ret = promptSvc.promptUsernameAndPassword(
  window, "Authorization", "Enter username and password.", 
  user, pass, null, {}
);
if (ret)
  alert("user:" + user.value + "
pass:" + pass.value);
else
  alert("canceled.");

リファレンス:
Interface Reference – nsIPromptService

TOP

パスワード管理

Webサービスを利用するXULアプリでは、たいていの場合、ログインするためのユーザ名やパスワードが付きものだ。入力したユーザ名やパスワードを記憶するために、 nsIPrefService などを利用して pref.js へ保存する?それは簡単だが好ましい方法ではない。
XULにはURIに関連付けてユーザ名やパスワードを管理する仕組みがきちんと提供されているのである。パスワードを保存したり削除したりするには nsIPasswordManager を、保存されたパスワードを問い合わせるには nsIPasswordManagerInternal を利用する。

const PM  = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
const PMI = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManagerInternal);

例えば、 http://www.example.com に関連付けられたパスワードを問い合わせるには、以下のようにする。

var host = { value : "" }, user = { value : "" }, pass = { value : ""};
try {
  PMI.findPasswordEntry("http://www.example.com", null, null, host, user, pass);
}
catch (ex) {
  // 該当するユーザ名やパスワードが見つからない
}
alert("host:" + host.value + "
user:" + user.value + "
pass:" + pass.value);

http://www.example.com のユーザ名 foo のパスワード bar を保存するには、以下のようにする。どうやら同じユーザ名で別のパスワードを保存しようとしてもうまくいかないようなので、一度 removeUser で削除した後、 addUser で追加するという方法である。

try {
  PM.removeUser("http://www.example.com", "foo");
}
catch (ex) {
  // ユーザ名 foo が存在しない場合、例外発生
}
try {
  PM.addUser("http://www.example.com", "foo", "bar");
}
catch (ex) {
  // 何らかの例外
}

なお、Firefox では保存されたユーザ名やパスワードが ツール > オプション > プライバシー > パスワード > 保存されているパスワードを表示 でパスワードマネージャを開くことができる。

リファレンス:
Interface Reference – nsIPasswordManager
Interface Reference – nsIPasswordManagerInternal

TOP

タブに開いたchromeウィンドウからタブを閉じる

ブラウザタブに chrome:// のURLをロードして読み込まれた Window から、タブを閉じる方法。
単純に Window 内で window.close(); してやればタブは閉じられる。
しかし、タブが残りひとつであった場合、ウィンドウ自体も閉じられてしまう。
これを防ぐには、親のブラウザウィンドウを参照し、 cmd_close コマンドを実行すれば良い。
タブ内の Window から親のブラウザウィンドウを参照するには、 nsIWindowMediator を利用すれば良い。ただし、最後に使用したブラウザウィンドウが親のブラウザウィンドウであるという前提条件付きである。

var winMed = Components.classes['@mozilla.org/appshell/window-mediator;1'].
             getService(Components.interfaces.nsIWindowMediator); 
var browserWin = winMed.getMostRecentWindow("navigator:browser");
browserWin.document.getElementById("cmd_close").doCommand();

TOP

textboxのundo/redo履歴をクリアする

Firefox 2.0 以降であれば、 textbox 要素の editor プロパティから nsIEditor にアクセスし、 nsIEditor の transactionManager プロパティからアンドゥやリドゥについての色々な操作が可能である。
例えばアンドゥ/リドゥの履歴をクリアするには以下のようにすればよい。

document.getElementById("myTextbox").editor.transactionManager.clear();

ちなみに chrome://browser/content/sanitize.js を見ると、

searchBar.textbox.editor.enableUndo(false);
searchBar.textbox.editor.enableUndo(true);

というやり方をしている。これでも同じ結果が得られるようだ。

リファレンス:
Interface Reference – nsIEditor
Interface Reference – nsITransactionManager

ScrapBookのバグBug 13244 – Undo works throughout multiple notes がめでたくFixできそうだ。

TOP

Mozilla Party 7.0 – プレゼンテーション資料

4月30日に Mozilla Party 7.0 が開催されました。そのときのプレゼンテーション資料はこちらへアップしました。

TOP