Copyright (C) 2017-2020 The Open Library Foundation
This software is distributed under the terms of the Apache License, Version 2.0. See the file "LICENSE" for more information.
This is a NPM module to aid with embedding the Quill editor in Stripes applications for building templates with token substitution.
In any case where a user-created HTML string will be rendered directly to the UI, it should be sanitized to eliminate any issues with malformed tags/attributes. This library exports a sanitize function that should be used within the ui-module prior to passing the value to the form. The function accepts the value to be rendered and an optional overriding configuration for the sanitization library. It will return the sanitized string if any removals were necessary, otherwise it will return the original parameter value.
import { sanitize, TemplateEditor } from '@folio/stripes-template-editor'
const value = persistedValue // value obtained from backend...
const appliedValue = sanitize(value);
<Form initialValues={{ template: appliedValue }}>
<Field component="TemplateEditor">
</Form>
If the sanitization needs to be adjusted for specific use-cases, it can be imported and extended...
import { SANITIZE_CONFIG } from '@folio/stripes-template-editor`;
const localConfig = { ...SANITIZE_CONFIG, ...MY_CONFIG, };
const appliedValue = sanitize(value, localConfig);
For the configuration possibilities, reference the DOMPurify configuration details if needed!
By default the preview resolves tokens with a flat regex substitution
({{token}} → value). It cannot evaluate Mustache sections, loops or
conditionals, so for templates that use them the preview does not match the
output mod-template-engine produces for the real message.
A consumer can opt in to a preview rendered by mod-template-engine itself, so
the preview becomes a true single source of truth:
import { SAMPLE_CONTEXT } from './sampleContext';
<Field
name="localizedTemplates.en.body"
component={TemplateEditor}
previewModalHeader={<FormattedMessage id="ui-foo.previewHeader" />}
previewRenderer="backend"
previewContext={SAMPLE_CONTEXT}
tokens={TOKENS}
tokensList={TokensList}
/>| Prop | Type | Default | Description |
|---|---|---|---|
previewRenderer |
'regex' | 'backend' |
'regex' |
Selects the preview renderer. 'regex' keeps the existing behaviour. |
previewContext |
object |
– | Sample context passed to the backend. Used only when previewRenderer="backend". |
previewSubject |
string |
– | Subject template, for consumers that keep the subject in a separate field. Used only when previewRenderer="backend". |
previewTemplateResolver |
string |
– | Template engine the template is stored with, e.g. 'handlebars', sent as templateResolver. Omitted, the backend falls back to mustache. Used only when previewRenderer="backend". |
The editor edits a single field (the body), so backend mode sends
{ body, context } to POST /template-request/preview and shows the rendered
body. header/body/context are all optional on that endpoint.
Pass previewSubject to have the subject rendered as well. It is sent as
header, and the preview then shows the rendered subject as a labeled line
above the body, which gets its own label. An empty string still renders the
subject line; omitting the prop sends no header and renders the body alone,
as before. The subject is shown as text, so tokens resolve but markup does not.
- The tenant must run
mod-template-engineproviding thetemplate-engineinterface2.3or later (the non-persisted/template-request/previewendpoint). The backend call is guarded by atemplate-engineinterface check (stripes.hasInterface): if the interface is absent, the preview falls back to the regex renderer — no error, no 404. The interface is declared in this library'soptionalOkapiInterfaces, so tenants withoutmod-template-engineare unaffected. - The consuming app must request the
template-request.preview.postpermission in itspackage.json.
When the backend rejects a template, the preview shows the diagnostic it returned below the generic message, followed by a short excerpt with a caret where the response points at a position. How much detail arrives depends on the template resolver; if none can be extracted, the generic message is shown on its own.
The context mirrors the nested object the backend builds for the real message
(not a flat token map). Tokens like {{organization.name}} and loops like
{{#orders}}…{{/orders}} resolve against it:
export const SAMPLE_CONTEXT = {
organization: {
name: 'Example Vendor',
primaryAddress: { city: 'Berlin', country: 'Germany' },
},
orders: [
{
order: { poNumber: '10037' },
orderLines: [
{ orderLine: { title: 'Introduction to Library Science', quantity: 2 } },
],
},
],
};The rendered HTML is sanitized before display, the same as the regex preview.
@skomorokh extracted this from ui-circulation in this commit. The code was largely written by @maximdidenkoepam and @skomorokh probably should have made more of an effort to bring the commit history along. However, you can view it at the originating module.
Other modules.
Other FOLIO Developer documentation is at dev.folio.org