mdmark

文書を描く仕組み

Markdown と設定を渡してから描かれるまでの流れと、テーマの層・機能のオン・オフの優先順

使う側のページが mount か render に Markdown と設定を渡してから、文書が描かれるまでの流れ。 見た目と機能が、何で決まるかを合わせて示す。

描かれるまでの流れ

  1. 設定に既定を当てる。省いたキーは既定になり、型の合わない値は無視する
  2. Markdown を解析し、GitHub Flavored Markdown の記法(表・タスクリスト・取り消し線・www の自動リンク)を HTML にする
  3. 文書の 印 を拾う。features の印は機能のオン・オフに使い、記法の印はその記法の機能がオンなら記法にし、オフなら取り除いて普通の Markdown として描く。対応表にある名前の印と登録した拡張の印は印の場所に置き換え、それ以外の印は取り除く
  4. 記法 を HTML にする。表・注意書き・タブ・ステップ・ファイルツリー・バッジ・目次・節・行の詳細・図表の番号を、中身を読める HTML にし、見出しに ID を付ける。読めない指定は、その箇所に書き方の警告を置き、読めた指定で描く
  5. 許可していない要素・属性・URL を落とす。script 要素・on で始まる属性・style 属性・javascript: の URL は残らず、スクリプトは実行されない。href と src は http・https・mailto と相対 URL だけ残り、画像の src は画像の種類と base64 の形の data: URL も残る。記法の class・data-*・id は、mdmark が記法から出した要素にだけ残る
  6. render は、ここで本文の HTML 文字列を返す。各記法の中身は、スクリプトを動かさなくても読める
  7. mount は、要素の中に本文を描いて class mdmark を付け、記法の操作(表の並べ替え・ピン止め・絞り込み・件数・列の表示の切り替え・集計の行・コピー・行へ移る処理、タブの切り替え、節と行の詳細の開閉)を付ける。印の場所があれば外部ライブラリと拡張のモジュールを読み、印刷と hashchange の受け取りを付ける。update は本文を差し替えて操作を付け直し、destroy は操作と受け取りを外す

索引を渡したときの流れ

opts.index・opts.docId・opts.references を渡すと、上の流れに次が加わる(考え方は 索引と被参照)。

  1. 索引の形を確かめ、Schema に合わない文書・用語の項目は除く
  2. 文書の glossary の印で囲んだ表から用語を読む。glossary がオフなら読まず、表を普通の表として描く
  3. 索引の terms・描く文書の表・ほかの文書の表(references.glossary)・文書の aliases から、照合する語の辞書を作る。同じ語は、索引の terms、描く文書の表、ほかの文書の表の順に優先する。文書の別名は backlinks がオンのときだけ入れ、描く文書自身の別名は入れない 辞書の語と本文の文字は、照合の前に NFKC・英字の小文字化・前後の空白の除去で正規化する。 正規化した後に同じになる語は 1 つの語として、この優先の順で先の用語を使う。
  4. 本文の文字を、語の区切りに揃うところだけ、長い語を先に辞書と照合する。用語は用語の id、文書の別名は文書の id ごとに、節ごとに最初に出たところだけに下線とツールチップを付ける。コード・リンク・見出し・用語集の表の中は照合しない 下線は、正規化する前の本文に記載したままの文字に付ける。 索引の用語の avoid と用語集の表の avoid= の列のやめた言い方も、辞書の語として同じ規則で照合する。 同じ位置で用語の語・別名にも当たるときは用語を選び、文書の別名にも当たるときはやめた言い方を選ぶ。 やめた言い方は、節ごとに言い方ごとの最初に出たところだけ、用語の下線とは別に数えて、波線のマーカーと代わりの用語のツールチップを付ける。 glossary がオフのときは、やめた言い方を照合しない。
  5. 描く文書を参照している文書を、opts.references.backlinks[opts.docId](無ければ索引の related に描く文書を持つ文書)から引き、本文の末尾に被参照の一覧を置く。backlinks がオフなら置かない
  6. 索引の題・意味・概要は Markdown として解析せず、文字として出す。リンクの href は、本文のリンクと同じ許可の検査を通す

render はここまでの HTML 文字列を返す。 意味と関連文書は、スクリプトを動かさなくても読める。 mount は、ツールチップを開閉する操作を付ける。 update で付け直し、destroy で外す。

埋め込んだ HTML を描くときの流れ

<!-- html --> の範囲に html のコードブロックがあり、html の機能がオンのとき、描かれるまでの流れに次が加わる(書き方は 記法)。

  1. 範囲の html のコードブロックの中身を、コードでなく生の HTML として読む。範囲のコードブロックが 1 つでないときは、書き方の警告を置き、コードのまま描く
  2. 中身に、上の許可の検査を通す。script 要素・on で始まる属性・javascript: の URL は残らない。button は type="button" に固定して残し、style はレイアウト・余白・枠・色・文字の宣言だけを残す
  3. 中の <mdmark-chart> などの custom element の中身を、図の部品の印の範囲と同じ定義として読み、図に置き換える。hints がオンなら、data-hint を持つ要素と図の箱の hint に、ツールチップの中身と印を置く
  4. 中の文字を、本文と同じ用語の辞書と照合する

render はここまでの HTML 文字列を返す。 mount は、中の図の部品に拡大・縮小・移動の操作を、ヒントに開閉の操作を付け、本文の列より広い HTML を中で横にスクロールさせる。 書いたスクリプトは動かず、動くのは mdmark が付ける操作だけになる。

機能のオン・オフの優先順

機能のオン・オフは、次の順に重ねて決まる。 後に挙げたものが、前に挙げたものを上書きする。

順 決めるもの 書く場所
1 mdmark の既定 機能の既定
2 設定の features opts.config.features
3 文書の印 文書の <!-- features: +機能 -機能 -->

文書の印は、書いた順に重ねる。 同じ名前が何度も出たら、後に書いたものが勝つ。 知らない機能名と、+・- で始まらない引数は無視する。 update で本文を差し替えると、差し替えた本文の印で決め直す。

テーマの層

mdmark の CSS は @layer mdmark に入る。 使う側が層の外に書いた CSS は、詳細度によらず mdmark の CSS に勝つ。 見た目は、次の 2 つで変えられる。

使う側の theme.css は、使う側のページが <link> で層の外に読む。 mdmark は theme.css を読まない。 画面で OS の設定がダークのときは、色の変数がダークの値になる。 描く先の要素かその祖先の class があるときは、OS の設定より先に class が配色を決める(配色を切り替える class)。 印刷では明るい配色に戻る。

外部ライブラリを読むタイミング

外部ライブラリのモジュールは、文書に対応表にある印があるときだけ、import() で読む。 印の無い文書では、外部ライブラリへの要求は 0 件になる。 同じ文書の同じ名前の印は、モジュールを 1 回だけ読む。 registerExtension で登録した拡張のモジュールも、文書にその印があるときだけ、load で読む。 schema を渡した拡張は、読む前に印の引数を検査し、合わなければ読まずに、その印の場所だけを書き方の警告に替える。 import map は使わない。

読み込みの間、印の場所には読み込み中の枠が出る。 モジュールを読めないとき、またはモジュールの draw が例外を投げたときは、その印の場所だけが知らせの枠に替わり、ほかの箇所は描かれる。 拡張のモジュールも同じ。