这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@brettfo
Copy link
Member

@brettfo brettfo commented Aug 28, 2019

This PR mimics the PocketViewTags helper items for F#. Since F# doesn't have dynamic invocation in the same way that C# does, I had to do things a little differently, but the end result is largely the same. The easiest approach is to simply show C#/F# equivalent pairs.

C#:

div[id: 1, @class: "someClass"]("body")

F#

div.["id", 1].["class", "someClass"].HTML("body")

Result:

<div id="1" class="someClass">body</div>

In action:
image

abstract member HTML: obj -> FSharpPocketViewTags
abstract member Item: string * obj -> FSharpPocketViewTags with get
default __.HTML content =
p.SetContent([|content|])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a method ToHtmlContent that you can use to implement this without involving PocketView. PocketViewTags.HTML actually probably belongs with the methods under Microsoft.DotNet.Interactive.Kernel and the whole thing should probably move into Microsoft.DotNet.Interactive.Jupyter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow. If in C# I do div("foo") that will call TryInvoke which internally just calls SetContent() and the body of that method does all of the fancy HTML escaping and encoding.

The ToHtmlContent() methods that I found only operate on string, so I don't know how I would apply that in the F# case. E.g.,

let content = "foo".ToHtmlContent() // this is now of the type `IHtmlContent`
div.<what_do_I_put_here_so_that_I_can_pass_in_content_from_above>(content)

This is made doubly difficult in that F# doesn't have dynamic and we're so strongly typed that it's sometimes painful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comment was only about the HTML method, which is unrelated to PocketView, and doesn't require dynamic.

    public static IHtmlContent HTML(string content) => content.ToHtmlContent();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example? Do you mean this?

-default __.HTML content =
-    p.SetContent([|content|])
+default __.HTML (content: string) =
+    p.SetContent([|content.ToHtmlContent()|])

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm suggesting we remove HTML from PocketViewTags and move it to someplace where it can be called directly from F# submissions. It doesn't need an F# wrapper or alternate implementation. It belongs in the same class with display and Javascript.

Copy link
Member Author

@brettfo brettfo Aug 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I see the confusion.

I'm simply trying to get around the fact that an F# object can't be directly invoked. E.g., this doesn't work:

div.["class", "c"]("body")
//                ^^^^^^^^ this fails because
//  ^^^^^^^^^^^^^^         this isn't a function

So we have to have an actual function that can be invoked:

div.["class", "c"].HTML("body")
//                 ^^^^ this IS a function and it CAN be invoked

Originally I called this innerHTML to mimic the HTML DOM, but then I found HTML() on PocketViewTags and thought I'd mimic that. Ultimately I don't care what this is called; the only restriction is that it has to exist.

Is there a name you'd prefer, or is HTML (or innerHTML) fine?


Quick edit:

The display and Javascript methods you mentioned feel like the wrong place for this, at least for F#, because the API would look like this and it feels clunky:

a.["href", "bing.com"].HTML("Click for bing!") // this is the current state in this PR
content(a.["href", "bing.com"], "Click for bing!") // this feels terrible
a.["href", "bing.com"].content("Click for bing!") // having `content` be an extension method feels acceptable, see below

If content() is an extension method then the API would have to look like this to be consumable by F#:

public static object content(this FSharpPocketViewTags tags, object body)
{
    tags.somehow_we_get_access_to_the_underlying_PocketView_value.SetContent(body);
}

And if we need an explicit overload just for F#, I'd rather leave it as it is in this PR; a dedicated method directly tied to the FSharpPocketViewTags class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spoke offline with @jonsequitur and @TIHan and long story short I mis-read the meaning of the HTML() method. To try to make the meaning clear I'm copying the DOM method name innerHTML().

There were other discussions about utilizing a constructor to set the inner content, but that opens a whole new can of worms around using the helper effectively.

@brettfo brettfo merged commit 3c945fa into dotnet:master Aug 29, 2019
@brettfo brettfo deleted the fsharp-html branch August 29, 2019 23:53
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 this pull request may close these issues.

3 participants