javascriptで継続

業務で、wysiwygエディタを書くことになったんだけど、iframeのcontentWindow.documentには
iframeノード生成時にはアクセスできない。HTMLドキュメントに書き込んでからアクセス可能となるようだ。

var id = get_uniq_id();

var textarea = convert_to_html_node(
     ["iframe",{
        id: "edit_"+id,
        onmouseout:function(){make_html();},
        className: "editor"}]);

var doc = textarea.contentWindow.document; //!!!この時点ではアクセスできない。

document.body.appendChild(textarea); //こうすると

var doc = $("edit_"+id).contentWindow.document; // できる。
doc.designMode = "on";
...

これだと、動的にwysiwygエディタや他の要素をjsで作っていく際に、関数的に書いているとちょっと面倒だ(手続き的なら大丈夫だが)。つまり、こちらはreturnの連鎖などでノードツリーをすべて作ってから、一気にHTMLに書き込みたいのに、その部分の処理だけ、後で実行する必要がある。

しかし、ノードを作る時点ではそのid名や各種パラメータなどがわかっていても、HTMLに書き込む時点では不明となったりする。

また、もしわかっていたとしても、ノードの初期化処理はノードの生成場所にまとめて定義したい。

var form = function(){
  var id = get_uniq_id();
  var make_html = function(){ ... };
  var node = ...;

  var text_area = ...;
  var doc = textarea.contentWindow.document; // !!!この時点ではアクセスできない。

  return ["div", {id:"form_"+id}, node, text_area];
}

function main(){
  var node = textarea();
  document.body.appendChild(node);
  var doc = $("edit_"+id).contentWindow.document; //書き込む時点でidパラメーターが不明。
  //この例だとidをこちらで定義して渡すとかはできるが、初期化処理が分散しよくない。
  //また、iframe以外のノードも帰ってくる可能性がある際に面倒が増す。
  ...
}

そこで継続を使う。

継続とはSchemeなどで使われるやりかたで、一時的にあるコンテキストでの環境を関数に閉包し、それを任意の時点で起動させることらしい。

結論はたいしたことじゃないが、以下のようにする。

var form = function(){
  var id = get_uniq_id();
  var make_html = function(){ ... };
  var text_area = ...;
  //この時点ではアクセスできないのでパラメーターと処理をクロージャーにしまう。
  var after_func = function(){
    var doc = $("edit_"+id).contentWindow.document;
    doc.designMode = "on";
  };

  return [["div",{id: "form_"+id},text_area], after_func];//返す
}
function main(){
  var node_and_after = textarea();
  var node = node[0];
  var after = node[1];
  document.body.appendChild(node);
  after();//ここで実行。
}

こんな感じて実行できる。

実際はこれでもだめで、更にtimerで1ms遅らさないとだめだった。

js言語の形としては関数的にもかけるが、関数的に書こうとすると微妙に相性の悪い機能が多い。

  • この件とか、appendChildとか、pop()、shift()系とかもそうだし、sortとかも。
  • 結構落とし穴があるので書くときには気をつけなければならない。
  • どっちかにすればいいのにと思う。