Gatsby Use plain html with frontmatter as source - reactjs

I am migrating from a handlebars based static site generator. Authors of pages are allowed to use either html or markdown. Therefore i have lots of partial html files for which i need to create pages. These html files are in fact .hbs file (handlebars), but there are no expressions, just plain html element with some frontmatter.
For example:
---
title: Example
author: Narendra
---
<div>
<h1>Example</h1>
<p> .. </p>
</div>
Authors are able to drop these files inside a directory structure.
I have not been able to find a transformer that can deal with such file. Am i missing something? Do i need to create a custom transformer for this.

AFAIK markdown is a superset of html, so gatsby-transformer-remark should be able to handle these .hbs.
Unfortunately there's no way that I know to make gatsby remark accept .hbs extension, but I think renaming them should do the trick.

Related

With Hugo, can we use HTML code in a md file?

With Hugo, I am writing some HTML5 as Goldmark markdown doesn't support CSS classes or IDs.
My code is in post1.md :
<h2 data-toggle="collapse" data-target="#collapse-definition" aria-expanded="false" aria-controls="collapse-definition">Définition</h2> is not compiled and is not compiled to HTML.
Even the simplest div markup is omitted.
Thanks for your help.
From version 0.6, Hugo uses Goldmark for markdown.
For security reasons, Goldmark wipes HTML code.
However, if you use HTML frequently in your site, you can add to your config.toml
[markup.goldmark.renderer]
unsafe = true # Allow HTML in md files
For a less frequent usage of HTML, you can add safeHTML parameter to your HTML string (Hugo doc for safeHTML).

React - don't parse certain HTML tags in dangerouslySetInnerHTML

So I'm building a chat system in React. Ideally, things like <strong> or <em> or <h2> would be parsed correctly, and formatted at such. However, I'd like things like <link> or <script> to just be displayed as text (for formatting and security reasons, of course).
Is there a way to pick which HTML tags I'd like to parse, and which to ignore?
Use a battle-tested library like DOMPurify to strip out all tags/attributes you don't want to allow. As Patrick says, do not attempt to roll your own using regex.

React : best way to inject Component in dynamically loaded HTML?

I'm new on React (I more at ease w/ jQuery or AngularJS). I have a special case and I don't find a good way to resolve it...
My app contains an area which is like a "document viewer". It loads an HTML content from the backend (via API, using Fetch) and inject it in the "viewer" component. The HTML content loaded looks like an "university report" (it's just a formatted text, only <span> and <p> with class="..." attributes, nothing more).
Ex : <p>Lorem ispum <span>some text</span> loreb bis <span>ipsum</span></p> ...
I load the content, and inject it this way in the render() of my component <Viewer> :
<div dangerouslySetInnerHTML={ getFreshlyLoadedHTML() } />
Easy, it works just fine !
But... Now, I want to inject some "interactive" components in the loaded HTML. For example, some button to give a feedback etc. The API must decide where to place the component between the words/nodes of the formatted text (HTML).
Ex :
<p> Lorem ispum <span>some text</span>
loreb bis <span>ipsum</span>
<MyFeedbackButton paragraph="1.3"/>
</p><p>Other Lorem Ipsum<p><span>...</span>
There, I'm stucked because I cannot use dangerouslySetInnerHTML if there are components inside the loaded HTML...
First attempt : I've tried modifying the API, and instead of sending the HTML in a string to the app, I send a custom JSON structure that represents almost the final JSX structure that I want. Then, in my react page, the render function only have to parse the JSON and build the JSX (here, a JsFiddle example if it's not clear : https://jsfiddle.net/damienfa/69z2wepo/34536/ )
It works, but I can't believe it's the good way...
I see a major problem : all the HTML node (span, p...) that I build from the render function are referenced by reactJs, is it really necessary ? Mostly, there are "dead" nodes (I mean, dom node that won't never changed, this is static formatted text).
Just take a look a all those "data-reactid" on nodes that never will be interactive...
What would be your advice on that case ?
What about my attempt with a JSON-structure sent by the API ?
Is there a way to say to react "do not reference that element" ?
Do you clearly see a better solution to my problem ?
Your current workflow is not very secure and subject to many potential errors and open doors, especially concerning code injection ...
The overload due to react tracking the nodes is not an issue, React could track 10 000 nodes and not have a problem (well actually on many of my apps React has more than 100 000 nodes to care about and it still rurns perfectly).
I see different solutions here:
If there are only 3 or 4 possibilities of dynamic components and order, you might have components like "templates" to which you would simple send text arguments. This is the safest and easiest option.
If it doesn't suit your use-case but the JSON file can contain only a limited set of components, the components should be located in your main app, and then rendered with custom props from the JSON. Actually given the structure of data you could consider using xml instead of json and build a xml tree that you would parse and render. Only components from your white list would be rendered and it would limit drastically the potentials security issues. If needs quite some work on the XML parser though.
If the JSON file can contain many many different and unpredictable components or if the behaviour of those components is largely dynamic and independant of your app, you might as well consider using an iframe, with its own JS and HTML, so that this part of the code is isolated from the rest.
Try using an inline anonymous function within the inner content from within React using JSX. It works! Just be careful about how you wire up the data so there isn't a route where a user can inject HTML from an input or text field.
<div className="html-navigation-button">{(() =>
{
const CreateMarkup = ( sNavItemName :string ) => {
return {__html: sNavItemName };
}
var sTextToAddHtmlTo = props.nextNavItem.name.toString();
sTextToAddHtmlTo = sTextToAddHtmlTo.replace( "/", "/<wbr>" );
return (
<div dangerouslySetInnerHTML={CreateMarkup( sTextToAddHtmlTo )} >
</div>
);
})()}
</div>
I didn't override the React internals of 'render()', but only used a React Component with props wiring to pass down data to it for rendering.
I added the hook for 'dangerouslySetInnerHTML' deep within the return content of the React Component so there would be no easy way to intercept and manipulate it.
As such, there is no 100% guarantee on safety, but that's where adding good security to web services, databases, and use of CORS and CORB would be helpful to lock down security risks.

how to access Hugo's template variables in a javascript file?

I'm trying to use react.js in Hugo. I know Go template variables are accessible in HTML file.
My question is how to access them in javascript. or is there a workaround?
thanks in advance.
UPDATE:
currently my workaround is to use meta tags in HTML and load Go template variables like this:
<meta name="title" content={{.Title}} />
and then in javascript,
function getMetaTitle() {
var metas = document.getElementsByTagName('meta');
for (i=0; i<metas.length; i++) {
if (metas[i].getAttribute("name") == "title") {
return metas[i].getAttribute("content");
}
}
return "failed to access...";
}
var metaTitle = getMetaTitle();
but this way is inconvenient when the number of meta tags growing, is there a more concise way to do this?
I doubt Hugo and React is a good pair but that's off topic and I might be wrong about that. You are asking, how to get Hugo variables into website's JavaScript. My answer:
Hugo is static website engine, so it only converts templates and markup documents (with your content) into HTML files. Now, when you upload your files onto your server, your JS cannot see anything Hugo — only your files.
The question becomes, how to transfer Hugo variables into some files of your website.
As you suggested, it's best to write variables into your HTML (or JSON) using Hugo, then read them by JS. If it's small amount, use attributes or tags. If there's a lot and it doesn't differ per-page, use a separate JSON file.
For example, personally I have a multilingual site which a) requires different language titles to appear dynamically via JS; b) uses JS which queries different Lunr.js search indexes in JSON format.
For both I use data-<name> attributes:
<section class="section-search" data-index="{{ .Site.BaseURL }}searchIndex.json" id="section-search">
<input type="search" id="search-input" placeholder="{{ ( index $.Site.Data.translations $.Site.Params.locale ).dataloading }}" data-loaded="{{ ( index $.Site.Data.translations $.Site.Params.locale ).dataloaded }}">
<!-- search button goes here -->
</section>
For example, on English templates (rendered into /public/), data-loaded attribute would be in English, but for Lithuanian templates (rendered into /public/lt/), data-loaded attribute would be in Lithuanian.
I wouldn't worry about "growing meta tags", but you could maybe write variables into a JSON file and then read it in JS if you are concerned about HTML bloat?
I'm building custom JSON first as HTML, then minifying/renaming it into JSON when building indexes for Hugo Lunr search as per this recipe. Instead of "baking in" the content with range as in mentioned recipe, you could simply list all the variables.
By the way, I'm using npm scripts as a build runner (instead of Grunt/Gulp) so I use json-minify:
"index:prepare": "json-minify public/json/index.html > public/site-index.json",
You could "bake" JSON files with any content (including Hugo template variables) via Hugo this way. Hope it helps.
You can specify a custom output format for Javascript within your config.toml so that Hugo then treats those particular formats and file extensions like it's content files where it replaces the template variables with adequate values.
So, an entry such as below in your config.toml will treat javascript files as one of the media type it needs to consider for its custom output formats:
[mediaTypes]
[mediaTypes."application/javascript"]
suffix = "js"
You can read more about it here
You can, of course, inline your JS in your layout files, but that is probably not what you want.
There have been some discussions about improvements in this area on the Hugo discussion site, but nothing concrete yet.

ngSanitize does not allow allow id attribute

I am using ngBindHtml to display some HTML from an (internal) CMS:
<span ng-bind-html="cmsHtml"></span>
The HTML contains a link with an id attribute:
"<a id='fsgPdfLink' href='http://blah/download.pdf' target='_blank'>Click here to download the PDF</a>"
However, I notice that the id attribute is removed by angular before writing the link to the page, so what gets rendered is just:
<a href='http://blah/download.pdf' target='_blank'>Click here to download the PDF</a>
Looking at the source for the ngSanitize module, it seems that for some reason the id attribute is not on the list of valid attributes:
https://github.com/angular/angular.js/blob/master/src/ngSanitize/sanitize.js#L206
What's the reason for not allowing the id attribute? Is it a security risk?
I'd really like to continue to use ngBindHtml if possible. Is there an API where I can add safe tags to the sanitizer's list? Or do I have to edit the source myself to add this tag?
To partially answer my own question, there doesn't seem to be an API to change the built-in whitelist, as described in this open issue:
https://github.com/angular/angular.js/issues/5900

Resources