Widgets in the Total.js CMS: use them in a page and write your own
A widget is a block that you place in a page: a headline, an alert, a gallery. It carries its own style, a form to configure it in the editor and, optionally, code that renders it on the server. A widget is one HTML file, like a component of Flow, and the CMS stores it in its metadata.
A widget inside a page
In the HTML of a page, a widget is a div with two attributes:
<div data-cms="headline__%7B%22h%22%3A%22h1%22%2C%22align%22%3A%22left%22%7D" data-cms-id="h1">
<h1 class="w-headline-h">Hello CMS</h1>
<p>Some text</p>
</div>data-cmsis<widget id>__<configuration>, where the configuration is a JSON object written withencodeURIComponent. The editor writes it; you can write it yourself when you generate pages.data-cms-idis the identifier of the instance in the page.
When the page is served, the CMS removes the data-cms attribute, keeps the HTML that is inside, and adds the style of every widget of the page to the head. If the widget is not installed, its block is dropped.
The parts of a widget file
| Part | What it is for |
|---|---|
<script total> | the metadata and the server code: exports.id, name, author, version, preview (an image, or a data URI), config (the defaults), and optionally dependencies, install, uninstall and render |
<style> | the CSS of the widget |
<body> | the design of the widget as the editor shows it; elements with the class CMS_edit are the editable ones; the other CMS_* classes (CMS_repeat, CMS_remove, CMS_unwrap...) are markers for the editor, and the compiler strips them before the page is served |
<settings> | the form that edits config in the editor (jComponent inputs whose path starts with ?.) and a <script> with exports.save(config, el) that changes the design when the configuration changes |
<template> | an optional template for the widget |
<readme> | the help of the widget |
CLASS in the style, the settings, the template and the design is replaced by a class that belongs to the widget (w- followed by its id), so two widgets never share a rule: in the widget alert, .CLASS-color1 becomes .w-alert-color1.
exports.dependencies accepts a list or a string separated with commas: an address ending in .js becomes a <script src> and one ending in .css a <link rel="stylesheet">, added to the head of the page.
Render on the server
A widget without exports.render is only cleaned and served as it is. With render it can build its HTML from the configuration:
<script total>
exports.id = 'hello';
exports.name = 'Hello';
exports.author = 'Me';
exports.version = '1';
exports.config = { text: 'world' };
exports.render = function(opt, next) {
next('<p class="w-hello">Hello ' + (opt.config.text || '').toUpperCase() + '</p>', true);
};
</script>
<style>
.CLASS { color: #07c; }
</style>
<body>
<p class="CLASS CMS_edit">Hello world</p>
</body>opt.config is the configuration of the instance, opt.html the HTML that was inside the block, and opt.id, opt.uid and opt.body describe it. next(html, replace) gives the HTML to serve; with true as the second argument it replaces the whole block. We saved this file in a local CMS and a page with data-cms="hello__..." and {"text":"mundo"} came out as <p class="w-hello">Hello MUNDO</p>, with .w-hello{color:#07c} in the head. The official widget picture uses the same function to add loading="lazy" to its image, and code to print the code of its settings.
exports.install and exports.uninstall run with the database of the CMS when the widget is added, changed or removed.
Install and remove widgets
The plugin Widgets of the admin imports a file; through the API it is widgets_save with { "html": "<file content>", "singleton": true } (singleton skips the widget when it already exists), widgets_list, widgets_read, widgets_detail and widgets_remove. They need the permission widgets (see the admin API). The 43 official widgets are in the widgets repository.