Skip to content

Commit

Permalink
start the plone.outputfilters package, refs #9938
Browse files Browse the repository at this point in the history
svn path=/plone.outputfilters/trunk/; revision=38866
  • Loading branch information
davisagli committed Aug 23, 2010
0 parents commit 6e24af5
Show file tree
Hide file tree
Showing 22 changed files with 1,149 additions and 0 deletions.
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Changelog
=========

1.0dev (unreleased)
-------------------

- Initial implementation.
339 changes: 339 additions & 0 deletions docs/LICENSE.GPL

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions docs/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plone.outputfilters is copyright

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA.
6 changes: 6 additions & 0 deletions plone/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
128 changes: 128 additions & 0 deletions plone/outputfilters/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
Introduction
============

``plone.outputfilters`` provides a framework for registering filters that
get applied to text as it is rendered.

By default, these filters are wired up to occur when text is transformed from
the text/html mimetype to the text/x-html-safe mimetype via the
PortalTransforms machinery.

With both Archetypes TextFields and the RichText field of
``plone.app.textfield``, this transform is typically applied when the field
value is first accessed. The result of the transform is then cached until the
value is replaced.


Included Filters
================

A default filter is included which provides the following features:

* Resolving UID-based links
* Adding captions to images

(These are implemented as one filter to avoid the overhead of parsing the HTML
twice.)


Resolving UID-based links
-------------------------

Internal links may be inserted with a UID reference rather than the real path
of the item being linked. For example, a link might look like this::

<a href="resolveuid/6992f1f6-ae36-11df-9adf-001ec2a8cdf1">

Such URLs can be resolved by the resolveuid view, but this requires an extra
redirect to reach the actual object. The resolveuid filter will avoid that by
replacing such URLs with the object's actual full absolute URL.

UIDs are resolved using ``plone.app.uuid.utils.uuidToURL``, with a fallback to
the Archetypes UID catalog for backwards compatibility. LingaPlone translations
are supported when LinguaPlone is present.

The resolveuid filter is enabled when XXX


Image captioning
----------------

Image tags with the "captioned" class and a ``src`` attribute that resolves to
an image object within the site will be wrapped in a definition list (DL) tag
which includes a caption based on the value of the image's ``description``
field, if any.

For example, this image tag::

<img src="path/to/image" class="captioned"/>

might be transformed into::

<dl class="captioned">
<dt><img src="path/to/image"/></dt>
<dd class="image-caption">Caption text</dd>
</dl>

assuming the image found at "path/to/image" has the description "Caption text".

The image captioning filter is enabled when XXX


Adding a custom filter
======================

As an example, the following filter replaces all doubled hyphens ("--") with em
dashes ("—"). (Don't use the example verbatim, because it doesn't parse HTML to apply itself only to text nodes, so will mangle HTML comments.)

A filter is a callable which accepts a UTF-8-encoded HTML string as input, and
returns a modified UTF-8-encoded HTML string. A return value of ``None`` may be
used to indicate that the input should not be modified.

.. include:: filters/example.py
:literal:

The ``order`` attribute may be used to affect the order in which filters are
applied (higher values run later). The is_enabled method should return a boolean
indicating whether the filter should be applied.

Filters are registered in ZCML as a named multi-adapter of the context and
request to IFilter.

>>> from Products.Five.zcml import load_string
>>> load_string("""
... <configure
... xmlns="http://namespaces.zope.org/zope">
...
... <adapter
... name="em_dash_adder"
... provides="plone.outputfilters.interfaces.IFilter"
... for="* *"
... factory="plone.outputfilters.filters.example.EmDashAdder"
... />
...
... </configure>
... """)

Now when text is transformed from text/html to text/x-html-safe, the filter will
be applied.

>>> str(self.portal.portal_transforms.convertTo('text/x-html-safe',
... 'test--test', mimetype='text/html'))
'test\xe2\x80\x94test'


How it works
============

``plone.outputfilters`` hooks into the PortalTransforms machinery by installing:

1. a new mimetype ("text/x-plone-outputfilters-html")
2. a transform from text/html to text/x-plone-outputfilters-html
3. a null transform from text/x-plone-outputfilters-html back to text/html
4. a "transform policy" for the text/x-html-safe mimetype, which says that text
being transformed to text/x-html-safe must first be transformed to
text/x-plone-outputfilters-html

The filter adapters are looked up and applied during the execution of the
transform from step #2.
2 changes: 2 additions & 0 deletions plone/outputfilters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def initialize(context):
"""Initializer called when used as a Zope 2 product."""
24 changes: 24 additions & 0 deletions plone/outputfilters/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:gs="http://namespaces.zope.org/genericsetup"
i18n_domain="plone.outputfilters">

<include package=".filters"/>

<gs:registerProfile
name="default"
title="HTML Output Filters"
directory="profiles/default"
description="Framework for applying filters to HTML as it is rendered."
provides="Products.GenericSetup.interfaces.EXTENSION"
/>

<gs:importStep
name="plone_outputfilters_various"
title="HTML Output Filters installation"
description="Import various plone.outputfilters"
handler="plone.outputfilters.setuphandlers.importVarious">
<depends name="componentregistry"/>
</gs:importStep>

</configure>
Empty file.
11 changes: 11 additions & 0 deletions plone/outputfilters/filters/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<configure
xmlns="http://namespaces.zope.org/zope">

<adapter
provides="..interfaces.IFilter"
name="resolveuid_and_caption"
for="* *"
factory=".resolveuid_and_caption.ResolveUIDAndCaptionFilter"
/>

</configure>
17 changes: 17 additions & 0 deletions plone/outputfilters/filters/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import re
from zope.interface import implements
from plone.outputfilters.interfaces import IFilter

class EmDashAdder(object):
implements(IFilter)
order = 1000

def __init__(self, context, request):
pass

def is_enabled(self):
return True

pattern = re.compile(r'--')
def __call__(self, data):
return self.pattern.sub('\xe2\x80\x94', data)
Loading

0 comments on commit 6e24af5

Please sign in to comment.