MT4 のクイックポストを EUC-JP で使う方法

| コメント(0)

Movable Type にはブックマークレットによるクイックポストという機能が用意されている。ところがこの機能、MT4 以降では文字コードに EUC-JP を使用していると利用できないのだ。ブログ記事投稿画面の下部に表示されているリンクをブックマークして利用しようとしても、そのままだと「不正な要求です。文字コードEUC-JPに含まれない文字データを送信しています。」というメッセージが表示されて、ブログ記事投稿画面に到達することができない。ページのタイトルや選択文字列に日本語の文字が含まれていた場合、JavaScript はそれを UNICODE でエスケープして送信するのだが、MT の側ではその文字列の処理を拒絶してしまうようなのだ。確かめていないけどこれはおそらく Shift JIS でも同様だと思う。

EUC-JPでもクイックポストを使いたい (うむらうす)にはスクリプトからページ・タイトルや選択文字列を送信する部分をカットするという方法が紹介されている。これはこれで一つの方法には違いないけれど、本質的な解決にはなっていない。この問題に何とか対処できないかと予てから考えていたのだけど、このほど JavaScript の勉強がてら腰を据えて取り組んでみて、苦難の末にどうにかうまく成功したのでここに記録しておくことにする。


まず最初に考えたのは MT の側で受けとった文字列のコードを変換して扱うようにできないか、ということだった。しかしこれはソースを見てもよくわからないし、下手にいじってほかの機能がダメになっても困るので断念。そこでスクリプトを修正して文字列を送信する側でコードを変換することを考えた。そのためのライブラリとして ecl.js という便利なものが公開されていて、それ自体は簡単にできる。またブックマークレットで外部ライブラリを読み込むことも特に難しくはない。ただ、それで普通にやってもなかなかうまくはいかないのだ。

調べてみると、JavaScript では外部ファイルを動的に読み込む場合、処理が非同期に行われることに原因があるらしい。今回のケースでいうと、ecl.js の読み込みが終わらないうちに文字コードの変換を行おうとするのでエラーとなるようだ。この仕様には利点もあるものの、ブックマークレットのような場合には大きな障害となる。これは本職のプログラマにとっても対処するのがなかなか難しい問題のようだ。

ブックマークを2回クリックすると2回目の時点ではすでに読み込みが終わっているので無事ブログ記事投稿画面にたどり着くことができる。実用上はこれで十分といえるかも知れないが、それでは何ともすっきりしないので回避できる方法はないか調べてみた。


いくつかの方法が紹介されていたのだが、それに従ってやってみても私のやり方がまずいのか自分の環境ではなかなかうまくいかなかった。いくつか試行錯誤するうちにたどり着いたのがいつでも jQuery を読み込めるブックマークレット jQuerify | バシャログ。である。これを参考にしてやってみたところ見事に成功したので、その方法を以下に紹介する。

  1. まず Escape Codec Library: ecl.js からライブラリ ecl.js をダウンロードし、どこかのサーバにアップロードしておく。MT を運用しているサーバでもいいし、ほかに利用できるサーバ・スペースがあればそれを使っても構わない。
  2. 以下のスクリプトをブックマークに登録する。もちろん ecl.js や MT のアドレス、blogid などは自分の環境に応じて適宜修正する。変更が必要になる(かも知れない)箇所は青字で記載。
    javascript:(function(){scr=document.createElement('script');scr.setAttribute('type','text/javascript');scr.setAttribute('src','http://www.your-site.com/ecl.js');document.getElementsByTagName('body')[0].appendChild(scr);id=window.setInterval(function(){if(JCT8836){window.clearInterval(id);d=document;w=window;t='';url=d.location.href.replace(/#.*$/,'');str='';if(d.selection)t=d.selection.createRange().text;else{if(d.getSelection)t=d.getSelection();else{if(w.getSelection)t=w.getSelection();}};if(t.match(/\n|\r/))str='<blockquote%20cite="'+url+'">\n%20%20<p>'+t.replace(/[\n\r]+/g,'</p>\n%20%20<p>')+'</p>\n%20%20<cite>'+d.title.link(url)+'</cite>\n</blockquote>';else{if(t)str='<q%20cite="'+url+'">'+t+'</q>('+d.title.link(url)+')';else{str=d.title.link(url);}};void(w.open('http://www.your-site.com/mt/mt.cgi?__mode=view&_type=entry&blog_id=1&qp=1&text='+EscapeEUCJP(str),null))}},100);})();
  3. あとはブログ記事で言及したいページをブラウザに表示させて、ブックマークをクリックするだけ。

これで大体はうまくいくようになると思う。取り敢えず自分の環境だと Firefox と Opera では意図した通りに動作している。IE だとデフォルトの設定ではポップアップ・ブロックに引っかかるのと、選択した文字列が長い場合に URL が途中で切られてしまうという問題が発生する。しかしこれはスクリプトではなくブラウザの実装の問題なので、私としてはこれ以上は追求しない(どうせ自分では使ってないし…)。なお、Shift JIS の場合は EscapeEUCJP() の代わりに EscapeSJIS() を使えばうまくいくのではないかと思う(ただし未検証)。


ブックマークレットのスクリプトはとても見づらいので、改行とインデントを適宜ほどこして行番号を付したものを以下に表示しておく。

 1:javascript: (
 2:  function () {
 3:    scr=document.createElement('script');
 4:    scr.setAttribute('type','text/javascript'); scr.setAttribute('src','http://www.your-site.com/ecl.js');
 5:    document.getElementsByTagName('body')[0].appendChild(scr);
 6:    id=window.setInterval (
 7:      function () {
 8:        if (JCT8836) {
 9:          window.clearInterval(id);
10:          d=document;w=window;t='';url=d.location.href.replace(/#.*$/,'');str='';
11:          if (d.selection) t=d.selection.createRange().text; else { if (d.getSelection) t=d.getSelection(); else { if (w.getSelection) t=w.getSelection(); } };
12:          if (t.match(/\n|\r/)) str='<blockquote cite="'+url+'">\n  <p>'+t.replace(/[\n\r]+/g,'</p>\n  <p>')+'</p>\n  <cite>'+d.title.link(url)+'</cite>\n</blockquote>';
13:          else { if (t) str='<q cite="'+url+'">'+t+'</q>('+d.title.link(url)+')';
14:            else { str=d.title.link(url); }
15:          };
16:          void ( w.open('http://www.your-site.com/mt/mt.cgi?__mode=view&_type=entry&blog_id=1&qp=1&text='+EscapeEUCJP(str), null) )
17:        }   // if (JCT8836)
18:      },    // function
19:      100
20:    );      // setInterval
21:  }
22:)();

私も見よう見まねでやってみただけなのでちゃんとわかっているわけではないのだが、簡単に解説してみると、まず3-5行目で script 要素を生成し、ライブラリ ecl.js を読み込んでいる。この読み込みが完了しないうちに次の作業を開始してしまうので、このまま普通に window.open(...EscapeEUCJP(...)...) とやってもうまくいかない。そこで ecl.js の最後に定義されているオブジェクト JCT8836 が存在しているかどうかを100ミリ秒ごとに検証し(6,8,19)、成功したらこのループを解除し(9)、記事本文に挿入すべき文字列を整形し(10-15)、それを EscapeEUCJP() で EUC-JP に変換して MT に送信する(16)、という手順で行っている。

なお、ブログ記事本文にあらかじめ入力される文章は、MT が自動生成するブックマークレットのものがあまりにあんまりなので(これについては開発者のセンスを疑ってしまう)自分なりに工夫して手を加えてみた。具体的にいうと選択文字列に改行が含まれる場合は <blockquote> タグで囲い(12)、そうでない場合は <q> タグで(13)、空の場合はページのタイトルからのリンクだけを生成する(14)、という風にしてみた。よそ様のサイトのページ・タイトルやコンテンツの一部を自分のブログのエントリーのタイトルに使用するというのはちょっとまともとは思えないので、そこの部分は空にしてある。このあたりも好みに応じて変えて使ってみるといいだろう。


自分でウェブサイトを運営するようになって数年が経ち、(X)HTML と CSS についてはほぼわかってきた(つもりになっている)のだが、JavaScript には未だによくなじめないでいる。セミコロンで区切って並べているのに先に書いたコマンドの実行が完了しないうちに次の作業を開始してしまう、というのは UNIX のシェルに慣れた身にはかなり衝撃的だった。まあそれでもこれまでは document.write() みたいな関数しか使いこなせていなかったのが、今回の作業を通じていろいろなことに慣れることができたのは収穫だった。

本当はこんなことにかまけている暇があるならこのところ放置気味になっているメインのブログをどうにかしろよ、という話ではあるんだけど…。


追記: 10月5日21時00分

コードを一部修正。

コメントする

ウェブページ

このブログ記事について

このページは、sergeiが2009年10月 3日 01:03に書いたブログ記事です。

ひとつ前のブログ記事は「MTOS に移行」です。

次のブログ記事は「MT4 月別アーカイブリストの年別表示: ダイナミック対応版」です。

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

OpenID対応しています OpenIDについて
Powered by Movable Type 4.38