mirror of
https://github.com/wassname/pyramid_formalchemy.git
synced 2026-08-11 11:23:53 +08:00
improve actions. decorator and stuff
This commit is contained in:
@@ -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)
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all " id="myaction">
|
||||
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all " id="myaction">
|
||||
<span class="ui-icon ui-icon-trash"></span>
|
||||
Click here
|
||||
</a>
|
||||
|
||||
|
||||
>>> 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)
|
||||
<a class="ui-widget-header ui-widget-link ui-corner-all " id="myaction" onclick="$(#link).click();">
|
||||
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all " href="#" id="myaction" onclick="$(#link).click();">
|
||||
<span class="ui-icon ui-icon-trash"></span>
|
||||
Click here
|
||||
</a>
|
||||
|
||||
"""
|
||||
body = '''
|
||||
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all ${state}"
|
||||
tal:attributes="%(attributes)s">
|
||||
<span class="ui-icon ${icon}"></span>
|
||||
<span tal:replace="label"></span>
|
||||
<span tal:replace="%(label)s"></span>
|
||||
</a>'''
|
||||
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
|
||||
[<UILink delete>, <Link link1>]
|
||||
|
||||
>>> from webob import Request
|
||||
>>> request = Request.blank('/')
|
||||
>>> print actions.render(request) #doctest: +ELLIPSIS
|
||||
<a class="ui-widget-header ...">
|
||||
<span class="ui-icon ui-icon-trash"></span>
|
||||
Delete
|
||||
</a><a href="http://localhost" id="link1">A link</a>
|
||||
|
||||
"""
|
||||
|
||||
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),
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user