ホーム >> 左脳Script >> Movable Type >> Plugin開発 >> 記事編集画面に操作ボタンを追加するには

記事編集画面に操作ボタンを追加するには


Movable Type のプラグインについてアレコレ調べる内に・・・エディタにボタンを追加して、エディタの機能の拡張をする物は、どのようにして作っているのかと疑問に思い始めました。

「Movable Type plugin 作成」なんてキーワードで検索すると、プラグイン作成の基礎となる「フィルター、コンテナタグ」等の作成方法を解説したページが良くヒットします。

ところが、エディタの機能拡張の説明が目に付くページがなかなかヒットしません。(斜め読みの可能性アリ


どうやら「Transformerプラグイン」と言われる分類のプラグインのようです。これで検索してみるも・・・ナニか、イマイチ判りにくい。もっと、こう、分りやすいモノはにぃのか?!

分りやすいマニュアル&リファレンスを探すより、人様のソースを見て独学する方が早いかもしれません。
と言うわけで、勉強サンプルの作成。


たたき台から実験

この部分は、Movable Type プラグインの基礎的な部分で、どんな種類のプラグインでも殆ど同じです。

package MT::Plugin::ezTest;

use strict;

use base qw(MT::Plugin);

my $plugin = new MT::Plugin::ezTest({
    name => 'easy test',
    version => '0.00+00',
    description => 'プラグイン作成サンプル',
    doc_link => 'http://n-yagi.0r2.net/script/',
    author_name => 'N-yagi',
    author_link => 'http://n-yagi.0r2.net/'
});
MT->add_plugin ($plugin);

以下の記述が、Transformerプラグインの特徴といえる書き方(他にも方法はある模様)で、テンプレートのソースを入れ替える為の記述のようです。

MT->add_callback('MT::App::CMS::template_source.archetype_editor', 9, $plugin, \&_insert);
具体的には、「template_source」がテンプレートソースを示しているとの事。この記述は、Movable Type Movable Type で、指定方法が違うらしいので注意して下さい。この記事では、 Movable Type を対象としています。

対象となるテンプレートは、「Movable Type インストールディレクトリ」 >> tmpl >> cms >> include と辿った先にあります。

上記 add_callbackで指定した、「_insert」関数で、指定したテンプレート内の記述を変更する動作をします。テンプレートを良く眺め、変更箇所を良く考えて指定してください。

sub _insert {
    my ($eh, $app, $tmpl_ref) = @_;
    my $old = <<HTML;
<a href="javascript: void 0;" title="<__trans phrase="HTML Mode" escape="html">" mt:command="set-mode-textarea" class="command-toggle-html toolbar button"><b>HTML Mode</b><s></s></a>
HTML
    $old = quotemeta($old);
    my $new= <<HTML;
<a href="javascript: void 0;" title="<__trans phrase="HTML Mode" escape="html">" mt:command="set-mode-textarea" class="command-toggle-html toolbar button"><b>HTML Mode</b><s></s></a>
<p>こまねち!</p>
HTML
    $$tmpl_ref =~ s/$old/$new/;
}

1;
上記コードでは、$old 変数で指定された文字列を、$new に置き換える作業をしています。

ボタン追加の試験ですので、エディタの「HTML ボタン」の右側に、何か追加してみましょう。


komanechi.PNG ひとまず成功です!

これで、ボタンの追加方法は分りました。

では、次に・・・


ボタンに機能を加える

機能を追加するには、どうしたらようでしょう。
それはどんな機能を実装するかにも寄るのですが、どんな機能であっても基本的に変わらない部分もあります。

エディタなのですから、
  • キャレット(エディタのカーソル)で指定された箇所のテキストが変化する。
  • 選択されているテキストが変化する(なんらかの変換をされる)
という動作をすることです。

つまり、ボタンを押した時に、「キャレットの位置」、「選択されたテキスト」が分らなければいけません。

また、エディタ自体はクライアントでの動作となります。したがって、ブラウザ上で動く事が最低限の条件となります。一般的には、ボタンの機能は Java Script で実装されます。

先の実験サンプルで言えば、「<p>こまねち!<p>」の部分に、「ボタンの形状から機能の全てまで」を全部記述する事になります。


まずは、既にあるボタンの形状に習ったボタンを作るところから。
以下、「<p>こまねち!<p>」の部分にあたるコードだけを示します。

<a href="javascript: void 0;" title="<__trans phrase="Test" escape="html">" class="toolbar button"><b>Test</b><s></s></a>
うーん、どうやら元々あるボタンは画像で作られている物のようですね。

testbtn.PNG 適当に"Test"と指定した部分が、「テスト」と翻訳されるとは思いませんでした。ただ、後ろに「class=」とゴミが付いているので、正しい指定を模索する必要があるようです。
2009年6月24日追記:上記コードの titleパラメータを二重引用符で正しく閉じていない事が原因でした。

ここで、画像を作るのは面倒なので、このテキストリンク型のまま突き進む事にします。プラグインとしての機能が完成し、リリースする段階で画像アイコンを作ればよいでしょう。

さて、ボタンが押下された時に呼び出される関数を作りましょう。

<script type="text/javascript">
function testFunction()
{
    alert("test!");
}
</script>
<a href="javascript: void 0;" title="<__trans phrase="Test" escape="html">" class="toolbar button" onclick="testFunction()"><b>Test</b><s></s></a>

testalert.PNG ひとまず、ボタンとしての動作を確認。

上手く動けば、後はこの関数内に記述をするだけです。


選択されたテキストの取得

testselect.PNG エディタで選択されているテキストの取得する関数です。とても簡単ですね。

function testFunction()
{
    alert( app.editor.actual.getSelectedText() );
}


実はこのままでは、エディタのフォーマットリッチテキストの場合、正しく動作しません。
フォーマットに対応したコードはこれだけの記述が必要になるようです。

function testFunction()
{
    var edit = app.editor.actual;
    var text = "";
    if(app.editor.mode != 'iframe')
    {
        text    =   edit.getSelectedText();
    }
    else
    {
        var selection = edit.getSelection();
        if(selection.createRange)
        {
            range = selection.createRange();
            text = range.htmlText;
        }else if(selection.getRangeAt)
        {
            range = selection.getRangeAt(0);
            var df = range.cloneContents();
            var doc = range.startContainer.ownerDocument;
            var div = doc.createElement('div');
            div.appendChild(df);
            text = div.innerHTML;
        }
    }
    alert(text);
}

testselect2.PNG タグを跨いでいても、正しく抜き出します。


テキストの加工&設定

テキストの取得が出来ました。これから、テキストの設定をする関数を作ります。
加工に関しては「プラグインの特色を決める主機能」となりますが、それは各自がプラグインを作る目的であり、ここで私が説明することではありません。したがって、選択されたテキストを加工し終えた後の、加工したテキストをエディタへ書き戻すところから説明します。


function getSelectedText()
{
    var edit = app.editor.actual;
    if(app.editor.mode != 'iframe')
    {
        text    =   edit.getSelectedText();
    }
    else
    {
        var selection = edit.getSelection();
        if(selection.createRange)
        {
            range = selection.createRange();
            text = range.htmlText;
        }
        else if(selection.getRangeAt)
        {
            range = selection.getRangeAt(0);
            var df = range.cloneContents();
            var doc = range.startContainer.ownerDocument;
            var div = doc.createElement('div');
            div.appendChild(df);
            text = div.innerHTML;
        }
    }
    return  text;
}
function setSelectedText(text)
{
    var edit = app.editor.actual;
    if(app.editor.mode != 'iframe')
    {
        if ( !defined(text) ) text = '';
        edit.setSelection(text);
    }
    else
    {
        var selection = edit.getSelection();
        if(selection.createRange)
        {
            range.pasteHTML(text);
        }
        else if(selection.getRangeAt)
        {
            edit.document.execCommand('inserthtml', false, text); 
        }
    }
}
function testFunction()
{
    var text    =   getSelectedText();
    alert(text);
    setSelectedText("こまねち!");
}
選択された文字列を取得する関数を getSelectedText 、設定する関数を setSelectedText と分けました。

test0.PNG コードを見ると分りますが、選択したテキストを問答無用で「こまねち!」に変換してしまう大変恐ろしい機能を実現しています。
test1.PNG変換後。


今回の実験ソースコード全容


package MT::Plugin::ezTest;

use strict;

use base qw(MT::Plugin);

my $plugin = new MT::Plugin::ezTest({
    name => 'easy test',
    version => '0.00+00',
    description => 'プラグイン作成サンプル',
    doc_link => 'http://n-yagi.0r2.net/script/',
    author_name => 'N-yagi',
    author_link => 'http://n-yagi.0r2.net/'
});
MT->add_plugin ($plugin);

MT->add_callback('MT::App::CMS::template_source.archetype_editor', 9, $plugin, \&_insert);

sub _insert {
    my ($eh, $app, $tmpl_ref) = @_;
    my $old = <<HTML;
<a href="javascript: void 0;" title="<__trans phrase="HTML Mode" escape="html">" mt:command="set-mode-textarea" class="command-toggle-html toolbar button"><b>HTML Mode</b><s></s></a>
HTML
    $old = quotemeta($old);
    my $new= <<HTML;
<a href="javascript: void 0;" title="<__trans phrase="HTML Mode" escape="html">" mt:command="set-mode-textarea" class="command-toggle-html toolbar button"><b>HTML Mode</b><s></s></a>
<script type="text/javascript">
function getSelectedText()
{
    var edit = app.editor.actual;
    if(app.editor.mode != 'iframe')
    {
        text    =   edit.getSelectedText();
    }
    else
    {
        var selection = edit.getSelection();
        if(selection.createRange)
        {
            range = selection.createRange();
            text = range.htmlText;
        }
        else if(selection.getRangeAt)
        {
            range = selection.getRangeAt(0);
            var df = range.cloneContents();
            var doc = range.startContainer.ownerDocument;
            var div = doc.createElement('div');
            div.appendChild(df);
            text = div.innerHTML;
        }
    }
    return  text;
}
function setSelectedText(text)
{
    var edit = app.editor.actual;
    if(app.editor.mode != 'iframe')
    {
        if ( !defined(text) ) text = '';
        edit.setSelection(text);
    }
    else
    {
        var selection = edit.getSelection();
        if(selection.createRange)
        {
            range.pasteHTML(text);
        }
        else if(selection.getRangeAt)
        {
            edit.document.execCommand('inserthtml', false, text); 
        }
    }
}
function testFunction()
{
    var text    =   getSelectedText();
    alert(text);
    setSelectedText("こまねち!");
}
</script>
<a href="javascript: void 0;" title="<__trans phrase="Test" escape="html">" class="toolbar button" onclick="testFunction()"><b>Test</b><s></s></a>
HTML
    $$tmpl_ref =~ s/$old/$new/;
}

1;
2009年6月17日追記:上記ソースコードの一部に、二重引用符の抜けが有ったようなので修正いたしました。ご迷惑お掛けしました。


さいごに

イカがでしたでしょうか。アイコンこそ作りませんでしたが、Movable Type のエディタに編集機能を追加するプラグインの作り方が判ったと思います。
このタイプのプラグインは、基本 Java Script メインです。テキストの変換部分が勘所であり、ここを工夫すれば、きっとアンなコトやコンなブログ記事を実現できるようになるでしょう。是非、有用なプラグインを作って公開して頂きたいと思います。

この記事を作成するに当り、

MTの編集画面にカラーピッカーを付けるcolorEditorプラグイン(http://blog.webcreativepark.net/2008/04/30-234954.html)

カラピッカーのソースを参考にさせて頂きました。テキストの取得と設定部分は殆ど流用です。




トラックバック(0)

トラックバックURL: http://n-yagi.0r2.net/sanoupulurun/mt-tb.cgi/86

コメントする

ホーム >> 左脳Script >> Movable Type >> Plugin開発 >> 記事編集画面に操作ボタンを追加するには

アーカイブ

このブログ記事について

このページは、n-yagiが2009年5月17日 23:07に書いたブログ記事です。

ひとつ前のブログ記事は「リダイレクトするテンプレート」です。

次のブログ記事は「Gmail を使えるようにしてみよう。」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Creative Commons License
このブログはクリエイティブ・コモンズでライセンスされています。