Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: Fenced blocks #5

Open
MurakamiShinyu opened this issue Jan 26, 2020 · 23 comments
Open

spec: Fenced blocks #5

MurakamiShinyu opened this issue Jan 26, 2020 · 23 comments
Assignees
Labels
spec Spec related thing
Milestone

Comments

@MurakamiShinyu
Copy link
Member

Adopt fenced divs from Pandoc's Markdown, that allows special fenced syntax for div blocks.
See the spec: Pandoc Extension: fenced_divs

... As with fenced code blocks, one can use either attributes in curly braces or a single unbraced word, which will be treated as a class name. The Div ends with another line containing a string of at least three consecutive colons. The fenced Div should be separated by blank lines from preceding and following blocks.

Example:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

Fenced divs can be nested. Opening fences are distinguished because they must have attributes:

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

Fences without attributes are always closing fences. Unlike with fenced code blocks, the number of colons in the closing fence need not match the number in the opening fence. ...

Discussion

This "fenced divs" syntax is very similar to the walled block in the current VFM draft. I prefer "fenced divs" because:

  • naming: "fenced divs" is better, because the term "fenced" is consistent with "fenced code blocks".
  • colons ::: is better than ===, because === is used for setext heading underline and will make confusion.
  • the attribute syntax, same as the fenced code attributes, enables adding arbitrary attributes
@MurakamiShinyu MurakamiShinyu added the spec Spec related thing label Jan 26, 2020
@MurakamiShinyu
Copy link
Member Author

MurakamiShinyu commented Jan 26, 2020

Extend to HTML semantic elements

I'd like to change the issue title "Fenced divs" to "Fenced blocks" because I want to extend it for HTML semantic elements.

Examples:

:::::: section {.classA #idA role="doc-abstract" aria-label="Abstract"}
The **Abstract** section has a summary of the principal ideas, 
concepts and conclusions of the work.
::::::

will be converted to:

<section id="idA" class="classA" role="doc-abstract" aria-label="Abstract">
<p>The <strong>Abstract</strong> section has a summary of the principal ideas,
concepts and conclusions of the work.</p>
</section>

and

:::::: aside {role="doc-tip"}
### Tip
Helpful information that clarifies some aspect of the content
or assists in its comprehension.
::::::

will be converted to:

<aside role="doc-tip">
<h3>Tip</h3>
<p>Helpful information that clarifies some aspect of the content
or assists in its comprehension.</p>
</aside>

Update: syntax changed ::: {section .classA #idA…} to ::: section {.classA #idA…} because the tag name inside the curly braces might make confusion with attribute name without value specified.

@MurakamiShinyu MurakamiShinyu changed the title spec: Fenced divs spec: Fenced blocks Jan 26, 2020
@MurakamiShinyu
Copy link
Member Author

Testing with pandoc, I found that ::: aside is converted to <div class="aside"> (not <aside>), but ::: section is converted to <section> (not <div class="section">). This behavior is different from what the pandoc document says: "a single unbraced word, which will be treated as a class name". I want to fix this inconsistency.

Proposal: the unbraced word is treated as element name if it is a valid HTML element name, otherwise treated as a class name (same as {.className}).

@spring-raining
Copy link
Member

One of my concerns is that attribute list which we should allow (Obviously ::: {script="alert('XSS')"} have to be omitted), but this spec seems to be very useful!

@uetchy
Copy link
Member

uetchy commented Jan 29, 2020

I had the same concern @spring-raining had. And that's why only classes are allowed in the original spec of walled blocks.

Too many freedoms sometimes could be harmful.

@uetchy
Copy link
Member

uetchy commented Jan 29, 2020

I like the naming of Fenced blocks from @MurakamiShinyu. It sounds natural.

@tk0miya
Copy link

tk0miya commented Jan 29, 2020

Proposal: the unbraced word is treated as element name if it is a valid HTML element name, otherwise treated as a class name (same as {.className}).

I prefer unbraced word is always considered as an element name, and braced words are considered as attributes (classes, IDs and attributes). It is consistent behavior. magical behavior would be useful, indeed. But it sometimes confuses readers.

@MurakamiShinyu
Copy link
Member Author

I agree that relying on "valid HTML element names" is not a good idea. It will change by HTML spec updates. And also we should consider about Custom elements.

@uetchy
Copy link
Member

uetchy commented Jun 14, 2020

So here is my take.

  • Suitable for CSS Theming.
  • More frequent, fewer keystrokes.
    • Fenced blocks are mainly for a specific block to have dedicated styles. plain declarations should always be tied with a class name. tagName is a nice alternative but keep in mind that scriptwriters should care about semantics for their manuscript and be agnostic as possible to its final HTML structure.
# Chapter 2

:::author
uetchy
:::
<h1>Chapter 2</h1>
<div class="author">
<p>uetchy</p>
</div>
.author {
  padding: 5px;
  border: 1px solid black;
  border-radius: 4px;
}

role support

Since we care about WCAG, role property must have special treatment. so here it is. @ is used because of its resemblance to a roll. any thoughts?

:::@doc-tip
### Tip
:::
<aside role="doc-tip">
<h3>Tip</h3>
</aside>
[role="doc-tip"] {
  background-color: yellow;
}

custom attributes

Maybe we need fine-grained control over these blocks, yet it's not so often. but it's always good to leave an option to users, isn't it?

:::alertbox {style="text-decoration: uppercase"}
Users beware!
:::

:::{#fig:signup}
1. Go to webiste
2. Click on `signup` button
:::
<div class="alertbox" style="text-decoration: uppercase">
<p>Users beware!</p>
</div>

<div id="signup" data-ref="fig">
<ul>
<li>Go to website</li>
<li>Click on <code>signup</code> button</li>
</ul>
</div>

latter uses cross-ref syntax.

@kmuto
Copy link

kmuto commented Jun 16, 2020

What will be happen on VFM when omitting open/close notation?

Pattern A:

:::author
I forgot to close.
Pattern B:

I forgot to open.
:::

@uetchy
Copy link
Member

uetchy commented Jun 17, 2020

VFM just ignores them.

@kmuto
Copy link

kmuto commented Jun 17, 2020

OK, so...

:::div1
alpha
:::::div2
beta
::::::::
  • take div1, ignore div2
  • take div2, ignore div1
  • ignore both

@tk0miya
Copy link

tk0miya commented Jun 17, 2020

Just FYI: The fenced code block in commonmark is closed by the end of the document if no closing code-fence found.
https://spec.commonmark.org/0.29/#example-96

@uetchy uetchy added this to the v1 milestone Jul 1, 2020
@uetchy uetchy removed this from the v1 milestone Jul 1, 2020
@akabekobeko akabekobeko self-assigned this Jan 16, 2021
@MurakamiShinyu
Copy link
Member Author

MurakamiShinyu commented Jan 27, 2021

現状の vfm の Fenced blocks 実装とその課題、Pandoc との比較

Fenced blocks は、Prior Art である Pandoc の fenced_divs と互換性があるとよい。

Pandoc の fenced_divs の仕様

https://pandoc.org/MANUAL.html#extension-fenced_divs

  • 開始は3つ以上の連続するコロンのあとに属性指定があること
    • 属性指定のあとに、さらに任意の数の連続するコロンがあってもよい
    • 属性指定の構文は次のいずれか:
      • ひとつの名前だけでクラス名を表す
      • 波括弧で囲んだ形式: {#identifier .class .class key=value key=value}
  • 終了は3つ以上の連続するコロン
  • 前後のブロックとの間は空白行で区切ること

例:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

<div id="special" class="sidebar">
  <p>Here is a paragraph.</p>
  <p>And another.</p>
</div>

次はネストの例。開始のフェンスには属性指定があることで終了のフェンスと区別される(3つ以上連続するコロンの数は関係ない):

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

<div class="Warning">
  <p>This is a warning.</p>
  <div class="Danger">
    <p>This is a warning within a warning.</p>
  </div>
</div>

内容が空の fenced div を試すと:

:::empty
:::

<div class="empty"></div>

現状の vfm の Fenced blocks をテストすると

しかし、現状の vfm パーサーの実装では、Pandoc のドキュメントにある次の例が処理できない:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

<p>::::: {#special .sidebar} Here is a paragraph.</p>
<p>And another. :::::</p>

Fenced blockへの {…} での属性指定は未サポート。ではクラス名だけを書く記法ではどうか:

::::: sidebar
Here is a paragraph.

And another.
:::::

<p>::::: sidebar Here is a paragraph.</p>
<p>And another. :::::</p>

どうも連続するコロンの数が3つよりも多いと fenced block として処理されないようである。コロンを3つに直したら:

::: sidebar
Here is a paragraph.

And another.
:::

<div class="sidebar">
  <p>Here is a paragraph.</p>
  <p>And another.</p>
</div>

ネストの例ではどうか。

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

<p>::: Warning :::::: This is a warning.</p>
<div class="Danger"><p>This is a warning within a warning.</p></div>
<p>::::::::::::::::::</p>

これを次のように直したところ現状の vfm で処理できるようになった:

::: Warning
This is a warning.

:::: Danger
This is a warning within a warning.
::::
:::

<div class="Warning">
  <p>This is a warning.</p>
  <div class="Danger">
    <p>This is a warning within a warning.</p>
  </div>
</div>

内容が空の Fenced block を試すと、Fenced block として処理されない:

:::empty
:::

<p>:::empty :::</p>

ここまでで分かった問題点

現状の vfm のパーサーでは

  • {…} での属性指定が未サポート
  • 連続するコロンの数はネストの外側では必ず3つ :::
    • 属性指定のあとにコロンがあるとだめ。(::: Fenced ::::::::::: のようにフェンスらしくできない)
    • ネストするごとに1つずつコロンの数を増やさなくてはならない
  • 内容が空だとだめ

見出しとの組み合わせの場合

Pandoc では、fenced div 内が見出しではじまる場合、fenced div で div ではなく section 要素が生成される。

例:

::: appendix
## Appendix A {#aaa .bbb data-ccc=ddd}

This is an appendix.
:::

<section id="aaa" class="bbb appendix" data-ccc="ddd">
  <h2 class="bbb" data-ccc="ddd">Appendix A</h2>
  <p>This is an appendix.</p>
</section>

pandocに --section-divs オプションを指定した場合の結果は:

<section id="aaa" class="level2 bbb appendix" data-ccc="ddd">
  <h2 class="bbb" data-ccc="ddd">Appendix A</h2>
  <p>This is an appendix.</p>
</section>

--section-divs オプションの有無にかかわらず、fenced div内が見出しではじまる場合は section 要素で囲まれ、見出しに指定された属性はsection要素にコピーされる。
class属性に levelN (N は見出しのレベル) が追加されることだけ --section-divs 指定があると違う。

現状のvfmでは

::: appendix
## Appendix A {#aaa .bbb data-ccc=ddd}

This is an appendix.
:::

<div class="appendix">
  <section id="aaa" class="bbb" data-ccc="ddd">
    <h2>Appendix A</h2>
    <p>This is an appendix.</p>
  </section>
</div>

vfm では見出しで自動的に section 要素が作られるが、Fenced block の div 要素の中にその section 要素ができる。あまりスマートでない。

role 属性について

現在の VFM の独自拡張で次のような記法で DPUB-ARIA の role 属性を指定できる:

:::@appendix
# Appendix A
:::

<section role="doc-appendix" id="appendix-a">
  <h1>Appendix A</h1>
</section>

この独自拡張仕様の見直しについては spec: WAI-ARIA role syntax (#28) にコメントする。
その要点は以下:

  • role 属性のための @ をプレフィックスする記法(例: @appendix)は廃止したい
  • クラス名に DPUB-ARIA で定義された名前を使うことを推奨し、そのようなクラス名が指定されたら自動的に role 属性も付加するようにする
    • 例: ::: appendix または {.appendix}<section class="appendix" role="doc-appendix">
  • スタイルシートでは role 属性ではなくクラス名を使う([role="doc-appendix"] ではなく .appendix を使うこと)
    • role 属性はアクセシビリティ用途、クラス名はスタイルシート用途、と区別
  • role 属性によって自動的に生成する HTML 要素を変えるようにはしない
    • ある role 属性値を指定するのに適切な HTML 要素はひとつと限らない
    • HTML 要素名を明示的に指定できるしくみがあったほうがよい(このあとの節で提案)

HTML 要素名を明示的に指定可能にする拡張案

(このコメントは長過ぎだったので次のコメント #5 (comment) に移動)

@akabekobeko
Copy link
Member

昨日の開発者会議を受けた #67 のとおり、本機能は v2 へ見送ります。

@akabekobeko
Copy link
Member

akabekobeko commented Feb 12, 2021

VFM v2 は remark-parse v9 対応を想定しているので、その際は本機能を自前で実装せずに Pandoc 互換となる以下を採用するのがよさそう。

@MurakamiShinyu
Copy link
Member Author

HTML 要素名を明示的に指定可能にする拡張案

(前のコメント #5 (comment) が長過ぎだったので分割した)

Pandoc の fenced_divs では、基本は div 要素が作られ、最初の要素が見出しであれば div の代わりに section 要素が作られる。

これをさらに拡張して、ほかの HTML 要素名も指定可能にしたい。

拡張案:

  • ::: のあとの名前が HTML 要素名として有効なもの(例: header, footer, main, nav, article, aside, section)の場合、その名前を HTML 要素名とクラス名の両方にする
  • ::: のあとに HTML 要素名、そのあとに波括弧囲みの属性指定 {…} という構文も可能にする

例:

::: aside
Hello
:::

<aside class="aside">
  <p>Hello</p>
</aside>

属性の指定もある場合:

::: article {#aaa .bbb data-ccc="ddd"}
# The Article
:::

<article id="aaa" class="article bbb" data-ccc="ddd">
  <h1>The Article</h1>
</article>

波括弧囲みのクラス名指定だけの場合はそれを HTML 要素名にはしない:

::: {.aside}
Hello
:::

<div class="aside">
  <p>Hello</p>
</div>
::: {.aside}
# Hello
:::

<section class="aside" id="hello">
  <h1>Hello</h1>
</section>

Fenced block の ::: のあとの名前を HTML 要素名にすると不正な HTML になるような場合には、その名前を HTML 要素名とはしないでクラス名にする

::: span
# Hello
:::

<section class="span" id="hello">
  <h1>Hello</h1>
</section>

Fenced block の内容にインラインのテキストも可能にする拡張案

Fenced block の ::: のあとの名前が HTML 要素名で、その内容に段落(p)要素を持つことができないものである場合、Fenced block 内のテキストを段落要素にしないでインラインのテキストの扱いにする

::: small
This is a small notice.
:::

<small class="small">This is a small notice.</small>

Fenced block の終了を分かりやすくする拡張案

Fenced block の終了の ::: のあとに任意で /名前 を書けるようにすることで、ネストした fenced block の開始と終了のペアを分かりやすくできたらよいかもしれない。例:

::: aside
:::: Warning
This is a warning.

::::: Danger
This is a warning within a warning.
::::: /Danger
:::: /Warning
::: /aside

@MurakamiShinyu
Copy link
Member Author

MurakamiShinyu commented Feb 12, 2021

@akabekobeko

VFM v2 は remark-parse v9 対応を想定しているので、その際は本機能を自前で実装せずに Pandoc 互換となる以下を採用するのがよさそう。

remark-fenced-divs の readme に次の記述:

If you don't need Pandoc compatibility you should consider using remark-directive.

remark-fenced-divs あるいは remark-directive を検討するとよさそうですね。

remark-directive では

:::main{#readme}

<main id="readme">

になります。これは私の HTML 要素名を明示的に指定可能にする拡張案 と似ています。私の案では、

:::main{#readme}

<main class="main" id="readme">

となるのですが、要素名と同じものをclassにも出力するのは実績がある Pandoc となるべく互換にしようとしたためです。
しかし、remark-directive の拡張が多くの人が利用する標準になっていくのであれば、Pandoc互換にこだわる必要はありません。

@akabekobeko
Copy link
Member

この記法は #67 により v1.0 では見送りとなりました。v2.0 で検討する場合は↑の @MurakamiShinyu さんコメントにあるとおり parser 変更があるため Pandoc 互換の benabel/remark-fenced-divs を検討予定です。

@MurakamiShinyu
Copy link
Member Author

v2.0 で検討する場合は↑の @MurakamiShinyu さんコメントにあるとおり parser 変更があるため Pandoc 互換の benabel/remark-fenced-divs を検討予定です。

Pandoc 互換ではない remarkjs/remark-directive も検討するとよいです。

@akabekobeko
Copy link
Member

はい。両方を候補にしましょう。ただし択一にしたいですね。

@nosuke23
Copy link

Pandoc の fenced_divs では、基本は div 要素が作られ、最初の要素が見出しであれば div の代わりに section 要素が作られる。
これをさらに拡張して、ほかの HTML 要素名も指定可能にしたい。

MarkdownはHTMLの軽量マークアップ言語であり、HTMLによるドキュメント生成において比較的頻繁に用いられるセマンティックタグやタグ構造を、ドキュメントの執筆者にとって見やすく、書きやすいように設計されたものです。

:::main ... :::がその哲学に則っているかというとどうでしょう。多くのMarkdownユーザーにとって一般的でないし、他のMarkdown拡張と互換性がない上、<main>~</main>と書くのと記述量として大差がありません。

単純にPandoc互換を目的とするなら、Pandoc記法のサブセットにすべきかと。

@MurakamiShinyu
Copy link
Member Author

Fenced blocksによって解決されると期待されている問題:

@MurakamiShinyu
Copy link
Member Author

Pandoc 互換ではない remarkjs/remark-directive も検討するとよいです。

はい。両方を候補にしましょう。ただし択一にしたいですね。

Pandoc互換の https://github.com/benabel/remark-fenced-divs は、"ARCHIVED: This plugin has never been completely adapted for remark 13+." となっているので、今後 remark 13+ に移行予定のvfmには使えなさそう。

vfm v1→v2の仕様変更で、見出しのsection囲みでの属性の扱いについてPandoc互換をやめていることもあるし、Pandoc互換よりも remarkjs のエコシステムでポピュラーで使いやすいものを採用するのがよさそう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
spec Spec related thing
Projects
None yet
Development

No branches or pull requests

7 participants