WordPressのビジュアルエディタであるTinyMCEで自動行頭一字下げを実現したのでご報告(?)です。要はこういうことです。
自動行頭一字下げとは?
「段落一字下げ」とかいろんな言い方がありますが、「段落の一番最初を一文字分空白にする」というアレですね。ブログでは段落(pタグ)の前後にマージンがつくことが多いのですが、日本語の段落では特に前後一行あけなどせず、「段落の開始時点で一字下げる」というのが通常のルールです。
MS Wordなんかにはこの機能があって、改行するとその時点で次の行からは一字下げになったりします。
行頭一字下げの機能がないとなにが問題か
破滅派に投稿される作品はWordPressの管理画面から投稿するというより、なんらかのソフトを使って作成したテキスト(ないしリッチテキスト)をコピペするというパターンが多いようです。
で、特にWordの場合は自動行頭一字下げが変になることが多いですね。小説などを書いていると「鉤括弧ではじまる行は一字下げをしない」というルールを遵守することが多いのですが、次のようなケースで自動行頭一字下げが壊れます。
- 地の文を書く(この行は一字下げ)
- 「そして、会話を書く」(この行は自動一字下げされてしまったので、BSキーなどで一字下げを解除)
- そして、この行は一字下げじゃなくなる
Wordは一度一字下げが解除されるとその後も自動一字下げが解除されたままなので、それ以降、全角スペースを入れていくことになります。次の日になると、保存・起動をした結果かどうかわかりませんが、再び自動一字下げが有効になっていたりします。結果として、何日もかけて小説を書いたりすると、一字下げが自動と手動の入り混じった変なテキストデータが出来上がります。
自動行頭一字下げを実現するには?
さて、管理画面から入稿したデータを表示するテーマ側で自動行頭一字下げを実現するのはそれほど難しくありません。こんなCSSを用意します。
.indent{ text-indent: 1em; }
indent
というクラスがついた要素は1文字インデントするということですね。で、Javascriptを利用して、該当する要素すべてにindent
というクラスをつけてまわります。
jQuery(document).ready(function($){ // 投稿本文のpタグを全部取得 $('.post-content p').each(function(i, p){ if( ! /^[ 【】《〔〝『「(”"'’\(\)]/.test($(p).text()) ){ // 正規表現で一字下げしない文字から始まっていなかったら // インデント用のクラスを付与 $(p).addClass('indent'); } }); });
これを行うことで、「全角スペースがあろうがなかろうが行頭一字下げ」という状況が実現できます。
ところがどっこい、投稿編集画面で同じような機能を提供するために同様のアプローチを取ることはできません。いままさに編集している画面で内容に応じてクラスを付与する、つまり、いままさに編集しているDOMをJSで勝手にいじるというのはあまりよくないアプローチだからです。
WordPressにはeditor-styleという機能があり、ビジュアルエディタの見栄えをある程度コントロールできるのですが、自動行頭一字下げはCSSだけでは実現できない(foo:contains()
はない)のです。
では、どうしたらよいでしょう?
TinyMCEのAPIを使う
さて、ビジュアルエディタはiframeとtextareaを交互に通信させるもので、WordPressのHTMLエディタというのはようするにtextareaで、ビジュアルエディタというのはbody以下がcontentEditableなiframeです。
それではどうすればよいかというと、ビジュアルエディタが更新されるにつれ、iframeの中のHTMLにstyleタグを書いていけばいいんですね。戦略としてはこうなります。
- TinyMCEのプラグインを登録する
- プラグインにビジュアルエディタの変更イベントを監視させる
- 変更があるたび、pタグを全部調査し、それが行頭一字下げの必要なテキストから成り立っているかを調べる
- 該当する行のインデックスを保存し、その全てに対してCSSを書く ex.
body p:nth-child(7){ text-indent: 1em; }
- styleタグを生成し、それをheadに突っ込む
こうすることで、「編集中のDOMを汚染しないで自動行頭一字下げする」という機能が実現できます。
で、これをどうやるかというと、ちょっとコードを書くのが面倒くさいので該当するコミットへのリンクを貼って終わりにします。ほんとうにありがとうございました。
[429] [429] Client error: `POST https://webservices.amazon.co.jp/paapi5/getitems` resulted in a `429 Too Many Requests` response: {"__type":"com.amazon.paapi5#TooManyRequestsException","Errors":[{"Code":"TooManyRequests","Message":"The request was de (truncated...)