-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial copy of collective.z3cform.keywordwidget
- Loading branch information
Johan Beyers
committed
Oct 30, 2011
0 parents
commit 1c9be3e
Showing
16 changed files
with
589 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
Introduction | ||
============ | ||
|
||
This product adds a Keyword widget (similar to Archetypes.Widget:KeywordWidget) | ||
for plone.z3cform. | ||
|
||
|
||
How To Use (Doc Tests): | ||
======================= | ||
|
||
>>> from z3c.form import testing | ||
>>> testing.setupFormDefaults() | ||
>>> import zope.interface | ||
>>> import zope.schema | ||
>>> from zope.schema.fieldproperty import FieldProperty | ||
|
||
Use the Keywords field your field type: | ||
|
||
>>> from collective.z3cform.keywordwidget.field import Keywords | ||
>>> class IFoo(zope.interface.Interface): | ||
... | ||
... keywords = Keywords(title=u'Keywords') | ||
|
||
>>> class Foo(object): | ||
... zope.interface.implements(IFoo) | ||
... keywords = FieldProperty(IFoo['keywords']) | ||
... | ||
... def __init__(self, keywords): | ||
... self.keywords = keywords | ||
... | ||
... def __repr__(self): | ||
... return '<%s %r>' % (self.__class__.__name__, self.name) | ||
|
||
We need to make sure that the keywords property is indexed in portal_catalog. | ||
|
||
First, we write the indexer. The indexer is a special adapter that adapts the type of an object | ||
and provides the value of the attribute to be indexed. | ||
|
||
>>> from plone.indexer.decorator import indexer | ||
>>> @indexer(IFoo) | ||
... def keywords(obj): | ||
... return IFoo(obj).keywords | ||
|
||
We need to register our indexer as a named adapter, where the name corresponds to | ||
the index name. In ZCML, that may be:: | ||
|
||
<adapter name="keywords" factory=".indexers.keywords" /> | ||
|
||
For testing purpoese, we will register it directly. | ||
|
||
>>> from zope.component import provideAdapter | ||
>>> provideAdapter(keywords, name='keywords') | ||
|
||
Now we add a form in which the widget will be rendered: | ||
|
||
Specify the KeywordWidget factory ('KeywordFieldWidget') as the field's widgetFactory. | ||
|
||
>>> from z3c.form.testing import TestRequest | ||
>>> from z3c.form import form, field | ||
>>> from collective.z3cform.keywordwidget.widget import KeywordFieldWidget | ||
|
||
>>> class FooAddForm(form.AddForm): | ||
... | ||
... fields = field.Fields(IFoo) | ||
... fields['keywords'].widgetFactory = KeywordFieldWidget | ||
... | ||
... def create(self, data): | ||
... return Foo(**data) | ||
... | ||
... def add(self, object): | ||
... self.context[object.id] = object | ||
... | ||
... def nextURL(self): | ||
... return 'index.hml' | ||
|
||
|
||
Create, update and render the form: | ||
|
||
>>> root = app | ||
>>> request = TestRequest() | ||
|
||
>>> addForm = FooAddForm(root, request) | ||
>>> addForm.update() | ||
|
||
>>> print addForm.render() | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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__) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
Introduction | ||
============ | ||
|
||
This product adds a Keyword widget (similar to Archetypes.Widget:KeywordWidget) | ||
for plone.z3cform. | ||
|
||
|
||
How To Use (Doc Tests): | ||
======================= | ||
|
||
>>> from z3c.form import testing | ||
>>> testing.setupFormDefaults() | ||
|
||
In your interface schema, use the Keywords field as your field type: | ||
|
||
>>> import zope.interface | ||
>>> import zope.schema | ||
>>> from zope.schema.fieldproperty import FieldProperty | ||
>>> from collective.z3cform.keywordwidget.field import Keywords | ||
>>> class IFoo(zope.interface.Interface): | ||
... | ||
... id = zope.schema.TextLine( | ||
... title=u'ID', | ||
... readonly=True, | ||
... required=True | ||
... ) | ||
... | ||
... keywords = Keywords(title=u'Keywords') | ||
|
||
|
||
Let's now create a class that implements our interface. | ||
|
||
>>> from AccessControl.Owned import Owned | ||
>>> class Foo(object, Owned): | ||
... zope.interface.implements(IFoo) | ||
... id = FieldProperty(IFoo['id']) | ||
... keywords = FieldProperty(IFoo['keywords']) | ||
... | ||
... def __init__(self, id, keywords): | ||
... self.id = id | ||
... self.keywords = keywords | ||
|
||
For the keywordwidget to work, we need to make sure that the keywords | ||
property is indexed in portal_catalog. | ||
|
||
First, we write the indexer. The indexer is a special adapter that adapts the type of an object | ||
and provides the value of the attribute to be indexed. | ||
|
||
>>> from plone.indexer.decorator import indexer | ||
>>> @indexer(IFoo) | ||
... def keywords(obj): | ||
... return IFoo(obj).keywords | ||
|
||
We need to register our indexer as a named adapter, where the name corresponds to | ||
the index name. In ZCML, that may be:: | ||
|
||
<adapter name="keywords" factory=".indexers.keywords" /> | ||
|
||
For testing purpoese, we will register it directly. | ||
|
||
>>> from zope.component import provideAdapter | ||
>>> provideAdapter(keywords, name='keywords') | ||
|
||
Now we add a form in which the widget will be rendered: | ||
|
||
Specify the KeywordWidget factory ('KeywordFieldWidget') as the field's widgetFactory. | ||
|
||
>>> from z3c.form.testing import TestRequest | ||
>>> from z3c.form import form, field | ||
>>> from collective.z3cform.keywordwidget.widget import KeywordFieldWidget | ||
|
||
>>> class FooAddForm(form.AddForm): | ||
... | ||
... fields = field.Fields(IFoo) | ||
... fields['keywords'].widgetFactory = KeywordFieldWidget | ||
... | ||
... def create(self, data): | ||
... return Foo(**data) | ||
... | ||
... def add(self, object): | ||
... self.context[str(object.id)] = object | ||
... | ||
... def nextURL(self): | ||
... return 'index.html' | ||
|
||
|
||
Create an AddForm: | ||
|
||
>>> request = TestRequest() | ||
>>> addForm = FooAddForm(portal, request) | ||
>>> addForm.update() | ||
|
||
Check for the keyword widget and render it: | ||
|
||
>>> addForm.widgets.keys() | ||
['id', 'keywords'] | ||
|
||
>>> addForm.widgets['keywords'].render() | ||
u'<div style="width: 45%; float: left">\n<span> Existing categories </span>\n<br />\n<select id="form-widgets-keywords"\n name="form.widgets.keywords:list"\n class="keyword-widget required keywords-field"\n multiple="multiple" size="14" style="width: 100%;">\n\n</select>\n</div>\n\n<div style="width: 45%; float: right;">\n<span>New categories</span>\n<br />\n<textarea id="form-widgets-keywords"\n name="form.widgets.keywords:list" cols="15"\n rows="13" wrap="off">\n</textarea>\n</div>\n\n<input name="form.widgets.keywords-empty-marker"\n type="hidden" value="1" />\n\n<div class="visualClear"><!-- --></div>\n' | ||
|
||
Let's now submit the addform with data: | ||
|
||
>>> request = TestRequest(form={ | ||
... 'form.widgets.id': u'myobject', | ||
... 'form.widgets.keywords': [u'chocolate', u'vanilla'], | ||
... 'form.buttons.add': u'Add'} | ||
... ) | ||
|
||
>>> addForm = FooAddForm(portal, request) | ||
>>> addForm.update() | ||
|
||
Check that the object has been created: | ||
|
||
>>> portal['myobject'] | ||
<Foo object at ...> | ||
|
||
Check that the keywords attr has been set: | ||
|
||
>>> portal['myobject'].keywords | ||
[u'chocolate', u'vanilla'] | ||
|
||
Render the widget again and check that the keywords are present and selected: | ||
|
||
|
||
>>> addForm.widgets['keywords'].render() | ||
u'<div style="width: 45%; float: left">\n<span> Existing categories </span>\n<br />\n<select id="form-widgets-keywords"\n name="form.widgets.keywords:list"\n class="keyword-widget required keywords-field"\n multiple="multiple" size="14" style="width: 100%;">\n\n \n <option id="form-widgets-keywords-0"\n value="chocolate" selected="selected">chocolate</option>\n\n \n \n \n <option id="form-widgets-keywords-1" value="vanilla"\n selected="selected">vanilla</option>\n\n \n \n</select>\n</div>\n\n<div style="width: 45%; float: right;">\n<span>New categories</span>\n<br />\n<textarea id="form-widgets-keywords"\n name="form.widgets.keywords:list" cols="15"\n rows="13" wrap="off">\n</textarea>\n</div>\n\n<input name="form.widgets.keywords-empty-marker"\n type="hidden" value="1" />\n\n<div class="visualClear"><!-- --></div>\n' | ||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<configure | ||
xmlns="http://namespaces.zope.org/zope" | ||
xmlns:z3c="http://namespaces.zope.org/z3c" | ||
xmlns:browser="http://namespaces.zope.org/browser" | ||
xmlns:genericsetup="http://namespaces.zope.org/genericsetup" | ||
i18n_domain="collective.z3cform.datepicker"> | ||
|
||
<genericsetup:registerProfile | ||
name="testing" | ||
title="collective.z3cform.keywordwidget testing profile" | ||
directory="profiles/testing" | ||
for="Products.CMFPlone.interfaces.ITestCasePloneSiteRoot" | ||
provides="Products.GenericSetup.interfaces.EXTENSION" | ||
/> | ||
|
||
<include package="plone.z3cform" /> | ||
|
||
<class class=".widget.KeywordWidget"> | ||
<require permission="zope.Public" | ||
interface=".interfaces.IKeywordWidget" /> | ||
</class> | ||
|
||
<adapter factory=".widget.KeywordFieldWidget" /> | ||
|
||
<z3c:widgetTemplate | ||
mode="input" | ||
widget=".interfaces.IKeywordWidget" | ||
layer="z3c.form.interfaces.IFormLayer" | ||
template="keyword_input.pt" | ||
/> | ||
|
||
<z3c:widgetTemplate | ||
mode="display" | ||
widget=".interfaces.IKeywordWidget" | ||
layer="z3c.form.interfaces.IFormLayer" | ||
template="keyword_display.pt" | ||
/> | ||
|
||
<adapter | ||
factory=".field.KeywordsDataConverter" | ||
/> | ||
|
||
</configure> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import zope.component | ||
import zope.schema | ||
import zope.interface | ||
import z3c.form.converter | ||
|
||
import interfaces | ||
|
||
class Keywords(zope.schema.List): | ||
"""A field representing a set.""" | ||
zope.interface.implements(interfaces.IKeywordCollection) | ||
unique = True | ||
value_type = zope.schema.TextLine() | ||
|
||
|
||
class KeywordsDataConverter(z3c.form.converter.BaseDataConverter): | ||
"""A special converter between collections and sequence widgets.""" | ||
|
||
zope.component.adapts(interfaces.IKeywordCollection, interfaces.IKeywordWidget) | ||
|
||
def toWidgetValue(self, value): | ||
collectionType = self.field._type | ||
if isinstance(collectionType, tuple): | ||
collectionType = collectionType[-1] | ||
|
||
if value: | ||
return collectionType(value) | ||
else: | ||
return collectionType() | ||
|
||
def toFieldValue(self, value): | ||
"""See interfaces.IDataConverter | ||
""" | ||
widget = self.widget | ||
if widget.terms is None: | ||
widget.updateTerms() | ||
collectionType = self.field._type | ||
if isinstance(collectionType, tuple): | ||
collectionType = collectionType[-1] | ||
|
||
return collectionType(value) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import zope.schema | ||
import z3c.form.interfaces | ||
|
||
class IKeywordWidget(z3c.form.interfaces.ISequenceWidget): | ||
"""A keyword widget. | ||
""" | ||
|
||
class IKeywordCollection(zope.schema.interfaces.ICollection): | ||
""" Marker interfaces for keyword collections | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<span id="" class="" | ||
tal:attributes="id view/id; | ||
class view/klass; | ||
style view/style; | ||
title view/title; | ||
lang view/lang; | ||
onclick view/onclick; | ||
ondblclick view/ondblclick; | ||
onmousedown view/onmousedown; | ||
onmouseup view/onmouseup; | ||
onmouseover view/onmouseover; | ||
onmousemove view/onmousemove; | ||
onmouseout view/onmouseout; | ||
onkeypress view/onkeypress; | ||
onkeydown view/onkeydown; | ||
onkeyup view/onkeyup"> | ||
|
||
<tal:block condition="view/formatted_value" content="structure view/formatted_value"/> | ||
</span> |
Oops, something went wrong.