シリーズの目次と、テキスト内の目次が、両方サイドバーに表示されるようになりました。
シリーズの目次
シリーズの目次は、同一シリーズ内のコンテンツを行き来するための目次です。
テキスト内の目次
テキスト内の目次は、本文の中で見出し(ヘッダー)が設定された箇所にジャンプするための目次です。
シリーズの目次とは違い、クリックするとその見出しのあるページにジャンプします。
シリーズの目次と、テキスト内の目次が、両方サイドバーに表示されるようになりました。
シリーズの目次は、同一シリーズ内のコンテンツを行き来するための目次です。
テキスト内の目次は、本文の中で見出し(ヘッダー)が設定された箇所にジャンプするための目次です。
シリーズの目次とは違い、クリックするとその見出しのあるページにジャンプします。
まだ実験的な機能なのですが、数式の組版に対応しました。
エディター画面の「数式」をクリックします。
数式エディターが開くので、MathJax形式で入力します。
プレビューすると、こんな風に表示されます。
横書きのとき
縦書きのとき
詳しくはMathJaxのドキュメントを見ていただくとして、大雑把に言うと\[
〜 \]
で囲むか、$$
〜 $$
で囲みます。
$$ E = mc^2 $$ \[ e^{i\theta} = \cos\theta + i\sin\theta \]
数式を組み込むと、MathJaxの組版が完了するまで、先頭ページの表示が少し遅くなります。ご注意ください。
作品ページから執筆ページ(エディターページ)に移動できるようになりました。
自分の作品であれば、タイトル脇に「編集する」というボタンが表示されます。
nehan.js 5.5.0をリリースしました。
以下、5.4.x系列からの変更点です。
:matches
, :not
, :lang
をサポートしました。text-combine-upright
が使用されるようになりました。demotext-orientation
の値にsideways
, upright
, mixed
が指定できるようになりました。demolist-style-position
の値に、inside
が指定できるようになりました。Nehan.Preloads
モジュールの追加。サイズ未設定のimg
やmath
などのサイズが動的に取得されるようになりました。onload
フックとして評価されるようになりました。pasted
からlazy
に変更されました。Nehan.PagedElement
が削除されました。今後はNehan.Documentを使用して下さい。Nehan.LexingRule
が削除されました。今後、シングルタグの定義にはNehan.setSingleTagName
を使用して下さい。Nehan.Rgb
, Nehan.Palette
, Nehan.Colors
モジュールが削除されました。v5.5.0から、Nehan.PagedElement
が削除されました。
これの中身は、単なるNehan.Document
のラッパで、やってることはページ状態と表示先DOMをDocumentクラスと一緒に管理しているだけのものです。
Nehan.Document
と役割が被ることが多いので、今回のバージョンアップで削除してしまうことにしました。
MathJaxのサポートですが、現時点では本ソースへの取り込みではなく、プラグインでの対応です。
詳しくは以下のリンクから確認して下さい。
https://github.com/tategakibunko/nehan.js/tree/master/plugins
例えばHTMLで「F-15」のような「-」(ハイフン)を含むboxを90度回転して表示させようとすると、ハイフンの後で改行されてしまいます。
なぜこんなことが起きてしまうのでしょうか。
フォントサイズが16と仮定して「F-15」という横書きのwordを囲むサイズが、32x16(横x縦)だとします。
これを縦書き用に90度回転させると、このwordを囲むサイズは、32x16から16x32になります。
このときFの後のハイフンが、回転前の横幅(32)ではなく、回転後の横幅(16)を前提にして解釈されるのが、改行が発生する原因です。
「F-」まで描画したところでインラインの描画位置が、回転後における横幅の限界(すなわち16)に届くのですが、この位置で発生したハイフンが、line-break-point
とブラウザに判断されるため、改行が発生してしまうわけです。
Unicodeの中でline-break-point
と解釈されるハイフンは他にも色々(*注1)ありますが、よく使われるのはHYPHEN MINUS(U+002D)
や、HYPHEN(U+2010)
です。
*注1 U+002D, U+2010, U+2012, U+2013とかもそう。調べたらもっとあるかも。
というわけで、nehan.js内では英数字を縦書き用に回転させるときだけ、U+002D
とU+2010
(U+2012,U+2013なども)を、あらかじめnon-breaking-hyphen(U+2011)
に変換して、この問題を回避しています。
white-space:pre
でも解決できるかもしれないです。
もちろんこれはベストな解決方法ではありません。
こうしたHyphenの動きをコントロールするため、CSSにはhyphens
というプロパティが定義されているのですが、なぜかChromeではまだ未実装(その他のブラウザは殆ど実装されている)なので、仕方なくこういう回避策をとっています。
Nehan Reader(version 2.1)をリリースしました。
オプションページにて、
などが設定できるようになりました。
ちなみに「小説家になろう」とか「青空文庫」のような、既に使っている人が多そうな対象は、デフォルトで設定しておきました。
なので、version2.1をインストールして「青空文庫」や「小説家になろう」の「作品ページ」にアクセスすると、作品本文を抜き出して縦書きページ送りにしたビューアーが自動的に起動しちゃいます。
捗りますね!
Nehan Readerのボタン上で右クリックして「オプション」へ進みます。
automatic convert URLsの欄に、自動変換させるサイトのURLパターンを記述します。
内容はSaveUrlList
というボタンを押すと保存されます。
URLパターンの記述方法は2つあります。
一つは、ダイレクトにサイトのURL(の一部)を記述する方法。
もう一つは、サイトのURLパターン
を正規表現で記述する方法(上級者向け)です。
以下はサンプルです(#
で始まる行はコメント扱い)。
# URLをダイレクトに記述 headlines.yahoo.co.jp # 正規表現で記述 r(www\.aozora\.gr\.jp/cards/\d+/files)
正規表現でパターンを指定する場合は、
r(正規表現)
の形式で記述しますが、メタ文字をエスケープする必要があることに注意して下さい。
サイトによっては、ページ全体ではなく、メインとなる記事のみを変換したいことがあります。
ヘッダーロゴの部分をスキップするのが面倒とか。
そういう場合は、オプションページのpath to convert targetの欄で、サイトごとの変換対象(へのjQueryPath)を設定することができます。
書式は
[URLパターン], [変換対象のjQueryPath]
の形式です。
[jQueryPath]の部分については、複数指定することもできます。
複数指定した場合は、最初に見つかったものが変換対象になります。
もし見つからなければ、ページ全体が変換されます。
以下はサンプルです。
# yahooニュースは、#mainを対象に変換する news.yahoo.co.jp, #main # URL部分は正規表現でもOK r([a-z]\.yahoo\.co\.jp), #main # www.example.comでは、まず.mainを探して、なければ.entryを探す www.example.com, .main, .entry
記述したら、忘れずに「SavePathList」というボタンで保存して下さい。
自動変換するサイトを指定しておくと、いちいち変換ボタンを押さなくても勝手にビューアーが起動するので、ウェブ上の連載作品を読むのがとても楽になりました。
http://tb.antiscroll.com/static/nehan-demo#list
このデモですけど、ブラウザの大きさを変えると、リフローすることに気付いた人はいるでしょうか。
こういうデモで、テーブル組版や回り込み処理を見せると「おお」となる人が多いんですけど、リスト組版を見せても「で?」という人が多いと思います。
しかし、一見すると単純に見えるリスト組版ですが、実はテーブルの組版とよく似た複雑な組版なのです。
nehan.jsでは、list-style-position:outside
かつdisplay:list-item
な要素と、display:table-row
な要素は、どちらもParallelGenerator
(並列組版)のサブクラスで実装されています。
特徴としては、複数の子要素が矛盾なく表示されるための「前計算」を必要とするケースが多い、というのがあります。
例えばテーブルなら、各セルのサイズをどう割り当てるのか、事前に何らかの計算が必要なのは、なんとなく想像がつくと思います。
でもリストはどうでしょうか?
「リストなんて、単にテキストの先頭にリストマークの添字を足すだけじゃないの?」と思う人もいるかもしれません。
この指摘は、list-style-position:inside
なら、まあそのとおりなのです。
しかしlist-style-position:outside
のときは、様相が異なります。
まずはUL>LI
が書かれたHTMLを、適当なブラウザで表示させみてください。
<ul style="list-style-position:outside"> <li>日本国民は、正当に選挙された(以下略)</li> </ul>
さて、表示されたリストですが、各リスト・アイテムの「リストマーク」は、マウス等ではテキスト選択できません。
つまり、このリストマークは、ユーザーがDOM操作では触れない組版要素になっています。
これが「CSSとDOMの境界」です。
これだけじゃありません。
list-style-positon:outside
のときは、リストの要素が一行を溢れても、リストマークの横幅だけ常に内容がインデントされています。
つまり空白の一列が割り込んでいるわけです。
この空白も、li
マークアップに対するmargin
やpadding
で実現されているわけではないので、CSSとDOMの境界と言えます。
正確にリストを組版するためには、これらの境界要素に関するサイズ配分を事前に計算する必要があるわけです。
で、こういう性質を知っていると、例えばブラウザにとってどんなリストが意地悪なのかが、なんとなく予想できます。
例えばOL>LI*1000
なマークアップで、それぞれのリストを1em
, 2em
, 3em
の文字サイズで順に表示させてみましょう。
<style type="text/css"> ol{ list-style-position:outside; } .hoge{ font-size:1em } .hige{ font-size:2em } .hage{ font-size:3em } </style> <ol> <li class="hoge">hoge</li> <li class="hige">hige</li> <li class="hage">hage</li> <!-- 以下1000行まで続く --> </ol>
どうしてこれが意地悪なのかというと、このリストを正しく表示するためには、1000行の添字が使うであろう数字文字列の最大幅を事前に計算する必要があるからです。
じゃないと、適切なインデントを実現できませんよね。
しかしchrome/firefox/safariにこれを表示させると、いずれも桁数が大きくなったところで、以下のようにリストの添字部分が「画面の左側」に見切れてしまいます。
body{margin-left:3em}
みたいな設定をしていたってダメです。左の限界を突破して表示が切れます。
もちろん普通に考えると、li要素にそれぞれ違う文字サイズを付与することなんて考えにくいことなので、実用上は問題ないのです。
ただ正確に扱おうとするなら、リスト要素もテーブル組版と同じく、先に必要領域を計算する必要のある重い組版に該当するわけです。
この1000行のリストが、現状のブラウザで瞬時に表示されるのは、単に各ブラウザが厳密な計算をサボっているだけで、組版処理そのものが単純だからではありません。
nehan.js 5.4.0をリリースしました。
このバージョンから新しく追加された機能や、5.3.x系から消えた機能などがいくつかあるので、ご注意下さい。
Nehan.Document
が新たに定義されました。onPage
コールバックがサポートされました。Nehan.setup
, Nehan.createEngine
, Nehan.PageStream
が廃止されました。Nehan.Document
は、paged media用のdocument環境を抽象化したクラスです。
こういう風に使います。
var doc = new Nehan.Document(); var target = document.querySelector("#target"); // 表示先 // 内容をセット doc.setContent("<h1>hello, nehan.js!</h1>"); // ページサイズやスタイルをセット doc.setStyle("body", { flow:"tb-rl", // or "lr-tb" width:600, height:400, fontSize:16 }); // 組版スタート doc.render({ // 各ページが完了する度に呼ばれる onPage:function(page, ctx){ console.log("page:%o, pageNo:%d, percent:%d", page, page.pageNo, page.percent); page.element.style.marginBottom = "1em"; // ちょっと下にスペースを足しておく target.appendChild(page.element); // 組版結果を表示先に追加していく } });
onPage
コールバックを定義すると、ページ計算が都度DOMに変換しながらのパースになります。
なので、ページを遅延評価するonProgress
コールバックを使う場合と比べると、全体のパーススピードは落ちるのですが、代わりにコードは簡略化されます。
これまでonProgress
内でページオブジェクトを取得する場合、以下のようにする必要がありました。
doc.render({ onProgress:function(tree, ctx){ // この中でページが欲しい場合は、tree -> page する必要があった var page = ctx.getPage(tree.pageNo); } });
onProgress
に渡されるのはページではなく、ツリー(まだDOM化されていない中間オブジェクト)だからです。
しかし段組表示がしたい場合などは、即座にDOM変換された結果が欲しいわけですから、onPage
が便利でしょう。
一方、ページ送りするビューアーを作る場合は、現在表示されていないページを変換する必要はないので、onProgress
を使って遅延しておくと、全体のパーススピードが上がります。
作成した各Documentは、それぞれに独立したCSS環境を持ちます。
だからそれぞれを縦書きにしたり横書きにしたりできるのですが、全ドキュメントに共通のスタイルを定義したいときもあります。
そういう場合は、Nehan.seStyle
を使ってください。
// 先にグローバルスタイルをセットしておく Nehan.setStyle(".header", { margin:function(ctx){ var em = ctx.style.getFontSize(); var rem = ctx.style.getRootFont().size; return { before:Math.floor(2 * rem - 0.14285 * em), after:rem }; } }); // 縦書き組版環境 var vert_doc = new Nehan.Document() .setStyle("body", {flow:"tb-rl"}) .setContent("<h1 class='header'>vert doc</h1>"); // 横書き組版環境 var hori_doc = new Nehan.Document() .setStyle("body", {flow:"lr-tb"}) .setContent("<h1 class='header'>hori doc</h1>");
グローバルスタイルについては、各ドキュメントを作る「前に」セットしておく必要があることに注意してください。