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

PostModifier for ScalaJS #538

Open
fdietze opened this issue Jul 25, 2021 · 11 comments · May be fixed by #539
Open

PostModifier for ScalaJS #538

fdietze opened this issue Jul 25, 2021 · 11 comments · May be fixed by #539

Comments

@fdietze
Copy link

fdietze commented Jul 25, 2021

For a dom dsl, I would like to show, which html code will be generated:

div("hello")

using a PostModifier, I want to render it into a temporary html element and extract the innerHTML of that element.

But as far as I understand, the PostModifier runs only on the JVM, so this is currently not possible.

Any ideas?

@fdietze
Copy link
Author

fdietze commented Jul 25, 2021

Or is it possible to wrap the code with other code before execution in the browser? That would also be an option for me.

@olafurpg
Copy link
Member

Thank you for reporting! The Scala.js support is implemented with an entirely separate compile/evaluate pipeline making it difficult to support JS/JVM with a unified API. A JS PostModifier would need to evaluate inside the browser every time HTML gets rendered while a JVM PostModifier evaluates once before the output markdown is generated.

Can you elaborate on your use-case? What would you concretely like to write in the markdown source and what should concrete render in the output?

@olafurpg
Copy link
Member

Or is it possible to wrap the code with other code before execution in the browser? That would also be an option for me.

Is it an option to manually wrap the code with a function call? For example, if you have an innerHTML helper method that performs the logic for you:

```scala mdoc:js
innerHTML {
  div("hello")
}
```

@fdietze
Copy link
Author

fdietze commented Jul 25, 2021

I started to work on the outwatch documentation again and want to automatically generate the corresponding html code for static content:

https://github.com/outwatch/outwatch#concatenating-strings

It doesn't matter much if it's evaluated at build-time with node or in the browser

(I'm on mobile now and can add some code later)

Yes, wrapping with a visible shared function call would have been my next feasible workaround.

@olafurpg
Copy link
Member

Have you considered writing an invisible helper method called “div” that implements your desired functionality?

@fdietze
Copy link
Author

fdietze commented Jul 25, 2021

Have you considered writing an invisible helper method called “div” that implements your desired functionality?

Very interesting idea!

This is what I tried:

```scala mdoc:js:shared:invisible
def div(modifiers: VDomModifier*):String = {
    val vnode = dsl.div(modifiers)

    val domNode = org.scalajs.dom.document.createElement("div")
    OutWatch.renderInto[IO](domNode, vnode).unsafeRunSync()
    domNode.innerHTML
}
```

```scala mdoc:js
div("Hello ", "World!", color := "tomato")
```

But then I realized that return values are not printed in mdoc:js. I was only able to write the result into the current node:

```scala mdoc:js
node.innerText = div("Hello ", "World!", color := "tomato")
```

I cannot put the node.innerText = ... inside the invisible function, since it would be a different node, right?
edit: I just tried. when :shared is used, there is no more node variable in scope.


Originally, I imagined having a custom modifier vnode like this:

```scala mdoc:js:vnode
div("Hello ", "World!", color := "tomato")
```

Which adds a comment, containing the innerHTML representation:

```scala
div("Hello ", "World!", color := "tomato")
// <div style="color: tomato;">Hello World!</div>
```

@olafurpg
Copy link
Member

One thing we could do is to make the node variable available through a global var or an implicit. Then you could update innerHTML. Do you think that would resolve your usecase?

@fdietze
Copy link
Author

fdietze commented Jul 25, 2021

Yes, I think either would solve my case. An implicit sounds more elegant to me. Would there be any downsides?

olafurpg added a commit to olafurpg/mdoc that referenced this issue Jul 26, 2021
This makes it possible to implement helper methods that edit
`innerHTML`. Fixes scalameta#538.
@olafurpg olafurpg linked a pull request Jul 26, 2021 that will close this issue
@olafurpg
Copy link
Member

Sounds good. I opened #539 to add a new implicit val nodeImplicit: HTMLElementImplicit in scope for every code fence that you can pass around to invisible helper methods.

@Atry
Copy link

Atry commented Jan 18, 2023

I think the use case would be to use the output of mdoc:js as a snapshot test, i.e., the test should be considered failed if the generated output changes.

@fdietze
Copy link
Author

fdietze commented Mar 14, 2023

For reference, this is what I ended up with in the outwatch docs:

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

Successfully merging a pull request may close this issue.

3 participants