SimpleBoxes

WebKit で CodePress を利用するために

CodePress (http://codepress.org/) は、ウェブブラウザ上で HTML や JavaScript などのソースを編集するために、文法カラーリングなどをサポートする便利なスクリプトです。

CodePress in Safari

Movable Type 4 では、テンプレートエディタとして利用されていて、Serene Bach 3 でも大いに利用しています。

CodePress の最新リリースバージョンは v 0.9.5 ですが、サポートされているブラウザは Firefox (Mozilla系ブラウザ)、Internet Explorer for Windows、Opera となっています。Safari は残念ながら、現時点では対象外です。

ざっと調べてみましたが、基本的な機能(文法カラーリング)ならば、Safari でも動作させることができます→CodePress 動作サンプル

Onload イベント

Firefox と Opera では、DOMContentLoaded イベントをトリガーにして CodePress を起動させています。

このイベントは Safari ではサポートされていません。従って、DOMContentLoaded の代わりに load イベントを利用します。

contentWindow の挙動の差異

CodePress では、textarea 要素にかぶせるようにして iframe 要素を配置して、その中で独自のエディタを動作させます。

iframe 要素で動作させたエディタの内部情報を取得するのに contentWindow プロパティを利用しています。

contentWindow は Safari 2.0 でも動作するのですが、その挙動が若干 Firefox などとは異なるため、iframe 内部の情報を正しく取得することができません。

codepress.js では、以下のようにして iframe で定義された CodePress オブジェクトを取得しています。

self.editor = self.contentWindow.CodePress;

[note] ここで、self は CodePress で作成した iframe 要素の DOM オブジェクトです。

self.editor には、iframe 内部で生成された CodePress オブジェクトが入って、内部の setCode やら syntaxHightlight やらのメソッドをコールできるようになります。

self.editor.setCode(self.textarea.value);
self.editor.syntaxHighlight('init');

ところが、Safari では、self.editor.setCode が関数ではないと怒られます。ontentWindow 自体はきちんと認識されているにもかかわらず、それを変数に代入すると参照できなくなってしまうような印象です。

ですので、Safari では、self.editor を利用するのではなく、常時 contentWindow を介して内部関数をコールしてあげる必要がある様子です。

self.contentWindow.CodePress.setCode(self.textarea.value);
self.contentWindow.CodePress.syntaxHighlight('init');

getSelection と getRangeAt

Safari では、Firefox 同様、window.getSelection が利用できます。

Firefox では、以下のようなコードで、選択された範囲の DOM Range オブジェクト range を取得できます。

var range = window.getSelection().getRangeAt(0);

しかしながら、Safari では、getSelection で取得できる DOM Selection オブジェクトが getRangeAt というメソッドを持っていないようです

[note] Safari 2.0.4 でのみ確認。Safari 3.0 では確認していません。

そこで、Safari では以下のようなコードで選択された範囲の DOM Range オブジェクト range を取得します。

var selection = window.getSelection();
var range = window.document.createRange();
range.setStart(selection.baseNode, selection.baseOffset);
range.setEnd(selection.extentNode, selection.extentOffset);

designMode で編集された内容

Safari では、Firefox 同様、iframe の属性として、designMode = 'on' をセットすることで、iframe の内容を編集可能にします。

CodePress では、マークアップはシンタックスカラーリングのためだけに利用されます。

そのため、syntaxHightlight メソッドで、シンタックスカラーリングを行う際に、一度編集された内容を復元して、マークアップし直すという操作が行われます。

designMode を変更して、編集モードになった時に、Safari では、改行挿入時に行われる操作が Firefox とは異なるため、そのままでは適用できません。

具体的には以下のような操作になるようです。

  • 一回目の改行では、ブロック分け操作になる。そのため空の div 要素が挿入される。
  • そのまま二回目の改行では、br 要素が挿入されるが、class 属性として、khtml-block-placeholder (Safari 3.0 では webkit-block-placeholder) が指定されている。

そのため、改行コードのバッファリング操作が Firefox とは異なります。

iframe に対するスタイル指定

CodePress では、iframe の読み込みを行う前に iframe のスタイルに関して position プロパティを absolute に指定しています。

挿入される iframe によって、textarea がずれてしまう現象を防ぐために行っているようです。

Safari 2 だと、position プロパティを absolute から static に変更すると、何故か iframe を再度読み込んでしまう現象が発生します。

これを防ぐためには position プロパティを最初から static にしておくという対処が考えられます。

ちなみにこのバグ(?)は Safari 3 では修正されているようで、Safari 3 では、この修正をする必要はありません。

更なる問題

ここまでの対応で、とりあえず CodePress の基本的な動作は実現可能になります。

しかしながら、CodePress 起動後の CodePress へのアクセスなどまだ解決すべき問題が残っています。

また、安定性も今ひとつで、特に undo 操作を行うと簡単にブラウザが落ちます。普通に利用する分には問題なさそうですが。

スポンサーリンク

<< [perl]ハッシュ(連想配列)のマージ :: BEGIN ブロックではまる (perl) >>