Skip to content

Commit bf3c1fc

Browse files
committed
Tidy rich-text-markup-transformations.md
1 parent e6d1318 commit bf3c1fc

File tree

1 file changed

+77
-111
lines changed

1 file changed

+77
-111
lines changed
Lines changed: 77 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
---
22
myst:
33
html_meta:
4-
"description": ""
5-
"property=og:description": ""
6-
"property=og:title": ""
7-
"keywords": ""
4+
"description": "How to store markup (such as HTML or reStructuredText) and render it with a transformation"
5+
"property=og:description": "How to store markup (such as HTML or reStructuredText) and render it with a transformation"
6+
"property=og:title": "How to store markup (such as HTML or reStructuredText) and render it with a transformation"
7+
"keywords": "Plone, content types, rich text, markup, and transformations"
88
---
99

10-
# Rich text, markup and transformations
10+
# Rich text, markup, and transformations
1111

12-
**How to store markup (such as HTML or reStructuredText) and render it with a transformation**
12+
This chapter describes how to store markup (such as HTML or reStructuredText) and render it with a transformation.
1313

14-
Many content items need to allow users to provide rich text in some kind
15-
of markup, be that HTML (perhaps entered using a WYSIWYG editor),
16-
reStructuredText, Markdown or some other format. This markup typically
17-
needs to be transformed into HTML for the view template, but we also
18-
want to keep track of the original “raw” markup so that it can be edited
19-
again. Even when the input format is HTML, there is often a need for a
20-
transformation to tidy up the HTML and strip out tags that are not
21-
permitted.
14+
Many content items need to allow users to provide rich text in some kind of markup, be that HTML (perhaps entered using a "What You See Is What You Get" or WYSIWYG editor), reStructuredText, Markdown, or some other format.
15+
This markup typically needs to be transformed into HTML for the view template, but we also want to keep track of the original raw markup so that it can be edited again.
16+
Even when the input format is HTML, there is often a need for a transformation to tidy up the HTML and strip out tags that are not permitted.
2217

23-
It is possible to store HTML in a standard `Text` field. You can even
24-
get a WYSIWYG widget, by using a schema such as this:
18+
It is possible to store HTML in a standard `Text` field.
19+
You can even get a WYSIWYG widget, by using a schema such as the following.
2520

26-
```
21+
```python
2722
from plone.autoform import directives as form
2823
from plone.supermodel import model
2924
from zope import schema
@@ -37,11 +32,10 @@ class ITestSchema(model.Schema):
3732

3833
(richtext-label)=
3934

40-
However, this approach does not allow for alternative markups or any
41-
form of content filtering. For that, we need to use a more powerful
42-
field: `RichText` from the [plone.app.textfield] package:
35+
However, this approach does not allow for alternative markups or any form of content filtering.
36+
For that we need to use a more powerful field, `RichText`, from the [`plone.app.textfield`](https://pypi.org/project/plone.app.textfield/) package.
4337

44-
```
38+
```python
4539
from plone.app.textfield import RichText
4640
from plone.supermodel import model
4741

@@ -50,28 +44,26 @@ class ITestSchema(model.Schema):
5044
body = RichText(title="Body text")
5145
```
5246

53-
The `RichText` field constructor can take the following arguments in
54-
addition to the usual arguments for a `Text` field:
47+
The `RichText` field constructor can take the following arguments, in addition to the usual arguments for a `Text` field.
5548

56-
- `default_mime_type`, a string representing the default MIME type of
57-
the input markup. This defaults to `text/html`.
58-
- `output_mime_type`, a string representing the default output MIME
59-
type. This defaults to `text/x-html-safe`, which is a Plone-specific
60-
MIME type that disallows certain tags. Use the {guilabel}`HTML Filtering`
61-
control panel in Plone to control the tags.
62-
- `allowed_mime_types`, a tuple of strings giving a vocabulary of
63-
allowed input MIME types. If this is `None` (the default), the
64-
allowable types will be restricted to those set in Plone’s
65-
{guilabel}`Markup` control panel.
49+
`default_mime_type`
50+
: A string representing the default MIME type of the input markup.
51+
This defaults to `text/html`.
6652

67-
Also note: The *default* field can be set to either a unicode object (in
68-
which case it will be assumed to be a string of the default MIME type)
69-
or a `RichTextValue` object (see below).
53+
`output_mime_type`
54+
: A string representing the default output MIME type.
55+
This defaults to `text/x-html-safe`, which is a Plone-specific MIME type that disallows certain tags.
56+
Use the {guilabel}`HTML Filtering` control panel in Plone to control the tags.
7057

71-
Below is an example of a field allow StructuredText and
72-
reStructuredText, transformed to HTML by default:
58+
`allowed_mime_types`
59+
: A tuple of strings giving a vocabulary of allowed input MIME types.
60+
If this is `None` (the default), the allowable types will be restricted to those set in Plone's {guilabel}`Markup` control panel.
7361

74-
```
62+
The *default* field can be set to either a Unicode object (in which case it will be assumed to be a string of the default MIME type) or a `RichTextValue` object (see below).
63+
64+
Below is an example of a field that allows StructuredText and reStructuredText, transformed to HTML by default.
65+
66+
```python
7567
from plone.app.textfield import RichText
7668
from plone.supermodel import model
7769

@@ -98,130 +90,104 @@ class ITestSchema(model.Schema):
9890
)
9991
```
10092

93+
10194
## The RichTextValue
10295

103-
The `RichText` field does not store a string. Instead, it stores a
104-
`RichTextValue` object. This is an immutable object that has the
105-
following properties:
96+
The `RichText` field does not store a string.
97+
Instead, it stores a `RichTextValue` object.
98+
This is an immutable object that has the following properties.
10699

107100
`raw`
108-
109-
: a unicode string with the original input markup;
101+
: A Unicode string with the original input markup.
110102

111103
`mimeType`
112-
113-
: the MIME type of the original markup, e.g. `text/html` or
114-
`text/structured`;
104+
: The MIME type of the original markup, for example `text/html` or `text/structured`.
115105

116106
`encoding`
117-
118-
: the default character encoding used when transforming the input markup.
119-
Most likely, this will be UTF-8;
107+
: The default character encoding used when transforming the input markup.
108+
Most likely, this will be UTF-8.
120109

121110
`raw_encoded`
122-
123-
: the raw input encoded in the given encoding;
111+
: The raw input encoded in the given encoding.
124112

125113
`outputMimeType`
126-
127-
: the MIME type of the default output, taken from the field at the time of
128-
instantiation;
114+
: The MIME type of the default output, taken from the field at the time of instantiation.
129115

130116
`output`
117+
: A Unicode object representing the transformed output.
118+
If possible, this is cached persistently, until the `RichTextValue` is replaced with a new one (as happens when an edit form is saved, for example).
131119

132-
: a unicode object representing the transformed output. If possible, this
133-
is cached persistently until the `RichTextValue` is replaced with a
134-
new one (as happens when an edit form is saved, for example).
135-
136-
The storage of the `RichTextValue` object is optimised for the case where
137-
the transformed output will be read frequently (i.e. on the view screen
138-
of the content object) and the raw value will be read infrequently (i.e.
139-
on the edit screen). Because the output value is cached indefinitely,
140-
you will need to replace the `RichTextValue` object with a new one if any
141-
of the transformation parameters change. However, as we will see below,
142-
it is possible to apply a different transformation on demand should you
143-
need to.
144-
145-
The code snippet belows shows how a `RichTextValue` object can be
146-
constructed in code. In this case, we have a raw input string of type
147-
`text/plain` that will be transformed to a default output of
148-
`text/html`. (Note that we would normally look up the default output
149-
type from the field instance.):
120+
The storage of the `RichTextValue` object is optimized for the case where the transformed output will be read frequently (for example, on the view screen of the content object) and the raw value will be read infrequently (for example, on the edit screen).
121+
Because the output value is cached indefinitely, you will need to replace the `RichTextValue` object with a new one if any of the transformation parameters change.
122+
However, as we will see below, it is possible to apply a different transformation on demand, if you need to.
150123

151-
```
124+
The code snippet belows shows how a `RichTextValue` object can be constructed in code.
125+
In this case, we have a raw input string of type `text/plain` that will be transformed to a default output of `text/html`.
126+
Note that we would normally look up the default output type from the field instance.
127+
128+
```python
152129
from plone.app.textfield.value import RichTextValue
153-
...
154130

155131
context.body = RichTextValue("Some input text", 'text/plain', 'text/html')
156132
```
157133

158-
Of course, the standard widget used for a `RichText` field will
159-
correctly store this type of object for you, so it is rarely necessary
160-
to create one yourself.
134+
Of course, the standard widget used for a `RichText` field will correctly store this type of object for you, so it is rarely necessary to create one yourself.
135+
161136

162137
## Using rich text fields in templates
163138

164-
What about using the text field in a template? If you are using a
165-
`DisplayForm`, the display widget for the `RichText` field will render
166-
the transformed output markup automatically. If you are writing TAL
167-
manually, you may try something like this:
139+
What about using the text field in a template?
140+
If you use a `DisplayForm`, the display widget for the `RichText` field will render the transformed output markup automatically.
141+
If you write TAL manually, you may try something like the following.
168142

169-
```html
143+
```xml
170144
<div tal:content="structure context/body" />
171145
```
172146

173-
This, however, will render a string like:
147+
This, however, will render a string as follows.
174148

175-
```
149+
```html
176150
RichTextValue object. (Did you mean <attribute>.raw or <attribute>.output?)
177151
```
178152

179153
The correct syntax is:
180154

181-
```html
155+
```xml
182156
<div tal:content="structure context/body/output" />
183157
```
184158

185-
This will render the cached, transformed output. This operation is
186-
approximately as efficient as rendering a simple `Text` field, since the
187-
transformation is only applied once, when the value is first saved.
159+
This will render the cached, transformed output.
160+
This operation is approximately as efficient as rendering a simple `Text` field, since the transformation is only applied once, when the value is first saved.
161+
188162

189163
## Alternative transformations
190164

191-
Sometimes, you may want to invoke alternative transformations. Under the
192-
hood, the default implementation uses the `portal_transforms` tool to
193-
calculate a transform chain from the raw value’s input MIME type to the
194-
desired output MIME type. (Should you need to write your own transforms,
195-
take a look at [this tutorial].) This is abstracted behind an
196-
`ITransformer` adapter to allow alternative implementations.
165+
Sometimes, you may want to invoke alternative transformations.
166+
Under the hood, the default implementation uses the `portal_transforms` tool to calculate a transform chain from the raw value's input MIME type to the desired output MIME type.
167+
If you need to write your own transforms, take a look at [this tutorial](https://5.docs.plone.org/develop/plone/misc/portal_transforms.html).
168+
This is abstracted behind an `ITransformer` adapter to allow alternative implementations.
197169

198-
To invoke a transformation in code, you can use the following syntax:
170+
To invoke a transformation in code, you can use the following syntax.
199171

200-
```
172+
```python
201173
from plone.app.textfield.interfaces import ITransformer
202174

203175
transformer = ITransformer(context)
204176
transformedValue = transformer(context.body, 'text/plain')
205177
```
206178

207-
The `__call__()` method of the `ITransformer` adapter takes a
208-
`RichTextValue` object and an output MIME type as parameters.
179+
The `__call__()` method of the `ITransformer` adapter takes a `RichTextValue` object and an output MIME type as parameters.
209180

210-
If you are writing a page template, there is an even more convenient
211-
syntax:
181+
If you write a page template, there is an even more convenient syntax.
212182

213-
```html
183+
```xml
214184
<div tal:content="structure context/@@text-transform/body/text/plain" />
215185
```
216186

217-
The first traversal name gives the name of the field on the context
218-
(`body` in this case). The second and third give the output MIME type.
187+
The first traversal name gives the name of the field on the context (`body` in this case).
188+
The second and third give the output MIME type.
219189
If the MIME type is omitted, the default output MIME type will be used.
220190

221-
:::{note}
222-
Unlike the `output` property, the value is not cached, and so
223-
will be calculated each time the page is rendered.
224-
:::
225-
226-
[plone.app.textfield]: http://pypi.python.org/pypi/plone.app.textfield
227-
[this tutorial]: http://plone.org/documentation/kb/portal-transforms
191+
```{note}
192+
Unlike the `output` property, the value is not cached, and so will be calculated each time the page is rendered.
193+
```

0 commit comments

Comments
 (0)