Skip to main content
2025 Python Packaging Survey is now live!  Take the survey now

Simple way to edit any HTML snippet

Project description

============
ice.adverlet
============

.. contents::

Usage
=====

This package - for Zope3 based sites - provides a simple way to edit
any HTML snippet. It includes a WYSIWYG-editor, undo support and
storage for images.

Examples of possible uses include: advertisement portlets,
announcements, footers, frontpages, etc.

The package provides the ZCML directive `adverlet` and TALES
expression `adverlet`.

To use the package follow these 6 simple steps:

1) Include the package:

<include package="ice.adverlet" file="meta.zcml" />
<include package="ice.adverlet" />

2) In the ZCML configuration file define all your adverlets, for
example:

<ice:adverlet name="top" />

<ice:adverlet
name="bottom"
description="This is an advertisement at the bottom of the frontpage"
/>

<ice:adverlet
name="footer"
description="Footer of the site"
default="default-footer"
wysiwyg="False"
/>

Notice:
`name` - Required.
`description` - Not required.
`default` - Not required, it is name of browser view, registered b
zcml-directives like browser:page.
`wysiwyg' - Not required. Defines usage rich-text editor by default for this
adverlet in management UI. User (admin) can change this in the form.
Default value is True.

3) Write `adverlet` TALES expression in to your skin:

<div tal:content="structure adverlet:top" />

where `top` is name of the adverlet.

4) The package provides a view to manage all registered adverlets.
This view may be called by a special content provider
in any page::

<div tal:content="structure provider:ice.adverlet.manage" />

5) This content provider has the permission "ice.adverlet.Manage".
Therefore, you need to grant this permission to a role in your
project, and allow "undo" for this user, for example::

<grant permission="ice.adverlet.Manage" role="foo.blah.Blah" />
<grant permission="zope.UndoOwnTransactions" role="foo.blah.Blah" />

6) Install and register 2 local utilities:

1. Factory - ice.adverlet.storage.SourceStorage;
Interface - ice.adverlet.interfaces.ISourceStorage;
Name - empty.
(into Local Site Manager)

2. Factory - ice.adverlet.storage.FileStorage;
Interface - ice.adverlet.interfaces.IFileStorage;
Name - empty.
(into local site)

That's it.

N.B. You can define your own templates for management UI.
To do this, take a look at ice/adverlet/browser/template
and write your own adapters in your project for your own templates.

You will need to:

- Change @adapter(IContentProvider, IDefaultBrowserLayer)
to @adapter(IContentProvider, IMyCustomLayer)
- Register this adapter with the same name
(take a look at ice/adverlet/browser/configure.zcml,
section <!-- templates -->.)

N.B. Also, you can use default templates but not default CSS for
management UI. For this, look in ZMI `Settings` form for
ice.adverlet.storage.SourceStorage local utility or define attribute
`defaultCSS=False` in your install-tool code.

Tests
=====

>>> import zope.interface
>>> import zope.component

Let's register a default view for one of our adverlets::

>>> import os, tempfile
>>> temp_dir = tempfile.mkdtemp()
>>> templateFileName = os.path.join(temp_dir, 'default_footer.pt')
>>> open(templateFileName, 'w').write('''
... <h1>Default Footer</h1>
... ''')

>>> from zope.publisher.interfaces import browser
>>> from zope.app.pagetemplate import simpleviewclass
>>> DefaultViewClass = simpleviewclass.SimpleViewClass(
... templateFileName, name='default-footer')

>>> zope.component.provideAdapter(
... DefaultViewClass,
... (zope.interface.Interface, browser.IDefaultBrowserLayer),
... zope.interface.Interface,
... name='default-footer'
... )

Let's register a few advertlets::

>>> from zope.configuration import xmlconfig
>>> import ice.adverlet
>>> context = xmlconfig.file('meta.zcml', ice.adverlet)

>>> context = xmlconfig.string('''
... <configure
... xmlns="http://namespaces.zope.org/zope"
... xmlns:ice="http://namespaces.zope.org/ice"
... i18n_domain="test">
...
... <ice:adverlet
... name="frontpage"
... />
...
... <ice:adverlet
... name="footer"
... description="Footer of the site"
... default="default-footer"
... />
...
... </configure>''', context)

Now we can try to call these adverlets in any view::

>>> templateFileName = os.path.join(temp_dir, 'template.pt')
>>> open(templateFileName, 'w').write('''
... <html>
... <body>
... <div tal:content="structure adverlet:frontpage" />
... <div tal:content="structure adverlet:footer" />
... </body>
... </html>
... ''')

>>> PageClass = simpleviewclass.SimpleViewClass(
... templateFileName, name='index.html')

>>> zope.component.provideAdapter(
... PageClass,
... (zope.interface.Interface, browser.IDefaultBrowserLayer),
... zope.interface.Interface,
... name='index.html'
... )

>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()

>>> class Content(object):
... zope.interface.implements(zope.interface.Interface)
>>> content = Content()

>>> view = zope.component.getMultiAdapter(
... (content, request), name='index.html')

>>> print view().strip()
<html>
<body>
<div></div>
<div>
<h1>Default Footer</h1>
</div>
</body>
</html>
<BLANKLINE>

To edit adverlets store HTML sources::

>>> from ice.adverlet.storage import SourceStorage
>>> from ice.adverlet.interfaces import ISourceStorage

>>> storage = SourceStorage()
>>> ISourceStorage.providedBy(storage)
True

>>> storage.sources['frontpage'] = u'''
... <h2><a
href="http://launchpad.net>Launchpad</a></h2>
... '''
>>> storage.sources['footer'] = u'''
... <h3><a href="http://ohloh.net>OhLoh</a></h3>
... '''

and register storage as utility::

>>> zope.component.provideUtility(storage, ISourceStorage)

Let's check the test view now::

>>> print view().strip()
<html>
<body>
<div>
<h2><a href="http://launchpad.net>Launchpad</a></h2>
</div>
<div>
<h3><a href="http://ohloh.net>OhLoh</a></h3>
</div>
</body>
</html>
<BLANKLINE>

Then we will test image storage and image wrapper.
To do this, let's register storage for the files::

>>> from ice.adverlet.storage import FileStorage
>>> from ice.adverlet.interfaces import IFileStorage

>>> files = FileStorage()
>>> IFileStorage.providedBy(files)
True

>>> zope.component.provideUtility(files, IFileStorage)

And let's try to use the image wrapper to store images in this storage::

>>> from ice.adverlet.image import ImageWrapper
>>> from ice.adverlet.interfaces import IImageWrapper

>>> wrapper = ImageWrapper()
>>> IImageWrapper.providedBy(wrapper)
True

Register adapter for DublinCore::

>>> from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
>>> from zope.dublincore.interfaces import IZopeDublinCore
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> from zope.app.file.image import Image

>>> zope.interface.classImplements(Image, IAttributeAnnotatable)

>>> zope.component.provideAdapter(
... factory = ZDCAnnotatableAdapter,
... provides = IZopeDublinCore,
... adapts = (IAttributeAnnotatable,)
... )

We use test image::

>>> from ice.adverlet.tests.tests import zptlogo
>>> wrapper.data = zptlogo
>>> wrapper.description = u'Logo image'

Now let's check file storage::

>>> [key for key in files.keys()]
[u'Image']

>>> [IZopeDublinCore(file).title for file in files.values()]
[u'Logo image']

Note that in management UI we use named global utilities IAdverlet
for store HTML instead of using the storage directly. Let's test
this feature::

>>> storage.sources['frontpage']
u'\n <h2><a
href="http://launchpad.net>Launchpad</a></h2>\n '

>>> from ice.adverlet.interfaces import IAdverlet
>>> frontpage = zope.component.getUtility(IAdverlet, 'frontpage')

>>> frontpage.source = '<h2>Hi there</h2>'

>>> storage.sources['frontpage']
'<h2>Hi there</h2>'

And let's check adverlet again::

>>> frontpage.source
'<h2>Hi there</h2>'

We provide event for modify sources::

>>> events = []
>>> zope.component.provideHandler(events.append, (None, ))

>>> frontpage.source = '''<h2>Welcome!
... You are here.</h2>
... '''

>>> events
[<ice.adverlet.events.SourceModifiedEvent instance at ...>]

The event holds the name of the global `adverlet` utility::

>>> events[0].name
u'frontpage'

Look up test browser class again::

>>> print view().strip()
<html>
<body>
<div><h2>Welcome!
You are here.</h2>
</div>
<div>
<h3><a href="http://ohloh.net>OhLoh</a></h3>
</div>
</body>
</html>
<BLANKLINE>

Let's test `newlines` parameter::

>>> frontpage.newlines = True

>>> print view().strip()
<html>
<body>
<div><h2>Welcome!
<br /> You are here.</h2>
<br /> <br /></div>
<div>
<h3><a href="http://ohloh.net>OhLoh</a></h3>
</div>
</body>
</html>
<BLANKLINE>

Cleanup::

>>> import shutil
>>> shutil.rmtree(temp_dir)


=========
Demo site
=========

To look the demo follow these steps:

1) In setup.py file your project write:

install_requires = [...'ice.adverlet',..]

2) In configure.zcml of your project write:

<include package="ice.adverlet.demo" />

3) Run zope instance, add 'DEMO SITE' in ZMI, go to thi site, look 'DEMO'

The demo site has defined 4 adverlets: header, main, footer, sidebar.
There are default views for `header`, 'main' and `footer` adverlets
(take a look at demo/app.zcml).
Also, there are user: login - `demo`, password - `demo`.

Other way: download tar-archive from
http://http://pypi.python.org/pypi/ice.adverlet
or http://launchpad.net/ice.adverlet/
and run buildout.


=======
CHANGES
=======

Version 0.2.3 (2008-12-22)
--------------------------

- fixed bug in images container name chooser to work in KGS


Version 0.2.2 (2008-08-04)
--------------------------

- more convenience adverlets-listing
- changes in default style sheets

Version 0.2.1 (2008-08-01)
--------------------------

- form status


Version 0.2.0 (2008-07-25)
--------------------------

- two modes: rich-text editor or simple textarea
- 'render newlines' field for simple mode
- `use default CSS for management UI` system parameter
- `upload` form and listing of images now is in same URL
- correct redirects in the form (not in the action handler, but
in `update` method).
- removed `Use Default View` column from management UI
- demo principal instead zope.Anonymous for using demo
in zopejroject or grokproject

Backward compatibility: yes, thanks to FieldProperty.


Version 0.1.1 (2008-07-19)
--------------------------

- Correct egg-info


Version 0.1.0 (2008-07-19)
--------------------------

- Initial release

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page