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.1 (2007-08-01)
--------------------------
- form status
Version 0.2.0 (2007-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 (2007-07-19)
--------------------------
- Correct egg-info
Version 0.1.0 (2007-07-19)
--------------------------
- Initial release
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.1 (2007-08-01)
--------------------------
- form status
Version 0.2.0 (2007-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 (2007-07-19)
--------------------------
- Correct egg-info
Version 0.1.0 (2007-07-19)
--------------------------
- Initial release
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
ice.adverlet-0.2.1.tar.gz
(37.1 kB
view hashes)