bajaux Tips and Tricks
Templating methods
Over the introductory tutorials, we mainly used Handlebars for templating HTML. Handlebars is certainly a solid, well-supported choice. Here are some aspects of Handlebars that may make it a good fit, or a poor fit, for your particular use case:
- The HTML is kept in a separate file, apart from your JavaScript.
- Escaping (see below) is automatically handled for you.
- The logic you may embed in a template (for loops, if statements, etc.) is very limited.
- HTML contents of elements are parsed as a string. If you are creating a large number of elements (tens of thousands or more), this can harm performance.
Here are a couple alternatives you might consider.
ES6 Template Strings
You can simply use template strings, which are part of JavaScript itself, to build out your HTML.
class MyWidget extends Widget {
doLoad(component) {
this.jq().html(`
<table>
${ component.getSlots().toArray()
.map((slot) => `<tr><td>${ _.escape(slot.getName()) }</td></tr>`)
.join('') }
</table>
`);
}
}
This way, the HTML is kept right in line with your JavaScript. You also have a lot more flexibility in terms of logic, since you are generating the HTML with JavaScript itself.
The downsides are again that the HTML is parsed as a string, which may have performance implications, and escaping is not handled for you, so you must be diligent about protecting yourself from XSS.
spandrel.jsx
By using the Building Composite Widgets With spandrel module, you can use JSX to define your widgets.
/** @jsx spandrel.jsx */
const MyWidget = spandrel((component) => {
return (
<table>{
component.getSlots().toArray().map((slot) => {
return (
<tr>
<td>{slot.getName()}</td>
</tr>
);
})
}</table>
);
});
(Keep in mind that JSX is not React and this does not turn your bajaux Widget into a React component.)
This approach, again, keeps your HTML right in line with your JavaScript and allows for any JavaScript logic you wish. The JSX compiles to JavaScript and native HTMLElements, so at scale, performance can beat parsing HTML as strings. JSX itself also handles the XSS-escaping of the text content of elements for you.
Anecdotally, Tridium has been using spandrel.jsx almost exclusively for several releases now, so it may be a good fit for your use case as well.
Escaping HTML for safety
When implementing a bajaux Widget, you must take care to ensure that any content that could be user-generated is correctly escaped to protect your users from reflected XSS attacks.
A reflected XSS attack could occur when a user of your station, who has limited write permissions, injects malicious JavaScript into the part of the station where they can write to. Another user with elevated permissions could then access that same part of the station, where a vulnerable Widget would cause that code to execute using their own permissions. In this way, the limited user could execute code using another user's elevated permissions, damaging the station or stealing information.
Whenever you display user-generated text, you must ensure that it is correctly escaped to prevent it from being added to the page as code.
Some examples of potentially user-generated text are:
- The names or display names of Components or their Slots
- Slot Facets
- The values of Component properties that are Strings, or displayed as Strings
- Values retrieved from the station via RPC (e.g.
baja.rpc()), BQL queries, etc. - Contents of files, which may be editable by users with write permissions to the file space
- Text retrieved from lexicons, which may be parameterized to include values from the station's Component Space
Any of these can contain information that was placed into the station by a user.
Some examples of methods of escaping this data for safe display are:
- Using
jQuery.text()instead ofjQuery.html() - Setting an
HTMLElement'stextContentinstead of itsinnerHtml - Using Handlebars templating
- Using
spandrel.jsx - Manually escaping HTML using
_.escape()or a similar JavaScript function