右矢印キーを押すと左にカーソルがうつる不可思議なテキストボックスについて


前の会社での話。

実は、前の会社を辞めてからも9月は特別に週一回行っていまして、自分がある程度関わったプログラムのバグ修正なんかをしていました(ほとんど、自分が関わったところではないところに時間を使いましたが)。

そんな中、昨年退職した上司が作成したあるウェブページのテキストボックスが変な挙動をしていました。

そのテキストボックスには、数値が入っていて、右寄せになっていました。その時は特別深く考えたわけではないのですが、CSSのtext-alignでrightを指定しているんだろうなとは思いました。

それはいいのですが、どうも入力するとおかしなことになります。

IEだと右矢印キーを押すと左にカーソルが移動し、左矢印キーを押すと右にカーソルが移動します。よくわからないけど、IEのバグかなと思って試しにChromeで見てみると、なんとChromeでは一番右にカーソルをうつして入力すると左側に文字が追加され、逆に一番左にカーソルをうつして入力すると右側に文字が追加されます。

初めての減少に思わずポカンとしてしまったのですが、多分、keydownでイベントを発生させていて何かやらかしているのだろうと思い調べてみました。すると、予想通り、数値のみしか入力させない記述がしてありました(参考:HTMLのテキストボックスを、できるかぎり半角数値のキー入力のみにする | while(isプログラマ))。

というわけでいろいろ変更してみたのですが、全く変化がありません。そして、試しにkeydownのイベントを無くしてみましたが、全く変化がありませんでした。正直、わけが分かりませんでした。

とりあえず、一から考え直そうと思って開発者ツールで対象のテキストボックスを選択し、右側のサイドバーを見たところ、あると思ったものが無いことに気づきました。そう、『text-align:right』の記述がありませんでした。スクロールバーを上から下まで移動させて見てみたのですが、その記述がみあたりません。「右寄せになってるのになぜ?」もはやパニックに近い状態の自分でしたが、ふと見られない記述がありました。

『direction:rtl』

なんじゃこりゃ? と思って調べてみると、文章の記述方向の設定をしている記述ということが分かりました(参考:direction – CSS | MDN)。rtl は右から左……。まさか……。

この記述を無くしたら、カーソルが想定通りに動きました(もちろん、これだと左寄せになってしまうので、『text-align:right』を追加しておきました)。

とりあえず、同じようなテキストボックスを下記においておきます。valueの値は12345としています。こうすれば、『54321』と表示されるような気がしなくもないんですが、『12345』と表示されています。

というわけで、もし、矢印キーを押したら逆方向にカーソルが移動する場合は、この記述がないか疑ってください。そんなこと、滅多にないと思いますが……。

なお、「テキストボックスに『direction:rtl』の指定があればカーソルの動きがおかしくなる。ということを言いたいだけだろうに、前置きが長すぎ! そんなんだからブログ続かないんだろ!」なんてツッコミは受け付けておりません。むしろ、こう書いたことがセルフツッコミです。

独自PHPにWordPressの管理バーを表示する方法


気づいたら6月は更新しないまま時間がすぎていきました。何か書きたいことがあったような気もするし、そんなに忙しかったわけでもなかった気がするんだけどなぁ……。他にやりたいことがありまして……。

今回は久しぶりにWordPressの話。WordPress以外で作ったページに、WordPressの管理バーを表示する方法について。そんな状況がはたしてどれだけあるんだとは言われそうですが、そういう業務があったので自分用にメモ。

まず調べたのが、WordPressで作ったページ以外にWordPressの機能を使う方法。これはすぐに分かりました。requireでWordPressのwp-blog-header.phpを読みこめばいいとのこと。例えば、WordPressのトップディレクトリにtestディレクトリを作成して、その中に独自のPHPを入れる場合は下記のようになる。

参考:WordPressを導入したがWPではないページ(.php)にWPタグや新着一覧を表示 | Ken’s WEB

次に管理バーを表示する方法を調べました。これも調べたら情報はあちこちにありました。どうやら、headタグ内に『<?php wp_head(); ?>』、bodyの閉じタグ直前に『<?php wp_footer(); ?>』を記述すればいいようです。
参考:WordPressの管理バーを表示させるためのおまじない二つ★ | oki2a24

これで表示できる! と思ったら表示されません。HTMLのコードを確認しても管理バーの記述がないので、CSSで非表示になっているわけでもないようです。ただし、body_class()で記述された中には、”admin-bar”とあります。is_admin_bar_showingという関数があるので試してみたところ、表示されてないのにtrueが返ってきました(参考:関数リファレンス/is admin bar showing – WordPress Codex 日本語版)。

ここからは根気です。管理バーを表示するコードを探して、どこから呼び出しているのかを探していきます。そうすると、『do_action( ‘admin_init’ );』を呼ぶ必要があるようだ、ということが分かりました。なぜ独自PHPではその箇所を通ってないのかまでは分からなかったのですが、コードに『do_action( ‘admin_init’ );』を追加してなんとか管理バーを表示することができました。。(2015/07/08修正)『do_action( ‘admin_init’ );』だと、余計な関数まで動いてしまうことが分かりました。実際に管理バーを表示するだけなら、『_wp_admin_bar_init();』を呼ぶだけでよさそうです。

以下、最低限のサンプルコード

ここで、『status_header( 200 );』を呼んでいる理由ですが、これがなかったらなぜかHTTPステータスが404となりました(一見、ちゃんと表示しているように見えるのですが、HTTPステータスを確認すると404でした)。どこが原因で404となっているのかは分からなかったのですが、とりあえずstatus_header関数を呼ぶことでHTTPステータスを200にすることができました。ただし、bodyタグにerror404というクラスが残ったままなので、根本的な解決にはなっていないかもしれません。

画像の比率を保ったまま枠内に収めて縦横中央表示するCSS(IE8対応)


divタグなどの枠内に画像を入れる時、縦横中央表示にして、かつ、枠のサイズより大きければ枠に収まるように画像の比率は変えずに小さくしたいということがあると思います。というより、先日自分はそういう事態に遭遇しました。

まず、サイズの比率を保ったまま、枠内に収める方法ですが、いろいろ試行錯誤した結果、下記のようにするとうまくいくことが分かりました。

widthとheightは普通、デフォルトがautoなので指定しなくていい場合が多いのですが、autoじゃないと動かないため指定しています。

上記の記述だと、枠(この場合、imgタグの親要素)のサイズより大きければ、max-widthとmax-heightの指定により、それ以上のサイズを超えないようになるので、枠に収まってくれます。最初はてっきり、どちらも100%のサイズになってしまうのではないかと思ったのですが、どうやら大きい方にあわせて縮小されるようです。

次に、縦横中央表示の方法ですが、横は簡単です。親要素に『text-align:center』を指定してやればいいだけです。問題は、縦の中央表示。いろいろ調べてみると、:before擬似要素を使って下記のように書くと、縦横中央表示する方法があることが分かりました。

before擬似要素をinline-blockとし、縦方向の揃えをmiddleとしています。同じく画像のほうもmiddleとすることにより、どちらも縦中央表示になります。ただ、inline-blockにすると余計なスペースができてしまうので、そのスペースを無くすために、枠の要素にfont-size:0の指定をしました(参考:display: inline-block の隙間を詰める方法 | Soraxism)。

ちなみに、IE8には対応していませんが、画像をCSSのbackground-imageで指定し、background-sizeをcontainとすると、枠に収まるようになりますが、この場合、枠のサイズより小さければ画像が拡大して枠のサイズに合わせて表示するようになります(もちろん、そのほうがいいということもあると思います)。

なお、IE8対応しなくていいのであれば、フレックスボックスやtransformを使って縦中央表示できます。

フレックスボックス利用

transform利用

下記にサンプルリンクを載せておきます。background-size:containを使った結果、フレックスボックスを使った結果、transformを使った結果も載せています
フレームサイズ:100×150、画像サイズ:175×200
フレームサイズ:100×150、画像サイズ:200×175
フレームサイズ:175×200、画像サイズ:100×150
フレームサイズ:175×200、画像サイズ:150×100
サイズランダム

jQuery Deferredで作るオリジナル確認ダイアログ


ある意味、前回(オリジナルのダイアログを閉じた時に、元の要素にフォーカスを戻す方法 | while(isプログラマ))のつづき。今回は確認ダイアログ版。

ただ、今回のエントリーはダイアログを作ることではなく、jQuery Deferredの勉強のメモです。最近になってjQuery Deferredについて調べてみました。まだまだ分かっていないことは多いのですが、試しにjQuery Deferredを使った確認ダイアログを作成することにしました。

今回作るのは、標準のconfirmメソッドを使うと下記のようなものです。

つまり、確認ダイアログを表示して、『OK』を押せばYahoo!JAPANへ、『キャンセル』を押せばGoogleへ飛ぶという処理です(キャンセルなら何もしないのが普通じゃないかと思われそうですが、分かりやすいようにどちらも何かしらの動作をするようにします)。

ただ、これだとダイアログのレイアウトを変更できないので、独自のダイアログを作成することに。ついでに、上記のYahoo!やGoogleに飛ぶ処理をjQuery Deferredで実現することにしました。試しに書いてみたコードが下記です。

サンプル:ダイアログのテスト

ようは、OKボタンを押した時にresolveメソッドを呼び、doneメソッドの引数に入れた関数を呼ぶ。キャンセルボタンを押した時にrejectメソッドを呼び、failメソッドの引数に入れた関数を呼ぶという処理をしています。

このぐらいならjQuery Deferredを使う必要はないんですけどね。そもそもキャンセルボタンを押すことが何でreject(異常終了)なのかと突っ込まれそうです。多分、この例はjQuery Deferredを使う例としては間違っていると思います。

ところで、jQuery Deferredを調べていると、Deferredオブジェクトの取得に『new $.Deferred』としているページが多々ありました。なので、Deferredオブジェクトかどうかの判定には『obj instanceof $.Deferred』とすればいいだろうと思ったのですが、結果はfalseになってしまいました。なぜだろう? と思って、jQueryのコードを見てみると、Deferredメソッド内で作成したオブジェクトをreturnしており、Deferred自身のインスタンスを生成しているわけではないようです。jQueryの公式ページのサンプルコードでは、Deferredオブジェクトの取得にnewをつけていません(deferred.promise() | jQuery API Documentation)。やたら、newを付けている解説ページが多いのだけど、なぜそうなったのだろうか・・・。

ところで、今回作成したopenConfirmメソッドでは、promiseメソッドで取得したpromiseオブジェクトを返していますが、ここはDeferredオブジェクトをそのまま返しても結果は変わりません。promiseオブジェクトとの違いとしては、promiseオブジェクトにはresolveやrejectがありません。それだけの違いですが、一般的にpromiseオブジェクトを返すようにするそうです。この辺りは、書きページの『deferred図解』の『なぜわざわざpromiseを渡すのか』を参考にしてください。
参考:jQuery deferredの使い方 – deferredの基本 | CodeGrid

jQuery Deferredはいろいろ応用ができそうな機能です。複数のDeferredオブジェクトを使ってwhenメソッドを使うとか。ただ、自分自身よく分かってないところもあるので、もう少し勉強しようと思います。

オリジナルのダイアログを閉じた時に、元の要素にフォーカスを戻す方法


先日、コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーションという本を読みました。Webアクセシビリティについて書かれた実践的な本で、WAI-ARIAについて全くと言っていいほど知らなかった自分には、もっと入門的な本も必要だと思いました(本の内容が難しいとうわけではありません。書いてあることは易しかったのですが、自分はこの本の想定読者のレベルに達してないというだけです)。ただ、この本を読んでもっとWebアクセシビリティを意識したサイトを作っていこうと思えたので、そういう意味では読んでよかったと思います。

さて、本を読み終わったらいつもブクログに本の感想というか批評というか日記というか、とにかくその本について思ったことを書くのですが、なんと今回はそのレビューページを、この本の編集の方に見てもらえたらしく、さらにレビューに書いた疑問を監訳者の方にまで見てもらえたようです(『コーディングWebアクセシビリティ – WAI-ARIAで実現するマルチデバイス環境のWebアプリケーション』のレビュー ヘイドン・ピカリング (amano225さん) – ブクログ)。たまにこうやって関係者からのコメントをもらえることがあるのですが、見られることを想定して書いてるわけではないので、嬉しくもありますが、どこか恥ずかしい気もちもあり、複雑なところです(さすがにオープンな場に書いている以上、見られたくないとは思っていません)。

ところで、自分が疑問に思ったのは本書の最後にほうに書いてあるダイアログについての記述です。ダイアログを閉じる時に、そのダイアログを開く前にフォーカスのあった要素にフォーカスを戻しましょうと書かれてあったのですが、それがあまりにも冗長のように思いました。本書には下記のように書いてありました。

ダイアログを開く時の処理

ダイアログを閉じる時の処理

つまり、開いた時にフォーカスがある要素のIDを取得し、なければその要素に’origin’というIDをつける(IDをつける処理は省略)。そして、閉じる時にそのIDから要素を選択して、その要素をフォーカスするという記述です。

なんだか冗長です。自分は下記のようにしたほうがいいのではないかとブクログに書いた次第です。

ダイアログを開く時の処理

ダイアログを閉じる時の処理

編集の方によると、確かにこちらのほうがいいだろうとのことでした。自分の意見が認められたみたいでうれしいです(意見したつもりはないのですが)。

さて、ここまでは余談です。今回、実際に作ってみることにしました。まず、HTML内にダイアログ用の記述として下記のような記述を追加します。

.dialog__layerはレイヤー用ですが、#TestDialogの背景をrgbaで指定しても同じことになるので、必要ないかもしれません。

CSSは下記のようにしました。クラスの命名は最近話題のBEMっぽくしてみました(参考:BEMを参考にしたCSS設計 – Qiita)。

次にJavaScriptの記述です。

何をしているかというと、ダイアログを開いた時にdocument.activeElementで現在フォーカスしている要素を取得しています(参考:JavaScriptでフォーカスのあたっている要素を取得する「document.activeElement」: 小粋空間)。そして、その要素をjQueryのdataメソッドでダイアログ用のタグに”back-focus”というキーで紐付け、ダイアログ内のボタンをおした時にその要素を取得してフォーカスを元に戻すという処理を行っています。

試しに、テキストボックス内に郵便番号を入力してエンターキーを押すと、書式が正しくなければ”正しい書式で入力してください”、正しければ”OKです”と表示するサンプルを作成してみました。
実行サンプル:ダイアログのテスト

エンターキーを押したらダイアログがでて、そのままエンターキーを押したらフォーカスが元に戻るのが分かると思います。注意点として、エンターキーをおした時にダイアログを表示する場合は、下記のようにe.preventDefault()がないとすぐに閉じてしまうようです。

特にこだわりがなければ、alertメソッドを使えばいいだけの話なんですけどね。ダイアログのレイアウトも変更したいという場合に。

ところで、document.activeElementという指定はつい最近知ったのですが、調べてみるとIE4の時からあった指定方法だそうです(document.activeElement – Web API インターフェイス | MDN)。昔からある手法ななのに、初めて知ることがあると、自分はまだまだ全然JavaScriptを分かってないんだなと思います。