Update the "Adding Field Type" howto.

Closes #48.
This commit is contained in:
A. Jesse Jiryu Davis 2016-02-07 07:00:14 -05:00
parent 4f08dc14d2
commit 00b85759d9
2 changed files with 57 additions and 42 deletions

View File

@ -41,3 +41,6 @@ def setup_env(self, **extra):
```
For more information see [value_from_raw :ref](value-from-raw/).
There is a more complete example in the
[Plugin How To :ref](../../../plugins/howto/#adding-new-field-types).

View File

@ -114,64 +114,76 @@ function we also track the plugin's filename to rebuild if the plugin changes.
## Adding New Field Types
Let's say you want to add a "datetime" type to the set of
[field types :ref](../../api/db/types/) used in your models, because the
built-in "date" type has no time component. You might update `blog-post.ini`
from the [blog guide :ref](../../guides/blog) like so:
Let's say you want to add an "asciidoc"
[field type :ref](../../api/db/types/) so you can write with [AsciiDoc](http://www.methods.co.nz/asciidoc) markup.
First [install AsciiDoc](http://www.methods.co.nz/asciidoc/INSTALL.html) so its command-line program is available. Then update `blog-post.ini` from the [blog guide :ref](../../guides/blog) like so:
```ini
[fields.pub_date]
label = Publication date
type = datetime # Custom "datetime" type.
[fields.body]
label = Body
type = asciidoc # Custom type.
```
In a blog post's `contents.lr`, specify its publication date like:
In a blog post's `contents.lr`, write some AsciiDoc like:
```
pub_date: 2016-01-02 12:34:56
body:
== Header 1
Some text.
-----
code here
-----
```
You can add your "datetime" type to Lektor with a plugin:
You can add your "asciidoc" type to Lektor with a plugin:
```python
from datetime import datetime
from subprocess import PIPE, Popen
from lektor.pluginsystem import Plugin
from lektor.types import Type
class DatetimeType(Type):
def asciidoc_to_html(text):
# The "-" at the end tells asciidoc to read from stdin.
p = Popen(
['asciidoc', '--no-header-footer',
'--backend=html5', '-'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, err = p.communicate(text)
if p.returncode != 0:
raise RuntimeError('asciidoc: "%s"' % err)
return out
# Wrapper with an __html__ method prevents
# Lektor from escaping HTML tags.
class HTML(object):
def __init__(self, html):
self.html = html
def __html__(self):
return self.html
class AsciiDocType(Type):
widget = 'multiline-text'
def value_from_raw(self, raw):
return datetime.strptime(raw.value, '%Y-%m-%d %H:%M:%S')
return HTML(asciidoc_to_html(raw.value or u''))
def strftime_filter(dt, fmt='%B %-d, %Y'):
return dt.strftime(fmt)
class DatetimeTypePlugin(Plugin):
name = u'datetime type'
description = u'Adds a new field type, "datetime".'
class AsciiDocPlugin(Plugin):
name = u'AsciiDoc'
description = u'Adds AsciiDoc field type to Lektor.'
def on_setup_env(self, **extra):
self.env.types['datetime'] = DatetimeType
self.env.jinja_env.filters['strftime'] = strftime_filter
```
This plugin also adds a `strftime` filter to Jinja.
Render a datetime with the default format in a template like:
```html+jinja
Published on {{ this.pub_date|strftime }}
```
Or a custom format:
```html+jinja
Published on {{ this.pub_date|strftime('%Y-%m-%d') }}
```
Python datetime objects implement the standard comparison protocol, so
ordering still works without modifying `blog.ini`:
```ini
[children]
model = blog-post
order_by = -pub_date, title
# Derives type name "asciidoc" from class name.
self.env.add_type(AsciiDocType)
```