How to Pass a String Containing Markdown to Custom View

Can I pass a string containing markdown to custom view?

The formatting markdown "magic" comes from this initialiser of Text, which takes a LocalizedStringKey. Since LocalizedStringKey conforms to ExpressibleByStringLiteral, Text("*Inline*") will call this initialiser, but Text(someStringVariable) will not.

So to format the markdown in the text property, you just need to call that initialiser. You can either make text a LocalizedStringKey itself:

struct MyTest: View {
let text: LocalizedStringKey

init(_ text: LocalizedStringKey) { self.text = text }

var body: some View {
Text(text)
Text("*Inline*")
}
}

Or create a LocalizedStringKey when creating the Text:

Text(LocalizedStringKey(text))

By using this initialiser of Text, you get the added benefit of localising the text! :D

How to show HTML or Markdown in a SwiftUI Text?

Text can just display Strings.
You can use a UIViewRepresentable with an UILabel and attributedText.

Probably attributedText text support will come later for SwiftUI.Text.

How to parse a small subset of Markdown into React components?

How it works?

It works by reading a string chunk by chunk, which might not be the
best solution for really long strings.

Whenever the parser detects a critical chunk is being read, i.e. '*' or
any other markdown tag, it starts parsing chunks of this element until the
parser finds its closing tag.

It works on multi-line strings, see the code for example.

Caveats

You haven't specified, or I could have misuderstood your needs, if there's
the necessity to parse tags that are both bold and italic, my current
solution might not work in this case.

If you need, however, to work with the above conditions just comment here
and I'll tweak the code.

First update: tweaks how markdown tags are treated

Tags are no longer hardcoded, instead they are a map where you can easily extend
to fit your needs.

Fixed the bugs you've mentioned in the comments, thanks for pointing this issues =p

Second update: multi-length markdown tags

Easiest way of achieving this: replacing multi-length chars with a rarely used unicode

Though the method parseMarkdown does not yet support multi-length tags,
we can easily replace those multi-length tags with a simple string.replace
when sending our rawMarkdown prop.

To see an example of this in practice, look at the ReactDOM.render, located
at the end of the code.

Even if your application does support multiple languages, there are invalid
unicode characters that JavaScript still detects, ex.: "\uFFFF" is not a valid
unicode, if I recall correctly, but JS will still be able to compare it ("\uFFFF" === "\uFFFF" = true)

It might seems hack-y at first but, depending on your use-case, I don't see
any major issues by using this route.

Another way of achieving this

Well, we could easily track the last N (where N corresponds to the length
of the longest multi-length tag) chunks.

There would be some tweaks to be made to the way the loop inside method
parseMarkdown behaves, i.e. checking if current chunk is part of a multi-length
tag, if it is use it as a tag; otherwise, in cases like ``k, we'd need
to mark it as notMultiLength or something similar and push that chunk as
content.

Code

// Instead of creating hardcoded variables, we can make the code more extendable
// by storing all the possible tags we'll work with in a Map. Thus, creating
// more tags will not require additional logic in our code.
const tags = new Map(Object.entries({
"*": "strong", // bold
"!": "button", // action
"_": "em", // emphasis
"\uFFFF": "pre", // Just use a very unlikely to happen unicode character,
// We'll replace our multi-length symbols with that one.
}));
// Might be useful if we need to discover the symbol of a tag
const tagSymbols = new Map();
tags.forEach((v, k) => { tagSymbols.set(v, k ); })

const rawMarkdown = `
This must be *bold*,

This also must be *bo_ld*,

this _entire block must be
emphasized even if it's comprised of multiple lines_,

This is an !action! it should be a button,

\`\`\`
beep, boop, this is code
\`\`\`

This is an asterisk\\*
`;

class App extends React.Component {
parseMarkdown(source) {
let currentTag = "";
let currentContent = "";

const parsedMarkdown = [];

// We create this variable to track possible escape characters, eg. "\"
let before = "";

const pushContent = (
content,
tagValue,
props,
) => {
let children = undefined;

// There's the need to parse for empty lines
if (content.indexOf("\n\n") >= 0) {
let before = "";
const contentJSX = [];

let chunk = "";
for (let i = 0; i < content.length; i++) {
if (i !== 0) before = content[i - 1];

chunk += content[i];

if (before === "\n" && content[i] === "\n") {
contentJSX.push(chunk);
contentJSX.push(<br />);
chunk = "";
}

if (chunk !== "" && i === content.length - 1) {
contentJSX.push(chunk);
}
}

children = contentJSX;
} else {
children = [content];
}
parsedMarkdown.push(React.createElement(tagValue, props, children))
};

for (let i = 0; i < source.length; i++) {
const chunk = source[i];
if (i !== 0) {
before = source[i - 1];
}

// Does our current chunk needs to be treated as a escaped char?
const escaped = before === "\\";

// Detect if we need to start/finish parsing our tags

// We are not parsing anything, however, that could change at current
// chunk
if (currentTag === "" && escaped === false) {
// If our tags array has the chunk, this means a markdown tag has
// just been found. We'll change our current state to reflect this.
if (tags.has(chunk)) {
currentTag = tags.get(chunk);

// We have simple content to push
if (currentContent !== "") {
pushContent(currentContent, "span");
}

currentContent = "";
}
} else if (currentTag !== "" && escaped === false) {
// We'll look if we can finish parsing our tag
if (tags.has(chunk)) {
const symbolValue = tags.get(chunk);

// Just because the current chunk is a symbol it doesn't mean we
// can already finish our currentTag.
//
// We'll need to see if the symbol's value corresponds to the
// value of our currentTag. In case it does, we'll finish parsing it.
if (symbolValue === currentTag) {
pushContent(
currentContent,
currentTag,
undefined, // you could pass props here
);

currentTag = "";
currentContent = "";
}
}
}

// Increment our currentContent
//
// Ideally, we don't want our rendered markdown to contain any '\'
// or undesired '*' or '_' or '!'.
//
// Users can still escape '*', '_', '!' by prefixing them with '\'
if (tags.has(chunk) === false || escaped) {
if (chunk !== "\\" || escaped) {
currentContent += chunk;
}
}

// In case an erroneous, i.e. unfinished tag, is present and the we've
// reached the end of our source (rawMarkdown), we want to make sure
// all our currentContent is pushed as a simple string
if (currentContent !== "" && i === source.length - 1) {
pushContent(
currentContent,
"span",
undefined,
);
}
}

return parsedMarkdown;
}

render() {
return (
<div className="App">
<div>{this.parseMarkdown(this.props.rawMarkdown)}</div>
</div>
);
}
}

ReactDOM.render(<App rawMarkdown={rawMarkdown.replace(/```/g, "\uFFFF")} />, document.getElementById('app'));

Link to the code (TypeScript) https://codepen.io/ludanin/pen/GRgNWPv

Link to the code (vanilla/babel) https://codepen.io/ludanin/pen/eYmBvXw

How can I wrap my markdown in an HTML div?

Markdown

For Markdown, This is by design. From the Inline HTML section of the Markdown reference:

Note that Markdown formatting syntax is not processed within block-level HTML tags. E.g., you can’t use Markdown-style emphasis inside an HTML block.

But it is explicitly allowed for span-level tags:

Unlike block-level HTML tags, Markdown syntax is processed within span-level tags.

So, depending on your use-case, you might get away with using a span instead of a div.

CommonMark

If the library you use implements CommonMark, you are lucky. Example 108 and 109 of the spec show that if you keep an empty line in between the HTML block and the markdown code, the contents will be parsed as Markdown:

<div>

*Emphasized* text.

</div>

should work, while the following shouldn't:

<div>
*Emphasized* text.
</div>

And, again according to the same section in the reference, some implementations recognize an additional markdown=1 attribute on the HTML tag to enable parsing of Markdown inside it.

Though it doesn't seem to work in StackOverflow yet:

Testing **Markdown** inside a red-background div.

How to link to part of the same document in Markdown?

In pandoc, if you use the option --toc in producing html, a table of contents will be produced with links to the sections, and back to the table of contents from the section headings. It is similar with the other formats pandoc writes, like LaTeX, rtf, rst, etc. So with the command

pandoc --toc happiness.txt -o happiness.html

this bit of markdown:

% True Happiness

Introduction
------------

Many have posed the question of true happiness. In this blog post we propose to
solve it.

First Attempts
--------------

The earliest attempts at attaining true happiness of course aimed at pleasure.
Soon, though, the downside of pleasure was revealed.

will yield this as the body of the html:

<h1 class="title">
True Happiness
</h1>
<div id="TOC">
<ul>
<li>
<a href="#introduction">Introduction</a>
</li>
<li>
<a href="#first-attempts">First Attempts</a>
</li>
</ul>
</div>
<div id="introduction">
<h2>
<a href="#TOC">Introduction</a>
</h2>
<p>
Many have posed the question of true happiness. In this blog post we propose to solve it.
</p>
</div>
<div id="first-attempts">
<h2>
<a href="#TOC">First Attempts</a>
</h2>
<p>
The earliest attempts at attaining true happiness of course aimed at pleasure. Soon, though, the downside of pleasure was revealed.
</p>
</div>

How to add new line in Markdown presentation?

See the original markdown specification (bold mine):

The implication of the “one or more consecutive lines of text” rule is that Markdown supports “hard-wrapped” text paragraphs. This differs significantly from most other text-to-HTML formatters (including Movable Type’s “Convert Line Breaks” option) which translate every line break character in a paragraph into a <br /> tag.

When you do want to insert a <br /> break tag using Markdown, you end a line with two or more spaces, then type return.

Passing Parameters to R Markdown

In my case it worked, just had to change the indentation in the header and some names which are available in my folder...

Here my jnk.Rmd

---
title: "Liquidity Report"
output: pdf_document
params:
client: "NAMESPACE"
---
```{r plot, echo=FALSE, warning=FALSE}
cftest <- read.csv(params$client)
```

And this is what I called in the console : render('jnk.Rmd',params= list( client= "NAMESPACE"))

How to pass variable to markdown? laravel mail

I eventually got the solution, by using the compact, instead of an array. I changed this line below, and everything works normal.

->markdown('emails.reset', compact('email'))

credits to @sibongisenimsomis from laracasts

Apparently passing variables to Markdown from Notification class works, differently. I used compact on my solution, after struggle for about an hour cause I was referring to another example which was using with, on a Mailable class.

https://laracasts.com/discuss/channels/laravel/passe-some-variables-to-the-markdown-template-within-a-notification

How to render string literal with html tags in django?

Just add safe template tag like @markwalker_ said in comments it will turn off autoescape of html tags.

 <p>{{ context|safe }}</p>


Related Topics



Leave a reply



Submit