anti scroll

ブラウザと小説の新しい関係を模索する

サムネールが画面に収まらない場合について

埋め込みサムネールを使う人が、モバイルとの兼用をどうするのかっていうのが課題だったわけですが。

今まではサイズの部分にレスポンシブな感じでパーセントを指定することをおすすめしてきたわけですが、よくよく考えたらもっと簡単な解決策がありました。

それは「画面に収まらない時はリンク(+表紙)を代わりに表示する」というものです。

小さい画面でサムネールを出しても仕方ないですし…

今後は例えばサムネール(800x600)をiphoneなどで閲覧した場合、サムネール部分が解像度に収まらないので、タイトルリンク(と、設定されていれば表紙)に置き換わって表示されます。

ただし、2014年8月25日以前のサムネールは、タイトルと表紙ではなく、URLのリンク(http://...みたいなリンク)として表示されてしまいます。

これが嫌な人は、新しいコードを取得して貼りつけ直してください。

backbone.touch.jsでモバイルデバイスの「クリック」を高速にする

クリックが遅い?

おそらく世間的には常識的な内容なんでしょうが、モバイル用フロントエンドの初学者には新鮮なことだったので書き残しておきます。

実はモバイル用のビューアーを書いていて、前から「なんかクリックが遅い?」と気になっていたのです。

ずっと「シミュレーター経由だからかなあ」とか思っていたんですが、なんとなく不安でモヤモヤしてました。

で、そんなときにたまたま、backbone.touch.jsというライブラリを見つけて「ああなるほど」と感心しました。

https://github.com/nervetattoo/backbone.touch

ここのドキュメントによると、タッチデバイスって、クリックイベントが300msぐらい遅れて発火するらしいのですね。

なので、backbone.touch.jsは、Backbone.View.prototype.delagateEventsを上書きして、clickを使って書かれたハンドラが「touchstart/touchend」を使ったハンドラに自動的に置き換わるようにしちゃおう、というライブラリなのだそうで。

じゃあどうやってtouchstart/touchendでクリックを判定するかというと、touchstartした座標を覚えておいて、touchendした位置がそこから殆どずれていなかったら「それってクリックだよね」っていう判定処理をしているみたいです。

クリックが遅れる理由

そもそもモバイルデバイスでクリックイベントが遅れる理由ですが、画面を触るという点について意味が被る「クリック」と「タッチ」を区別するためなんでしょう。

よくよく考えたら「そりゃそうだ」と合点しました。

スマホ自体を持っていないので、そういうイメージそのものを、これまで考えつかなかったです。

やっぱり一つぐらいタッチデバイスを持ってたほうがいいのかなあと、改めて思いました。

デフォルトのジェスチャー判定を抑止

ちなみにソースを覗いて気になったのは、touchendの発生時、対象がAタグとかBUTTONタグなら、デフォルトのtouchendイベントの発火を抑制してる箇所です。

これはおそらく、モバイルブラウザで表示されるAとかBUTTONタグには、デフォルトで同じような「クリックみなし」のジェスチャー判定が、すでにバインドされているからなんだと思います。

なので、ダブル発火を防ぐためにpreventDefaultしている、と。なるほど〜!

なんにせよ、backbone.jsを使ってクリックを扱うロジックを「click」で統一させたいなら、backbone.touch.jsを読み込むだけで勝手に置き換えてくれるのは便利です。

実際シミュレーター経由で試したら、ちゃんとクリックが高速反応してて感動しました。

モバイル用のビューアーで表示設定の変更ができるように

モバイル用のビューアーが、表示設定の変更に対応しました。

新しいビューアーはこういう見た目になっていますが、

f:id:convertical:20140822203708p:plain

左上のアイコンをクリックすると、表示設定の画面になります。

f:id:convertical:20140822203731p:plain

縦書き、横書きの切り替え、フォントサイズの変更、明朝ゴシックの切り替えなどが設定できます。

あとは内部的なことですが、今まではデスクトップ用のビューアーを無理やりモバイル用にしていたので、使わないコードが大量にロードされていました。

しかし今回モバイル用のビューアーを完全にリライトしたことで、全体のファイルサイズを約1/4まで圧縮できました。

これで初回ロードも少しは速くなるんじゃないかなと思います。

Google Analyticsの埋め込みに対応

Google Analyticsの埋め込みに対応しました。

アカウント管理の「プロフィール編集」から設定できます。

入力欄には、GoogleAnalyticsのプロパティID(UA-123456-89 みたいなやつのことです)を設定します。

設定すると、各小説ページヘのアクセス(自分自身のアクセスは除く)がGoogle Analyticsに送信されます。

チップリンクが作成できるように

tipというタグを使ってチップリンクが作成できるようになりました。

こんな感じで書くと…

新しい<tip title="パソコン">パーソナルコンピューターの略</tip>が欲しい。
新しい<tip title="テレビ" text-only="true">テレビジョンの略?なのか?</tip>も欲しい。
<tip title="スマホ" icon="exclamation-triangle">スマートフォンの略</tip>も欲しい。

こんなふうに表示されます。

f:id:convertical:20140813221543p:plain

本文にはタグの中身ではなく、title属性に指定された文字列がリンクとして表示されることに注意してください。

で、表示された「パソコン」というリンクをクリックすると、こういうダイアログが出ます。

f:id:convertical:20140813222057p:plain

リンク前のアイコンを消す場合は、text-only属性をtrueに、アイコンを変えたい場合は、icon属性にアイコン名を指定します。

この際、指定するアイコン名については「アイコンフォントを入れる」を参照してください。

この「チップ」機能は、まんま1998年に発売されたノベルゲーム「街」で使われていたものを真似たものです。

本文には表示させたくないけど、補足説明を付け加えたいときなんかは便利なんじゃないかなーと思います。

実際の動作が見たい方は、縦書き文庫のヘルプにて「チップリンクを作成する」を見てください。

月別のポイント統計が確認できるように

ページ送りログに加えて、月別のポイント統計が確認できるようになりました。

f:id:convertical:20140809132923p:plain

各月の上位30の作品別ポイント集計を出力します。

ちなみに青空文庫アカウントで今月のポイント統計を見たら、こんな感じでした。

f:id:convertical:20140809133407p:plain

jingoo v1.2.5 release

jingooのv1.2.5をリリースしました。

ひょんなことからjingoov1.2.4にバグ(割りとでかい)を見つけてしまい…緊急でリリースしました。

旧バージョンを使用中の方は、アップデートすることをおすすめします。

バグの詳細

具体的なバグは何かというと、オブジェクトをドットで展開する際に、対象が以下の様な入れ子のオブジェクトだったとき、evalが失敗して例外が投げられていたことです。

{{ user.image.filename }}

原因

原因はASTの評価処理で、ドットでプロパティにアクセスする評価式を、次のようなパターンマッチでのみ受け取っていたからでした。

| DotExpr(Ident(name), Ident(prop)) ->
  jg_obj_lookup_by_name env ctx name prop

オブジェクトのドット展開は左結合で、右にドットが2つ以上続く場合は左辺が再帰的にオブジェクトを返すはずですが、DotExprの評価式で左辺がIdentのみの評価しかしていなかったので、左辺がobjectを返すようなASTだったときにマッチするパターンがなく、SyntaxErrorがthrowされていたわけです。

今までこれに気づかなかったのは、単に入れ子のオブジェクトを扱っていなかったからなんですが、今回キャラクタ機能というのをリリースした際に、キャラクタオブジェクトの画像オブジェクト、という入れ子のオブジェクトを展開する必要があって、初めてバグに気づきました。

修正

対応自体は簡単で、パターンマッチのケースを一つ追加するだけで大丈夫でした。

| DotExpr(Ident(name), Ident(prop) ->
  jg_obj_lookup_by_name env ctx name prop

(** 左辺がオブジェクト *)
| DotExpr(left, Ident(prop)) ->
  jg_obj_lookup env ctx (eval_expr env ctx left) prop

おまけ

久しぶりのソースだったので「思い出せるかなあ」と憂鬱だったのですが、OCamlってコンパイラに型エラーで怒られているうちに、徐々に思い出すんですよね。

改めて型システムは偉大だなあ…などと思いました。

キャラクター登録と台詞記法をサポートしました

機能縦書き文庫に「キャラクター」が登録できるようになりました。

そして登録したキャラクターを使った台詞を記述する記法として「台詞記法」を追加しました。

キャラクター登録

キャラクタを登録すると、それぞれのキャラクタにプロフィールページが作られます。

さらにキャラクタを作品に「キャスト登録」すると、プロフィールページの「出演作品」とか、作品ページ脇の「登場人物一覧」というところに反映されます。

台詞記法

台詞記法を使うと、登録したキャラクターに台詞形式の発言をさせることができます。

[speak pochi いただきます]
[speak pochi@excited ごちそうさまでした!]

それぞれのキャラクタには、最大で5つまでの画像を登録できるので、色々な台詞を「笑顔」とか「怒り顔」など、画像を切り替えて表示させることができます(@excitedの部分です)。ノベルゲームなどでよくある手法ですよね。

表示させると、こんな感じになります。

f:id:convertical:20140801093021j:plain

上の画像は「ジュエルセイバーFREE」の画像素材を利用しています。

さらに発言者の画像をクリックすると、プロフィールがポップアップ。

f:id:convertical:20140801094630p:plain

作品に登場するキャラクターは、作品ページの登場人物一覧のところにも表示されます。

f:id:convertical:20140801094603p:plain

メリット

台詞記法を使うと、

  • 発言者の画像クリックでプロフィールがダイアログされるので、読者は人物が誰だったのかを思い出すのが容易
  • 執筆者は発言者が変わったことを仄めかす文章を省略できる
  • 執筆者は画像を切り替えることで、喜怒哀楽の変化を説明する手間も省ける

というのが良いところだと思います。

それよりもなによりも、それぞれのキャラクターにプロフィールページがあることによって、一つの作品やそれを取り巻くコンテンツに、新しい見方が加わるのが面白いと思います。

キャラクター機能や、台詞記法の詳しい説明はヘルプを見てください。