2009年3月31日火曜日

JavaScriptでWYSIWYGエディタへの道

JavaScriptのWYSIWYGエディタは世の中にたくさんあるけれど、いったいどうやって実現しているんだろう?
…と気になってしまって夜も眠れなくなりそうになったのでちょっと調べてみた。

最初に見つけたのは、iframeを作ってcontentEditable = trueにする方法だった。

contentEditable.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>contentEditable</title>
<script type="text/javascript">
//<![CDATA[
var o = null;
var f = null;
var d = null;
var b = null;
var la = null;
function findBody(doc){
for(var i = 0; i < doc.childNodes.length; ++i){
if(doc.childNodes[i].nodeName == 'HTML'){
for(var j = 0; j < doc.childNodes[i].childNodes.length; ++j){
if(doc.childNodes[i].childNodes[j].nodeName == 'BODY'){
return doc.childNodes[i].childNodes[j];
}
}
}
}
return null;
}
function onLoad1(){
o = document.getElementById('o');

f = document.getElementById('f');
d = f.contentDocument;
b = findBody(d);
d.charset = 'utf-8';
b.contentEditable = true;
b.innerHTML = '<div>HELLO WORLD</div>'
+ '<font style="color:red;">red string</font> '
+ '<a href="http://www.google.com/">google</a> '
+ '<font style="color:blue;">blue string</font>'
+ '<div>editable</div>';
b.focus();
}
function test1(){
var s = f.contentWindow.getSelection();
for(var i = 0; i < s.rangeCount; ++i){
var r = s.getRangeAt(i);
la = r;
var fragment = d.createDocumentFragment();
var div = d.createElement('div');
div.innerHTML = '<font style="color:green;font-size:large;font-weight:bold;">'
+ r + '</font>';
while(div.firstChild){
fragment.appendChild(div.firstChild);
}
var container = r.startContainer;
var offset = r.startOffset;
r.deleteContents();
switch(container.nodeType){
case 1:
container.insertBefore(fragment, container.clidNodes[offset]);
break;
case 3:
var node = container.splitText(offset);
node.parentNode.insertBefore(fragment, node);
break;
}
}
}
//]]>
</script>
</head>
<body onload="javascript:onLoad1()">
hello
world<br/>
<iframe name="f" id="f" src="about:blank" width="200" height="150"></iframe><br/>
<input type="button" value="test1" onclick="javascript:test1()"/><br/>
<span name="o" id="o">...</span>
</body>
</html>

※注意※IEでは動きません。

0 件のコメント:

コメントを投稿