diff --git a/pyramid_formalchemy/actions.py b/pyramid_formalchemy/actions.py
index 4a97454..2f96fc8 100644
--- a/pyramid_formalchemy/actions.py
+++ b/pyramid_formalchemy/actions.py
@@ -1,5 +1,25 @@
# -*- coding: utf-8 -*-
from chameleon.zpt.template import PageTemplate
+from pyramid.util import DottedNameResolver
+import functools
+
+def action(name=None):
+ def wrapper(func):
+ action = name or func.__name__
+ @functools.wraps(func)
+ def wrapped(self, *args, **kwargs):
+ request = self.request
+ if request.format in ('html', 'xhr') and request.model_class is not None:
+ for key in self.actions_categories:
+ attr = '%s_%s' % (action, key)
+ objects = getattr(request.model_class, attr, None)
+ if objects is None:
+ objects = self.defaults_actions.get(attr, Actions())
+ setattr(request, key, objects)
+ request.action = func.__name__
+ return func(self, *args, **kwargs)
+ return wrapped
+ return wrapper
class Action(object):
@@ -38,6 +58,9 @@ class Action(object):
rcontext.update(self.rcontext)
return self.template.render(**rcontext)
+ def __repr__(self):
+ return '<%s %s>' % (self.__class__.__name__, self.id)
+
class Link(Action):
"""
An action rendered as a link::
@@ -78,26 +101,27 @@ class UILink(Action):
>>> from webob import Request
>>> request = Request.blank('/')
>>> action = UILink('myaction', icon='ui-icon-trash',
- ... label='Click here')
+ ... label="string:Click here")
>>> print action.render(request)
-
-
+
>>> action = UILink('myaction', icon='ui-icon-trash',
- ... label='Click here', attrs={'onclick':'$(#link).click();'})
+ ... label="'Click here'", attrs={'onclick':'$(#link).click();'})
>>> print action.render(request)
-
+
"""
body = '''
'''
def update(self):
if 'state' not in self.rcontext:
@@ -108,16 +132,58 @@ class UILink(Action):
if 'href' not in self.attrs:
self.attrs['href'] = repr('#')
+class Actions(list):
+ """
+ >>> actions = Actions('pyramid_formalchemy.actions.delete',
+ ... Link('link1', content=repr('A link'), attrs={'href':'request.application_url'}))
+ >>> actions
+ [, ]
+
+ >>> from webob import Request
+ >>> request = Request.blank('/')
+ >>> print actions.render(request) #doctest: +ELLIPSIS
+ A link
+
+ """
+
+ def __init__(self, *args):
+ res = DottedNameResolver('pyramid_formalchemy.actions')
+ list.__init__(self, [res.maybe_resolve(a) for a in args])
+
+ def render(self, request, **kwargs):
+ return u''.join([a.render(request, **kwargs) for a in self])
+
+
+new = UILink(
+ id='new',
+ label='string:New ${request.model_name}',
+ icon='ui-icon-circle-plus',
+ attrs=dict(href="request.fa_url(request.model_name, 'new')"),
+ )
+
+
save = UILink(
id='save',
- label='Save',
+ label='string:Save',
icon='ui-icon-check',
attrs=dict(onclick="jQuery(this).parents('form').submit();"),
)
+save_and_add_another = UILink(
+ id='save_and_add_another',
+ label='string:Save and add another',
+ icon='ui-icon-check',
+ attrs=dict(onclick=("var f = jQuery(this).parents('form');"
+ "jQuery('#next', f).val(window.location.href);"
+ "f.submit();")),
+ )
+
edit = UILink(
id='edit',
- label='Edit',
+ label='string:Edit',
icon='ui-icon-check',
attrs=dict(href="request.fa_url(request.model_name, request.model_id, 'edit')"),
)
@@ -125,7 +191,7 @@ edit = UILink(
delete = UILink(
id='delete',
views='edit',
- label='Delete',
+ label='string:Delete',
state='ui-state-error',
icon='ui-icon-trash',
attrs=dict(onclick=("string:var f = jQuery(this).parents('form');"
@@ -136,20 +202,14 @@ delete = UILink(
cancel = UILink(
id='cancel',
views='edit',
- label='Cancel',
+ label='string:Cancel',
icon='ui-icon-circle-arrow-w',
attrs=dict(href="request.fa_url(request.model_name)"),
)
-class Actions(list):
-
- def __init__(self, *args):
- list.__init__(self, args)
-
- def render(self, request, **kwargs):
- return u''.join([a.render(request, **kwargs) for a in self])
-
-new_actions = Actions(save, cancel)
-show_actions = Actions(edit, cancel)
-edit_actions = Actions(save, delete, cancel)
-
+defaults_actions = dict(
+ listing_buttons=Actions(new),
+ new_buttons=Actions(save, save_and_add_another, cancel),
+ show_buttons=Actions(edit, cancel),
+ edit_buttons=Actions(save, delete, cancel),
+)
diff --git a/pyramid_formalchemy/views.py b/pyramid_formalchemy/views.py
index ff68ca5..623970d 100644
--- a/pyramid_formalchemy/views.py
+++ b/pyramid_formalchemy/views.py
@@ -45,6 +45,9 @@ class ModelView(object):
pager_args = dict(link_attr={'class': 'ui-pager-link ui-state-default ui-corner-all'},
curpage_attr={'class': 'ui-pager-curpage ui-state-highlight ui-corner-all'})
+ actions_categories = ('buttons',)
+ defaults_actions = actions.defaults_actions
+
def __init__(self, context, request):
self.context = context
self.request = request
@@ -118,8 +121,6 @@ class ModelView(object):
def render(self, **kwargs):
"""render the form as html or json"""
request = self.request
- if 'action' in kwargs and request.format != 'json':
- kwargs['actions'] = getattr(actions, '%(action)s_actions' % kwargs)
if request.format != 'html':
meth = getattr(self, 'render_%s_format' % request.format, None)
if meth is not None:
@@ -244,6 +245,7 @@ class ModelView(object):
grid.append(Field('delete', fatypes.String, delete_link()))
grid.readonly = True
+ @actions.action()
def listing(self, **kwargs):
"""listing page"""
page = self.get_page(**kwargs)
@@ -274,10 +276,38 @@ class ModelView(object):
pager = kwargs.pop('pager')
return self.render_grid(fs=fs, id=None, pager=pager)
+ @actions.action()
+ def show(self):
+ id = self.request.model_id
+ fs = self.get_fieldset(suffix='View', id=id)
+ fs.readonly = True
+
+ event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs)
+ alsoProvides(event, events.IBeforeShowRenderEvent)
+ zope.component.event.objectEventNotify(event)
+
+ return self.render(fs=fs, id=id)
+
+ @actions.action()
+ def new(self):
+ fs = self.get_fieldset(suffix='Add')
+ fs = fs.bind(session=self.session, request=self.request)
+
+ event = events.BeforeRenderEvent(fs.model, self.request, fs=fs)
+ alsoProvides(event, events.IBeforeEditRenderEvent)
+ zope.component.event.objectEventNotify(event)
+
+ return self.render(fs=fs, id=None)
+
+ @actions.action('new')
def create(self):
request = self.request
fs = self.get_fieldset(suffix='Add')
+ event = events.BeforeRenderEvent(fs.model, self.request, fs=fs)
+ alsoProvides(event, events.IBeforeEditRenderEvent)
+ zope.component.event.objectEventNotify(event)
+
if request.format == 'json' and request.method == 'PUT':
data = json.load(request.body_file)
else:
@@ -288,6 +318,7 @@ class ModelView(object):
except Exception:
# non SA forms
fs = fs.bind(self.context.get_model(), data=data, session=self.session, request=request)
+
if self.validate(fs):
fs.sync()
self.sync(fs)
@@ -301,25 +332,10 @@ class ModelView(object):
else:
fs.rebind(fs.model, data=None)
return self.render(fs=fs)
- return self.render(fs=fs, action='new', id=None)
+ return self.render(fs=fs, id=None)
- def show(self):
- id = self.request.model_id
- fs = self.get_fieldset(suffix='View', id=id)
- fs.readonly = True
-
- event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs)
- alsoProvides(event, events.IBeforeShowRenderEvent)
- zope.component.event.objectEventNotify(event)
-
- return self.render(fs=fs, action='show', id=id)
-
- def new(self, **kwargs):
- fs = self.get_fieldset(suffix='Add')
- fs = fs.bind(session=self.session, request=self.request)
- return self.render(fs=fs, action='new', id=None)
-
- def edit(self, id=None, **kwargs):
+ @actions.action()
+ def edit(self):
id = self.request.model_id
fs = self.get_fieldset(suffix='Edit', id=id)
@@ -327,12 +343,18 @@ class ModelView(object):
alsoProvides(event, events.IBeforeEditRenderEvent)
zope.component.event.objectEventNotify(event)
- return self.render(fs=fs, action='edit', id=id)
+ return self.render(fs=fs, id=id)
- def update(self, **kwargs):
+ @actions.action('edit')
+ def update(self):
request = self.request
id = request.model_id
fs = self.get_fieldset(suffix='Edit', id=id)
+
+ event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs)
+ alsoProvides(event, events.IBeforeEditRenderEvent)
+ zope.component.event.objectEventNotify(event)
+
fs = fs.bind(request=request)
if self.validate(fs):
fs.sync()
@@ -346,11 +368,11 @@ class ModelView(object):
else:
return self.render(fs=fs, status=0)
if request.format == 'html':
- return self.render(fs=fs, action='edit', id=id)
+ return self.render(fs=fs, id=id)
else:
return self.render(fs=fs, status=1)
- def delete(self, **kwargs):
+ def delete(self):
request = self.request
record = request.model_instance