htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

window.open で生成した DOMWindowオブジェクトのDOCTYPEを指定する

完全に趣味の範囲ですが…。

下記コードで使われることになる document.implementation ですが、主要ブラウザはほぼ対応しています。
ただしIE8のみDOMImplementationは存在しているのに、メソッドがないという謎な状況になっています。

// wnd に DOMWindowを入れる。
var wnd = window.open("about:blank", "_blank");

// DocumentTypeオブジェクトを作る。
var doctype = document.implementation.createDocumentType(
    "html",
    "-//W3C//DTD XHTML 1.0//EN",
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");

// 挿入します。
wnd.document.insertBefore(doctype, wnd.document.getElementsByTagName("html")[0]); // IE9はここで例外

IE9ではDocumentTypeオブジェクト挿入の段階で DOM Exception: HIERARCHY_REQUEST_ERR (3) な例外が発生します。
回避方法が分かりません…。
Rangeオブジェクトで範囲とってぶち込めばいいのかな?

回避方法が分かりました。
DocumentTypeを作るのはwnd内でやらなきゃいけなかったみたいです。
なんでこんな初歩的なことに気付かなかったんだ…。

var doctype = wnd.document.implementation.createDocumentType(
    "html",
    "-//W3C//DTD XHTML 1.0//EN",
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
wnd.document.insertBefore(doctype, wnd.document.getElementsByTagName("html")[0]);

挿入時のコードですが、たぶん

wnd.document.insertBefore(doctype, wnd.document.firstChild);

でもいいような気がします。

また、RangeオブジェクトでinsertNodeするのもアリです。

var range = document.createRange();

range.selectNodeContents(wnd.document);
// もしくは range.selectNode(wnd.document.getElementsByTagName("html")[0]);

range.insertNode(doctype);

こっちの方がよりDOMを触ってる感じがしますね!
ただし、IE8以下ではRangeオブジェクトは使えません。

あと、今回は挿入に insertBefore を使っていますが、
これではなく appendChild を使うと、HTML上では

<html>
    <head></head>
    <body></body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

という許されざる状況になるのでよくないと思います。


最後に、createDocumentTypeメソッドの第二引数と第三引数に null を渡してあげると、HTML5形式になります。