question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FlowContent and PhrasingContent separation is useless

See original GitHub issue

Apparently those contents come from XSD, but in the end of the day, they are quite useless and very confusing in kotlinx.html.

It does not help with static type check

if I write something invalid according to XSD, like body > span > div

body { // BODY creates FlowContent
    span { // SPAN creates PhrasingContent

        div { // DIV can only be created in _FlowContent_, not in SPAN

            // DIV is still allowed, because it is actually created in BODY, 
            // not in innermost parent SPAN
        }
    }
}

it is still silently accepted by the compiler and even leads to obscure IllegalStateException("You can't change tag attribute because it was already passed to the downstream") if I try to change attributes.

To me this seems like a general problem of ‘fall-through’ builder design.

It breaks the abstraction

Both functions, FlowContent.i and PhrasingContent.i are identical: they produce the same I object. But there’s no common abstraction between those two functions. Which leads to the third problem.

It prevents reusable code

I chose to use Tag as a basis for my DSL, which seemed like a good base class. But in the end I had to write the ugliest code in a decade of my career:

fun Tag.mdl_icon(icon: String, text: String? = null) {
    if (this is FlowContent) {

        i("material-icons") {
            +icon
        }
        if (text != null) {
            span(classes = "visuallyhidden") {
                +text
            }
        }

    } else if (this is PhrasingContent) {

        i("material-icons") {
            +icon
        }
        if (text != null) {
            span(classes = "visuallyhidden") {
                +text
            }
        }
    }
}

Both if and else part are identical, but functions i and span are different. Condition like if (this is FlowContent || this is PhrasingContent) cannot work, of course.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:4
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
kosiakkcommented, Sep 20, 2016

Very simple suggestion is to declare all tag-functions for the Tag class and discard *Content. We’ll have exactly one SPAN class and exactly one Tag.span function.

Pros:

  • less code to generate
  • simpler implementation, much easier to lean
  • solves all the problems above
  • minimal library, which does one thing (helps to write html from Kotlin)

Cons:

  • hierarchy check still won’t work
1reaction
cy6erGn0mcommented, Mar 2, 2017

You can use FlowContent or HtmlBlockTag for that purpose. Just need to be documented

Read more comments on GitHub >

github_iconTop Results From Across the Web

What is the difference between phrasing content and flow ...
So phrasing content is mostly intra-paragraph level, whereas flow content is basically whatever you might want to put inside body directly, ...
Read more >
Phrasing content - HTML Standard, Edition for Web Developers
Phrasing content is the text of the document, as well as elements that mark up that text at the intra-paragraph level. Runs of...
Read more >
3 Semantics, structure, and APIs of HTML documents - W3C
As a general rule, elements whose content model allows any flow content or phrasing content should have at least one node in its...
Read more >
<iframe>: The Inline Frame element - HTML - MDN Web Docs
Sandboxing is useless if the attacker can display content outside a sandboxed iframe — such as if the viewer opens the frame in...
Read more >
When To Use The Button Element | CSS-Tricks
Phrasing content is a limited subset of HTML elements that “defines the text and the ... <button> Outside of a <form>, I'm just...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found