飴屋

2016年の日記

2016/12/28

Wordpressで管理するサイトの制作をよくお引き受けするのですが、タイトルや本文以外にお客さんが独自に入力したい項目を更新画面に追加する際、よくカスタムフィールドテンプレートというプラグインを導入させてもらってもらす。数ある似たようなプラグインの中からこれを選択した理由は、ググるとよくみかける、という理由なのですが、たくさんの人に使われているだけあって、機能が充実しています。

ただ、ちょっとバグっぽい挙動が現在の最新バージョンに残っていて、お客さんから何とかならないかと相談されました。

相談1

フィールドセット(特定の入力欄のセット)をmultiple指定(セットの追加・削除ができるように)した際に、セットの中の複数行入力欄(textarea)にtinyMCE(リッチエディタな拡張)をつけると、フィールドセットを「追加」した際に追加されたtextareaのtinyMCEが操作を受け付けなくなる。

どうも調べた感じだと「追加」されるフィールドセットは一つ前のフィールドセットを複製し、入力値をリセットした上で下に追加されているっぽかったです。その複製の際にtinyMCE化されているtextareaがそのまま複製され、その上さらにtinyMCE化を重ねて行うおうとしているのが問題になっているようでした。

そこで「追加」の際にtinyMCE化を一度解除して、追加後に再度tinyMCE化を行うことでなんとなく誤魔化せるようになりました。具体的には「textarea_tmce_ids」というローカル変数にtextareaのidが集められているところで「tinyMCE.execCommand('mceRemoveEditor')」を呼び出すように変えたのと、「textarea_tmce_ids」で集めたidに対してtinyMCE化している箇所があるのでそれが終わった後に同様にそのidに対して「switchMode(id)」を呼び出してあげました。

相談2

tinyMCE化されたtextareaの内容を編集してから、別の入力欄でメディアピッカーを使って画像を選択すると先に編集したtextareaの編集内容がリセットされている

これはメディアピッカーで画像を選択した際の挙動が

  1. 選択した内容を入力欄(input[type~"hidden"])に反映させる
  2. カスタムフィールドテンプレートの入力欄の内容をサーバーに送って、更新する
  3. 更新された内容を読み込みなおして入力欄を更新する

    という流れになっているのと関係がありそうでした。2番と3番の挙動はajax的にサーバーと通信をして行われるので、ページの遷移は伴いません。

ここでtinyMCEの挙動について説明をしておくと、textareaをtinyMCE化した場合、textareaは非表示となり、DOM的にtextareaの直前にリッチエディタが作成されます。リッチエディタ上で編集された情報は随時非表示のtextareaに反映されるというわけではなく、どうもフォームのsubmitをきっかけに自動的に内容が同期されるっぽいです。

メディアピッカーが画像を選択し終わったあとの処理はajax的に処理をされるので、カスタムフィールドテンプレートの入力欄の中でtinyMCE化されたtextareaだけは編集内容が同期される前の状態でサーバーに送信されてしまうというのが、問題の原因だったと思われます。

メディアピッカーで画像を選択した際に「cft_use_this」という関数が呼び出されるので、前述の2番の挙動の前に何かtextareaに編集内容を同期する方法がないかと考えていたのですが、時間がなかったので

win.jQuery("#cft textarea:hidden").each(function(){
switchMode(win.jQuery(this).attr("id"));
switchMode(win.jQuery(this).attr("id"));
});

↑こんな感じのコードを追加してお茶を濁しました。tinyMCE化を一度オフにしてからオンにしなおすと同期されるというのを利用しました。多分、もっといい方法があると思いますが、tinyMCEのAPIリファレンスを眺めていてもすぐに見つけることができなかったのでした。

早くプラグインの開発者の人が直してくれるといいなと思っています。
もしかしたらWordpress(の同梱tinyMCE)とカスタムフィールドテンプレートの相性が悪いだけなのかもしれません。そうだとしたら、導入タイミングがよくなかったという感じですね。

2016/9/12

WEBサイトを彩るパーツにSVGが使われることも増えてきた昨今に出くわした問題のメモです。とあるレスポンシブWEBデザインなページの内のとあるボタンをSVGにし、PCのブラウザでボタンをクリックできることを確認し、Android端末のブラウザ(Chrome)でも同様にボタンがクリックでき、問題なく動作することを確認し、続いてiOS端末のブラウザ(Safari)で同様の確認作業を行った際、ボタンをタップしても想定した動作が起こりませんでした。
タップ時にiOSでだけ何かしらのJavaScriptのバグが発生しているのかと思い、タップ時にalertを出すように処理を変更し、再度タップしてもうんともすんともいいませんでした。

どうやらiOSのSafariでは<svg>要素でonclickイベントが発火しないっぽいので、<a>要素ででも囲ってみようかと思いましたが、試しに

svg {cursor:pointer;}

↑このように<svg>要素に対して、マウスカーソルを指型にするCSSをあててみたところ、<svg>要素のボタンもonclickを発火するようになりました。「なんでだよ!?」と内心思いましたが、動いたのでとりあえずよしとしたのでした。

2016/8/22

不可解な現象が起こったとの連絡をお客さんからもらったので調査したときのお話です。いわゆるお問い合わせフォームを設置したら、お問い合わせ完了時の通知メールが二通届き、しかも片方は入力内容が空になっているとのことでした。

お客さん内製のPHPのフォームだったのですが、PHPの記述には問題がなく、サーバー側の問題かメールサーバーかスパムフィルターの問題を疑ったのですが、どうも関係なさそうでした。

悩んだ末、たどり着いた問題の原因は、完了ページに二度アクセスが飛んでいるということでした。

<link rel="shortcut icon" href="" />

お客さんがページのアイコンの設定を空にしていたのを発見しました。アイコン画像のファイルはユーザの操作とは関係なくブラウザが自動的に取得するようになっていることが多いと思います。その際href属性が空文字だと、リンクは現在表示中のURLに向かっていることになるので、完了画面を表示すると同時に自身へのアクセスがもう一度発生するということになります。その二度目のアクセスが入力内容が空っぽの不要なメールを生んでいたというのが原因でした。未検証ですが、Firefoxで起こるという情報がありました。

これが<img src="" />や<script src="" />では同じことが起こらないのは属性名の違いと関係するのでしょうかね。

2016/4/20

Windowsのアップデートに伴って再起動を促されたので、迷わず再起動したところPCが起動しなくなったので情報を集めながらなんとかしたときのメモ。逝ってしまったPCの中には一月くらい集中して作成していたプログラム等があり、バックアップが済んでいないファイルもいくつかあり、その中にはもう一度作り直すには相当根性が必要という状況でした。PC自体が復活するに越したことはないですが、そのファイルをサルベージするのを最優先事項と定めました。

対象はASUSのノートパソコン、OSはWindows 10、SSDのCドライブがあるだけで光学ドライブはなし。

PCは再起動すると、Windowsが自力で状態回復を始めようとしました。がどうしても途中で処理が止まって沈黙します。ソフトウェア的な問題だったらいいですが、ハードウェアが絡んでいそうな予感がします。再度再起動すると、PCはリカバリモードで立ち上がりました。いくつか選択肢が出ますが、とりあえずそのまま「続行(Windows 10を起動する)」を選択してみます。が、起動はやはり失敗に終わります。もう一度再起動するとまたWindowsが自力回復を始めますがストップし、次はリカバリモードで立ち上がります。今度は、メニューから「トラブルシューティング」を選びます。「PCのリフレッシュ」「PCを初期状態に戻す」「詳細オプション」というメニューが出てきますが、まだ初期状態に戻して大事なファイルを失うわけにはいかないのでリフレッシュを試みます。しかし、それも特に状況を変化させませんでした。

そして悪戦苦闘しているうちにとうとうPCはブルースクリーンを出してリカバリモードにすらならなくなりました。電源を切ってしばらく待ってから起動したらリカバリモードになることもありましたが、基本的に具合の悪そうな顔文字「:(」とエラーメッセージが表示されます。エラーメッセージは

page_fault_in_nonpage_area (ntfs.sys)

↑こんな感じでした。pageとついてるのでメモリ関連のエラーでしょうか。ntfsと書いてあるのでハードディスクかファイルシステムの問題でしょうか?とにかく原因がまだ特定できません。別のWindowsマシンで状態を回復させるディスクをUSBメモリに作ってみて、そこから起動を試みましたが、途中から同じエラーメッセージが出てだめでした。

いよいよできることが少なくなってきましたが、USBメモリを使って起動するというところから着想を得て、特に詳しくもないLINUXをUSBメモリから起動してみることにしました。確かそんなことができたと思って調べてみると、unetbootinというソフトが紹介されてました。詳しくは知りませんが、LINUXのOSイメージ(isoファイル)をブートしてくれるもののようです。デストリビューションをいろいろ選べるようで、Ubuntuとか使ってみるかと思ったのですが、いろいろやってうまくいかなかったので最終的にちょっとかじったCentOSにしました。デスクトップ版(GUI)とテキスト版(CUI)とがありましたが、無線LANでネットワークにつなぐのが楽だったのでGUI版を使いました。この時点でちゃんとわかっていなかったのですが、LiveCDとかいうものが使われているとかなんとかで、OSを再起動する度に設定が失われるので激しく戸惑いました。それからキーボードの配列が初期状態でUS配列だったのでこれにもいろいろ惑わされました。いろいろ設定をいじくり回してなかなか勉強になりましたが、目的になかなか届きません。

それでやっとSSDをマウントする段になって、ファイルシステムが原因でマウントできないとのメッセージが出ました。CentOSでは標準ではNTFSには対応していないとのことなので、ntfs-3gをインストールしました。このパッケージのあるリポジトリがまたCentOS6では標準的には読み込まれないとのことなので、その辺の設定も必要とのことでした。Microsoft育ちなので、デバイスの扱いやマウントするという文化に翻弄されながらSSDのデバイスとリンクするファイルを見つけてなんとかマウントできそうなところまできました。しかし、マウントを拒否されるのでした。やはりファイルシステムが一部壊れているのかはたまたブートに関する情報が邪魔しているのか、よくわかりませんが、「ntfsfix」というコマンドで解決できるかもしれないとのこと。これは「ntfsprogs」というパッケージにあるそうなのでインストールしてみます。そして実行前に注意する点があるそうで、対象ドライブのブート情報をぶっ壊す可能性があり、元のようには起動できなくなるかもしれないとのことでした。第一目的はファイルの救出ですから、それも止む無しと「ntfsfix」を実行します。破損したクラスタがどうのこうのという情報がズラーッと並んでいます・・・。

結果、対象のSSDに無事マウントでき、求めていたファイルも壊れずに残っていました。万歳!
さて次にこのファイルをどうやって拾い上げるかが問題になりました。なんかこのままCentOSのデスクトップに救い上げても、LiveCDのせいなのかなんなのか揮発してしまいそうで怖かったので、もっとちゃんとしたところに保存しておきたいなと思いました。そこでうちのルーターにつながっているNASが一番手っ取り早いのではないかと思い、マウントを試みます。うちのNASはLANDISKなのでSAMBAとCIFSを扱うモジュールをインストールするとマウントできるようになりました。

ファイルの復旧が完了し、一息ついたところで、このPCをよみがえらせることにも挑戦しようと思いました。とりあえずそのまま再起動してみると、SSDのブート情報は本当に吹っ飛んでいたのか、「ブートできないのでCtrl+Alt+Delで再起動しろ」的なメッセージが黒い画面に表示されました。現在、Windows10のインストールメディアをさっきのUSBメモリに作り、再インストールを試しているところですが、インストールが途中で止まるという状況です。5年近く前に買ったノートなので、開発機としては少し使いにくくなってきたところではありますが、いろいろ気に入っていたんですよね。どうしようか微妙に悩まれます。

2016/4/6

Wordpressで構築されたサイトをSSL化したときに起きたお話。WordpressのサイトURLをhttpsで始まるようにすれば大概のプラグインは問題なく変更後のURLが使われるようになりますが、投稿済みの記事の中で絶対URLでリンクが張られた画像などのパスは、そのままデータベース上に残るのでSearch-Regexのようなプラグインを使って置換してあげる必要があります。そして、テーマのファイル中の「http」を「https」に置換したら作業が完了・・・と思っていましたが、まだ一部にmixed content(混在コンテンツ)がみられるとのことでした。

原因はSimple Local Avatars プラグインで記事投稿者の画像を扱っていたのですが、そのパスにhttpが残っていたとのこと。Search-Regexでは検出されないようなので、以下のような簡単なコードで一括変換しました。

$users = get_users( array('orderby'=>ID,'order'=>ASC) );
foreach ($users as $user) {
$av = get_user_meta( $user->ID, 'simple_local_avatar', true );
$av = str_replace('http:','https:',$av);
update_user_meta($user->ID, 'simple_local_avatar',$av);
print_r($av);
}

とりあえずうまくいったようです。他にも応用できそうなのでメモ。

2016/3/1

Github上のお客さんのリポジトリにあるデータを使って、アレコレやろうというお仕事で、git cloneでつまづきました。

現象

Cloning into 'repo-name'...

↑cloneコマンドを叩くとこんな表示が出てから何も進展しない状態になりました。ローカルには「repo-name」フォルダができ、その直下には「.git」フォルダもでき、設定情報も記録されている模様。でも、なぜかファイルのクローニングが始まっている気配がありません。

原因

gitのことをインターネットで調べると、いつも「Windows環境」という条件がネックで調査が進まないのですが、それにしても情報が見つかりませんでした。なので、思いつく限りのことを試した結果、

git clone https://github.com/okyakusan_name/repo-name.git

↑このcloneコマンドでは情報が不十分だったようです。そもそも、お客さんの用意したリポジトリはプライベートリポジトリなのでアクセスが制限されているので、アクセス権限をもっているアカウントであることを伝える必要があったようです。公開鍵の登録作業やsshに関する設定はできていて、

ssh -T git@github.com

↑これが開通したので、それでアカウント認証に関する情報は揃っていたのだと勝手に思っていました。

とりあえずの解決策

git clone https://username:password@github.com/okyakusan_name/repo-name.git

↑このようにGithubのユーザ名とパスワードをくっつけたらcloneが無事完了しました。今回、cloneが停止したように見えたのは、多分裏で、usernameかpasswordの入力待ち状態が続いていただけだと思われます。

.git/config ファイルにユーザー名とパスワードごとURLが記録されているので、次にgitコマンドを入力する分には何も問題は起こりませんでした。ただ、URLに直接パスワードまで載っているのはよろしいはずがないので、多分 ~/.ssh/config ファイルあたりに何か記入しておけば最初のコマンドでも大丈夫だったのではないかと推測します。(未検証)Windowsユーザーは、~(home)ディレクトリになじみがないので、いろいろ過去にもつまづいたなぁ・・・。

2016/1/20

HTMLのコーディングのお仕事をしていると「古いIEへの対応」という呪縛のようなものがありましたが、今はそれも昔の話。随分と作業をしやすくなったものですが、また新たな悩みの種もあります。スマホのブラウザ各種、タブレットのブラウザ、Macのブラウザ、Mac上で動いているWindowsのブラウザ・・・この辺への対応を求められることが多くなってきています。スマホの特定機種のブラウザがメーカーによって独自の調整を経ている場合、HTMLのコーディングだけではどうにもならない差が生まれることもあり、まだまだ茨の道が敷かれているようです。

今回はiOSのSafariのhover擬似要素のお話です。hover擬似要素は元々、要素がマウスオーバーされたときの挙動を記述するためのものかと思いますが、マウスがないスマホやタブレット端末においてはその扱いに揺れがみられます。Androidのブラウザは指でタッチするのを開始されるとhover状態になるようです。iOSのSafariの場合、調べてみるとiOSのバージョンアップとともにその挙動は細かい変化を遂げてきたようです。現状で、一度タップするとhover状態になり、要素がリンクの場合、hover状態でもう一度タップするとリンクが発火するような挙動を示しています。

今回、お仕事でPCサイトを作成していて、途中からiPadでもみられたらうれしいというリクエストをいただいたのですが、とあるリンクがhover時に見た目がグニャリと変化し、リンク先に飛んだ後にブラウザの履歴を「戻る」がなされたときに、iPadだと戻った先のページのさっきタップしたリンクがグニャリと変化したままで気持ちが悪いとのご意見をいただきました。どうやら、「戻る」ってもhover状態はキープされ続けるようで、別の要素をhoverさせるまでそれは解除されないようです。

ググった結果、「擬似要素hoverを使うのは諦めろ(JavaScriptで同様に実装しろ)」という先人の知恵が散見されたのですが、がっつりPC向けに作りこまれたこのページの場合、擬似要素hoverを捨てるとその対応に工数がガッツリ持っていかれそうな塩梅でした。これはどうにか小手先で対処したいという欲求が高まります。

フォーカスを外す、他の要素のクリックイベントを発火する・・・などいくつか小手先の対処法を考えて試してみましたが、戻った先のリンク先はグニャリとしたままでした。他の要素がhover状態になるまで、頑なにhover状態を保ち続けるところから、内部的に「この要素は今hover状態」と要素毎に状態を管理するのではなく、window内の「今hover状態な要素」という情報が管理されていて、これを書き換えない限りずっとグニャリとしているのだろうなと予想はしましたが、書き換える有効な方法が思いつきませんでした。

最終的に今このグニャリとしている子は元に戻せないと判断し、一度DOM上からこの子を外して新しい子を同じ場所に配置することで戻ってもグニャッてない状態を作り出すことができました。

// jQueryを使用
// $('a:hover') <- hover状態にあるグニャリ要素
// その後ろに印代わりの要素を挿入しておきます

$('a:hover').after('<div id="tmpmarker" />');

// DocumentFragmentにグニャリ要素を移動させる

var tmp = $('<div />').append($('a:hover'));

// 印の要素の後ろにグニャリ要素を戻して、目印を消します

$('#tmpmarker').after(tmp.find('a')).remove();

これで要素はhover中と判断されなくなり、グニャッとしなくなりました。目的達成!この小手先技が不要になる未来を待っています。

開発日記

Last-Modified