z3c.form and Javascript subform CRUD widget for Plone - plone

I need a widget which has add/remove of subforms via Javascript (create-read-update-delete).
It would be similar to DataGridField, but instead of having lines it would present subforms as blocks.
A jQuery plug-in example: http://vipullimbachiya.com/jQuery/Plugins/MultiField/SampleMultiField.htm#example
Does z3c.form or Plone has this kind of subform CRUD widgets already? The main thing would be implement this 100% on the client side, without HTTP postback when you press add/remove buttons.

There is plone.z3cform.crud / plone.app.z3cform.crud:
class IOneEntry(interface.Interface):
# Schema definition
class MainForm(crud.CrudForm):
update_schema = IOneEntry
def get_items(self):
# return items implementing IOneEntry
def add(self, data):
# Add one IOneEntry object
def remove(self, (id, data)):
# Remove one IOneEntry object
but this does not use AJAX to add entries.

Related

adding a button in tryton view form

hi i have been searching and i cant find any tutorial about how to add a button in my view_form part of a custom module.
i wanted to add a button and make it call a method i made every time it is clicked.
in xml view form :
<label name="fieldstring"/>
<field name="fieldstring"/>
<button name="dosomething"/>
code:
def dosomething(cls,records):
#treatement
is there any example module that is using a button associated to a treatment??
In order to add a button to a view you have to make 3 steps:
Add the button to the _buttons dictionary of ModelView class. Normally this is done in the setup method of your class. Here you can define the icon and the states (when the button is invisible for example). If nothing needed you can define it with an empty dictionary.
For example:
#classmethod
def __setup__(cls):
super(Class, cls).__setup__()
cls._buttons.update({
'mybutton': {},
})
More complex examples can be found on tryton modules, for example:
http://hg.tryton.org/modules/account_invoice/file/84a41902ff5d/invoice.py#l224
Declare your method and decorate it with ModelView.button (in order to check access right to this button). For example:
#classmethod
#ModelView.button
def mybutton(cls, records)
#DO whatever you want with records
NOTE that the name method must be the one that you use as key of the _buttons dictionary in step1.
And finally add it to the view. You can find all the attributes that can be used on:
http://doc.tryton.org/3.2/trytond/doc/topics/views/index.html?highlight=button#button
Note that the string and name attributes are mandatory.
Also the name must be the name of the method to call, defined in step 2.
You can find some examples in:
http://hg.tryton.org/modules/account_invoice/file/84a41902ff5d/view/invoice_form.xml#l51

Extending SearchableText using collective.dexteritytextindexer

I am trying to extend the SearchableText index for my content type.
I have succeeded in getting multiple fields to be included by marking them as indexer:searchable="true" in the model file.
However I can't extend the SearchableText from my type's py as follows:
class IMyBehavior(form.Schema):
dexteritytextindexer.searchable('description')
description = schema.Text(title=u'Precis')
alsoProvides(IMyBehavior, IFormFieldProvider)
class MySearchableTextExtender(object):
adapts(IMyBehavior)
implements(dexteritytextindexer.IDynamicTextIndexExtender)
def __init__(self, context):
self.context = context
def __call__(self):
"""Extend the searchable text with a custom string"""
return 'some more searchable words'
I have to admit, I don't really know how the first class works. Do I have to set the searchable fields in this class to be able to extend the SearchableText in the second?
If I remove all the indexer:searchable="true" from the model, then the SearchableText is just empty.
Is the first class trying to register the schema at the same time? If so what should this look like if it's just extending the SearchableText?
The collective.dexteritytextindexer provides two important features:
As you already achieved, dexteritytextindexer gives you the ability to put values into Plone's SearchableText index. By adding dexteritytextindexer.searchable(FIELDNAME) to your form, the value of the field will appear in the SearchableText. In Archetypes you have the same feature, by adding searchable=True to the field definition.
collective.dexteritytextindexer gives you also the ability to extend the searchableText manually by registering an IDynamicTextIndexExtender adapter. It extends the values from part 1 with the values from your adapter.
I guess the Problem in your case is, that you have missed to register the adapter: https://github.com/collective/collective.dexteritytextindexer#extending-indexed-data
Example:
<adapter
factory=".yourbehavior.MySearchableTextExtender"
provides="collective.dexteritytextindexer.IDynamicTextIndexExtender"
name="IMyBehavior"
/>
Here's a working example:
This code extends the SearchableText of a container with the searchableText of it's children.
IDynamicTextIndexExtender adapter:
https://github.com/4teamwork/ftw.simplelayout/blob/a7d631de3984b8c1747506b9411045fdf83bc908/ftw/simplelayout/indexer.py
Register the adapter with zcml:
https://github.com/4teamwork/ftw.simplelayout/blob/a7d631de3984b8c1747506b9411045fdf83bc908/ftw/simplelayout/behaviors.zcml#L21
And the most important part - test the implementation:
https://github.com/4teamwork/ftw.simplelayout/blob/a7d631de3984b8c1747506b9411045fdf83bc908/ftw/simplelayout/tests/test_indexer.py#L31

Querying adapters against plone.directives.form.Schema

I have a form model created as following:
from plone.app.directives import Form
class IFormSchema(form.Schema):
foobar = schema.Bool(title=u"Just another field")
I'd like to register an adapter against this definition:
#component.adapter(IFormSchema)
#interface.implementer(ITreeSelectURLProvider)
def TreeSourceURL():
"""
"""
return "http://foobar"
The registration goes correctly.
However, there is an issue that I don't know if IFormSchema is directly provided by any object in any point of z3c.form processing chain, so that I could call:
provider = ITreeSelectURLProvider(someObject)
Does IFormSchema get directly applied to some object (zope.interface.directlyProvides?) in any point of z3c.form or plone.autoform chain
If not, what is the recommended practice so that I can register adapters against the model? What classes I should make to implement this interface?
To make matters worse, the context in the question is not a real content item but a subform object.
Dexterity make sure that the schema interface (be that defined on the filesystem and referenced in the FTI, or defined through the web or in an XML file) is provided by instances of the content type.
This isn't really about forms, it's about Dexterity. The form.Schema base class is just a marker that extends Interface, and which allows some of plone.autoform's processing to take place at configuration time.

Setting field defaults on programmatically created Dexterity items

I have a Dexterity content type based on plone.directives.form.Schema which has a number of form hints for assigning defaults:
#form.default_value(field=ITrial['start_on'])
def default_start_on(data):
return datetime.now()
Some of the defaults are more complex, passing back objects that are themselves instances of Dexterity types. These objects are essential for the main type's setup, which is triggered by various events.
I'm now in the process of testing. Ideally, I'd like to be able to use something like:
item = createContentInContainer(folder, 'ctcc.model.trial', 'item')
That is, I'd like the defaults to be picked up by the item without having to be manually passed into the constructor.
If I was using zope.schema I could use FieldProperty to set up proxies to the schema fields. Is there something equivalent for Dexterity, or perhaps a function for pushing an object through form creation?
Solution: I ended up going with David's option #1, intercepting ObjectCreatedEvent.
#grok.subscribe(ITrial, IObjectCreatedEvent)
def create_trial(trial, event):
if getattr(trial, 'start_on', None) is None:
trial.start_on = default_start_on(None)
It stills feels like I'm replicating part of form behaviour, but at least it's using the same functions that are providing the form defaults.
As you've discovered, the #form.default_value decorator is respected by z3c.form forms, but not when items are created in other ways. You have several options:
Write a handler for the ObjectCreatedEvent for your content type which sets up the necessary default values. This is the simplest approach to implement, but may not work if there are other handlers of this event that need the values in place.
Create your own subclass of Dexterity's generic Item class, and use it instead of Item as the basis for your content type. Then you can customize the __init__ method to set whatever you want. This would require migration of existing content items though, if you already have some.
This is a more complicated option. Replace the factory utility used to construct the content type. createContentInContainer ends up looking for an IFactory utility with a name equal to the factory attribute of the content type's FTI. The default implementation is in plone.dexterity.factory but you could replace it with a different one that does more.

How to access z3c.form widget settings from browser view

Given following widget based on z3c.form https://github.com/collective/Products.UserAndGroupSelectionWidget/blob/z3cform-widget/src/Products/UserAndGroupSelectionWidget/z3cform/widget.py
I would like in some browserview to access its settings and corresponding field. Since Widget does not know the schema and field upfront, I'm interested in what information do I need to get widget and field. Currently I have available the fieldname and context, which seemed to be enough for archtypes https://github.com/collective/Products.UserAndGroupSelectionWidget/blob/z3cform-widget/src/Products/UserAndGroupSelectionWidget/browser.py#L60
EDIT: To simplify the question, I would like to access a field that is defined in some z3c form and its widget. I could not find other way except passing request and context to form init and then accessing the field. Is there a multiadapter?
The idea is to have a z3c.form widget that people hook into whatever field which does an ajax call. That ajax request needs to pass parameters and response will lookup where widget was used and with what settings. The question is, how to lookup the z3c.form field and which information is needed to do so?
Getting the Field
If you can get the schema, you can get the field.
For a dexterity content type, if you know the field name and the type's portal_type, you can get the schema from the type's Factory Type Information (FTI).
So, if we know portal_type and field_name:
from zope.component import getUtility
from plone.dexterity.interfaces import IDexterityFTI
fti = getUtility(IDexterityFTI, name=portal_type)
schema = fti.lookupSchema()
field = schema.get(field_name)
Getting the Widget
From the z3c.form documentation: http://packages.python.org/z3c.form/widget.html
The widget is a multiadapter, so if you have the field, you can get it like so:
ageWidget = zope.component.getMultiAdapter((field, request),
interfaces.IFieldWidget)
Important: If you have however specified a widget via plone.autoform, then that widget won't be fetched. plone.autoform manually sets a widgetFactory on the z3c.form.field.Field object (which is not the same as the zope.schema Field!). The best way to get the widget then, is what you have already done, by manually calling initiating a FieldWidget.
So for example if you want the UserAndGroupSelectionWidget:
widget = FieldWidget(field, UserAndGroupSelectionWidget(field, request))
P.S Since I'm also in the collective and use the picker widget, I've updated the code for you ;)

Resources