What HTML processing is used on observablehq? - javascript

I just read up on the changes in d6.js version 6 and stumbled across this d3.groups() example on observablehq.com.
There, I saw the following code snippet to create an HTML table from the Map athletesBySport:
html`<table>
<thead>
<tr><th>Sport</th><th>Athletes</th></tr>
</thead>
<tbody>${Array.from(athletesBySport, ([key, values]) => html`
<tr>
<td>${key}</td>
<td>${values.map(d => d.name).join(", ")}</td>
</tr>`)}</tbody>
</table>`
What kind of "markup" / HTML processing is this? Some special patterns that I can detect are
hmtl`...`
and the
$
sign which seems to allow to execute a script that generates inline html.

The answer to this question can be found here, in Observable's standard library. This introduction also explores the standard library.
The
html`...`
part is "just" a JavaScript tagged template literal, i.e., a JavaScript template literal that is parsed with a specific method.
From Observable's documentation:
html`string`
Returns the HTML element represented by the specified HTML string literal. This function is intended to be used as a tagged template literal. Leading and trailing whitespace is automatically trimmed. For example, to create an H1 element whose content is “Hello, world!”:
html`<h1>Hello, world!`
The documentation further states how expressions embedded with $ are handled:
If an embedded expression is a DOM element, it is embedded in generated HTML. For example, to embed TeX within HTML:
html`I like ${tex`\KaTeX`} for math.`
If an embedded expression is an array, the elements of the array are embedded in the generated HTML.
There are more tagged literals availabe in Observable, such as svg, md for markdown, tex for LaTex, and more.

Related

Javascript custom template engine

I'm trying to create a custom template engine in javascript but I'm having trouble getting started as I cannot extract tokens using regex.
Here are the requirements:
Variables are defined like this: $(variable)
Functions: $(name arg1 "this is arg2 but it contains whitespaces.")
Function arguments can contain other variables $(name $(variable) arg2)
Both variables and functions will be rendered async. For example: Get the value for $(variable) from db then replace it.
This is not for rendering an html page but to simply replace a string entered by a user on the backend.
Edit
More information:
Suppose a user enters the following string:
$(id $(lowercase John))
On the backend application must do:
Convert "John" to lowercase.
Get the id for "john" from db.
This is only a simple example to demonstrate how this should work.
Are there any libraries that can help me achieve this? If not, any idea how to implement this?
EDIT 2:
I tried using Mustache and I changed the delimiters to $(), however the function (section) tags do no satisfy the requirements. In Mustache, for functions I must do this: $(#name) $(variable) "this is arg2 but it contains whitespaces."$(/name) also it does not support async rendering.
If not, any idea how to implement this?
You should use an Abstract Syntax Tree, and write a compatible parser. While regex (as Pedro Lima stated) is good for simple templating, if you ever want to extend the parser, you'll need something a bit more robust.
As an example of an Abstract Syntax Tree parser, $(test1 $(test2) test3) lorem ipsum $(test4) would be turned into the following:
(Thanks to Mile Shang's Syntree for the tree generator.)
As for specifically how to write a parser, I think you can figure it out. Just iterate over the string and check for the template delimiter. Reading the source code for a templating library like Handlebars might help.
Here. This regex will identify the templates that can be replaced. Note that it only selects the innermost templates in nested templates.
/\$\((?<FirstTerm>\S+?)(?<OtherTerms>(?:\s+(?:\w+|".*?"))+)?\)/g
So just use a regex replace function with your templating logic recursively until there are no more matches. The inner templates will be replaced and you'll be left with the string with templates replaced.
Other answers on this post are correct, however, I want to share exactly how I managed to implement this:
Create a recursive match function. I used Steven Leviathan's article to implement this.
Create a render function and inside the function call the recursive match function to find and replace variable/function names with appropriate values.
Keep calling the render function recursively until all arguments inside a function have been replaced.

Using a string as input with reactDOM.render, marked.js and babel

So I am attempting to build a git markdown previewer using React, babel and marked.js. Marked.js is a markdown parser.
So say I have a value that I want to use from my html.
<div id="markdownInput"># This is my input</div>
In javascript, I store it as the variable myInput.
var myInput = document.getElementById("markdownInput").value;
myInput is now "# This is my input" and is a string. Marked.js uses a function called "marked()" that takes a string as input and converts the git markdown to html.
var myOutput = marked(myInput);
myOutput is now equal to:
"<h1>This is my input</h1>"
Notice that the markdown is converted (# =>h1) but it is also stored as a string. If I attempt to use this with reactDOM.render like so:
ReactDOM.render(myOutput, document.getElementById("output-container"));
My "output-container" in my HTML ends up with displaying:
<h1>This is my input</h1>
rather than displaying "This is my input" in large header letters. What it boils down to is that React.DOM.render() needs an object as input and not a string. It needs:
<h1>This is my input</h1>
As an object but I am inputting it as a string because the marked() function only outputs as a string (which wraps everything in quotes).
Is there anything that I can do to convert myOutput to an object? I am extremely knew to React so perhaps I haven't learned a better method for something like this.
Thanks
Well, found this Using marked in react and used the "dangerouslySetInnerHTML" attribute. Is there perhaps a better way to do this though?

JDBC in Google Script "&" to "&"

When getting the values from MySql database in Google Spreadsheets using JDBC service and I get the ampersand character as & instead of &. I would like to know how should I make the call so I directly get & as value.
I am using the following connection: "jdbc:mysql://ip:port/server?useUnicode=true&characterEncoding=UTF-8". Also, I am using rs.getString() method to take the data from the query.
Thanks a lot!
I am not sure where you are outputting your data, but this is usually a cause:
In HTML, the ampersand character (“&”) declares the beginning of an
entity reference (a special character). If you want one to appear in
text on a web page you should use the encoded named entity “&”
This seems like a simple rule, but what about urls in HTML, javascript files, javascript in HTML, etc… Here’s a little guide to help clear up that ampersand HTML confusion:
Text in HTML:
<p>Jack & Jill ran up the hill.</p>
A link in HTML (or any HTML attribute value):
tired meme
A link in javascript:
window.location = 'http://google.com/?l=1&q=rick+roll';
If you’re using a web framework that escapes variables for you and you pass in a url as a variable into javascript, then you’ll have to make sure it doesn’t encode the ampersands. In Django, you would write something like this: window.location = '{{ url|escapejs }}';
Also, if this is inline javascript—in an HTML document, not a separate .js file—then you still shouldn’t escape the ampersand, which means the document will not validate as XHTML. Either throw it into a separate .js file or stop worrying so much about validating your code.
Inside an onclick in HTML:
<a href="#" onclick="window.location='?l=1&q=rick+roll';return false">
kablammo!
</a>
This is redundant to the second example, but worth pointing out since it’s javascript inside an attribute of an HTML tag.
Dynamically in Javascript (example using jQuery):
$('#result').text('Jack & Jill'); // .text() escapes the text for you
$('#result').html('Jack & Jill'); // .html() sets the HTML directly
document.getElementById('result').innerHTML = 'Jack & Jill';
Reference information: Click Here

Render XML data with ReactLayout

The XML data in PhoneCallResponse does not appear in the generated HMTL.
Probably because React uses XML for its components.
Is there a special way to handle this?
PhoneCallResponse = React.createClass({
render() {
return (
<Response>
<Say voice="alice">
Thanks for the call. Configure your number's voice U R L to change this message.
</Say>
<Pause length="1"/>
<Say voice="alice">
Let us know if we can help you in any way during your development.
</Say>
</Response>
);
}
});
FlowRouter.route('/twilio/', {
action: function() {
ReactLayout.render(Layout, {
content: <PhoneCallResponse />
});
}
});
React reasons with JSX (it's not XML!) this way: Capital letter at the start of the tag indicates a React component. Lowercase tags are rendered straight out as DOM elements without further computation. At the end of the day, React renders HTML views, not XML.
Your code will cause a reference error, as neither Response, Say or Pause are defined components. The reason is the way JSX is transpiled before React ever does anything: JSX tags with a capital letter are treated as components. So <Response></Response> will be converted to React.createElement(Response, {}, null), and if Response isn't a valid React component within the scope, the javascript engine will complain, and everything crashes. Lowercase tags however are treated as strings, and React will simply render an HTML tag <response></response>
If you insist on mixing XML in with your HTML, or your goal is to render an XML document, then use lowercase tags or dangerouslySetInnerHTML which is the React way of injecting strings in the DOM. Keep in mind however that HTML5 is not XML in the way that XHTML was, and XHTML is more or less dead. Standard compliant custom tags these days follow the pattern <x-custom-tag>, <x-another-custom-tag> and so forth, just to make sure you avoid any name collision that might be caused by new tags in a future HTML standard.
On a side note: React plays well with HTML5 custom elements and shadow DOM. Sadly, this part of the HTML standard is very "work in progress", and apparently miles away from being ready to use, but as of Chrome version 49 this example should demonstrate the general idea: https://jsfiddle.net/dannyjolie/je8pmazk/.

Dynamic Unicode Generation into the DOM

I have a function linking to a method for a JavaScript library I'm working on. Basically taking romanized Korean and converting it to specific Unicode sequences and re-inserting it into the DOM. The resulting strings that it generates are correct, but the re-insertion back into the DOM seems off...
For example: If I have the following in my DOM:
<ko>hangug-eo</ko>
The function is meant to convert it accordingly, replacing hangug-eo with 한국어 to show on the browser:
한국어 within the <ko> tags...
The function that does the string setting within the DOM is as follows:
function (){
var z=document.getElementsByTagName('ko');
for(x=z.length;x--;){
z[x].childNodes[0].data=kimchi.go(z[x].childNodes[0].data);
}
}
However, it seems that all this seems to be doing is just placing the &# Unicode entities straight into the DOM without it converting to their respective character equivalents... So all I'm seeing is 한국어
Can anyone please point out what I may be doing wrong?
kimchi.go() is the function that ultimately provides the Unicoded string...
You can always just set the text directly using textContent without having to use HTML entities:
z[x].textContent = '한국어';
But if you need to use HTML entities, just use innerHTML instead
z[x].innerHTML = kimchi.go(z[x].childNodes[0].data);
You can see the latter in the example below.
https://jsfiddle.net/nmL3to8w/1/

Categories

Resources