merged Dojo 1.0 branch
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2387 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
3f704eb6f9
commit
7ec9bbdc15
32 changed files with 597 additions and 231 deletions
|
@ -1,3 +1,7 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
|
||||
dojoMacroTemplate = ViewPageTemplateFile('macros.pt')
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
i18n_domain="zope">
|
||||
|
||||
<resourceDirectory name="ajax.dojo" directory="dojo" />
|
||||
<!-- <resourceDirectory name="ajax.dojo1" directory="dojo1" /> -->
|
||||
|
||||
<page
|
||||
for="*"
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<metal:def define-macro="main">
|
||||
|
||||
<script type="text/javascript">
|
||||
djConfig = { isDebug: true,
|
||||
parseOnLoad: true };
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="ajax.dojo/dojo.js"
|
||||
tal:attributes="src context/++resource++ajax.dojo/dojo.js">
|
||||
tal:attributes="src context/++resource++ajax.dojo/dojo/dojo.js;
|
||||
djConfig macro/djConfig|nothing">
|
||||
</script>
|
||||
|
||||
</metal:def>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
==================
|
||||
Browser View Tools
|
||||
==================
|
||||
|
||||
|
@ -5,8 +6,9 @@ Browser View Tools
|
|||
>>> from zope.interface import Interface, implements
|
||||
>>> from zope.publisher.interfaces.browser import IBrowserRequest
|
||||
|
||||
|
||||
The Generic View class
|
||||
----------------------
|
||||
======================
|
||||
|
||||
GenericView is intended as the base class for application-specific views.
|
||||
The GenericView class itself provides only basic functionality, so you
|
||||
|
@ -64,7 +66,7 @@ bodyTemplate attribute.
|
|||
|
||||
|
||||
The View Controller
|
||||
-------------------
|
||||
===================
|
||||
|
||||
There is a special view class that does not directly adapt to a real context
|
||||
(i.e. typically a content) object but to a view instead. Thus it can provide
|
||||
|
@ -131,10 +133,11 @@ Calling a macro provided by Controller.macros[] returns the real ZPT macro:
|
|||
The pre-set collection of macros for a certain slot may be extended
|
||||
(this may be done by overriding the view's setupController() method, e.g.):
|
||||
|
||||
>>> controller.macros.register('css', 'node.css', resourceName='node.css', media='all')
|
||||
>>> controller.macros.register('css', 'node.css', resourceName='node.css',
|
||||
... media='all', priority=110)
|
||||
>>> len(controller.macros['css'])
|
||||
5
|
||||
>>> m5 = cssMacros[4]
|
||||
>>> m5 = controller.macros['css'][4]
|
||||
>>> print m5.name, m5.media, m5.resourceName
|
||||
css all node.css
|
||||
|
||||
|
@ -158,7 +161,7 @@ We can also access slots that are not predefined:
|
|||
|
||||
|
||||
The View Configurator
|
||||
---------------------
|
||||
=====================
|
||||
|
||||
A view configurator is typically a multiadapter for a content object that provides
|
||||
a set of properties to be used for setting up special presentation
|
||||
|
@ -167,9 +170,9 @@ characteristics of a page. Typical examples for such characteristics are
|
|||
- the skin to be used
|
||||
- the logo to show in the corner of the page
|
||||
|
||||
The default configurator uses attribute annotations for retrieving view
|
||||
properties; that means that there could be a form somewhere to edit those
|
||||
properties and store them in the content object's annotations.
|
||||
There is a standard configurator that uses attribute annotations for
|
||||
retrieving view properties; that means that there could be a form somewhere
|
||||
to edit those properties and store them in the content object's annotations.
|
||||
|
||||
>>> from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
|
||||
>>> from zope.annotation.attribute import AttributeAnnotations
|
||||
|
@ -179,8 +182,8 @@ The configurator is called automatically from the controller if there is
|
|||
an appropriate adapter:
|
||||
|
||||
>>> from cybertools.browser.configurator import IViewConfigurator
|
||||
>>> from cybertools.browser.configurator import ViewConfigurator
|
||||
>>> component.provideAdapter(ViewConfigurator, (SomeObject, IBrowserRequest),
|
||||
>>> from cybertools.browser.configurator import AnnotationViewConfigurator
|
||||
>>> component.provideAdapter(AnnotationViewConfigurator, (SomeObject, IBrowserRequest),
|
||||
... IViewConfigurator)
|
||||
>>> controller = Controller(view, request)
|
||||
|
||||
|
@ -197,18 +200,9 @@ stored in the attribute annotations. So let's set a 'skinName' attribute:
|
|||
>>> controller.skinName.value
|
||||
'SuperSkin'
|
||||
|
||||
Another way of providing view configurations is using a view configurator
|
||||
as a utility, this can be used for setting view properties by certain
|
||||
packages.
|
||||
|
||||
>>> from cybertools.browser.configurator import GlobalViewConfigurator
|
||||
>>> component.provideUtility(GlobalViewConfigurator())
|
||||
|
||||
>>> gvc = component.getUtility(IViewConfigurator)
|
||||
|
||||
|
||||
Processing form input
|
||||
---------------------
|
||||
=====================
|
||||
|
||||
GenericView also provides an update() method that may be called from
|
||||
templates that might receive form information.
|
||||
|
|
117
browser/action.py
Normal file
117
browser/action.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Base classes (sort of views) for action portlet items.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
from urllib import urlencode
|
||||
from zope import component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
action_macros = ViewPageTemplateFile('action_macros.pt')
|
||||
|
||||
|
||||
class Action(object):
|
||||
|
||||
template = action_macros
|
||||
macroName = 'action'
|
||||
priority = 50
|
||||
condition = True
|
||||
permission = None
|
||||
url = '.'
|
||||
viewName = ''
|
||||
targetWindow = ''
|
||||
title = ''
|
||||
description = ''
|
||||
icon = ''
|
||||
cssClass = ''
|
||||
onClick = ''
|
||||
innerHtmlId = ''
|
||||
prerequisites = []
|
||||
|
||||
def __init__(self, view, **kw):
|
||||
self.view = view
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros[self.macroName]
|
||||
|
||||
@Lazy
|
||||
def url(self):
|
||||
return self.getActionUrl(self.view.url)
|
||||
|
||||
def getActionUrl(self, baseUrl):
|
||||
if self.viewName:
|
||||
return '/'.join((baseUrl, self.viewName))
|
||||
else:
|
||||
return baseUrl
|
||||
|
||||
|
||||
class ActionRegistry(object):
|
||||
""" Use this object (probably as a global utility) to collect all kinds
|
||||
of action definitions that should be available on the system.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.actionsByName = {}
|
||||
self.actionsByCategory = {}
|
||||
|
||||
def register(self, name, category='object', cls=Action, **kw):
|
||||
action = cls(None, name=name, category=category, **kw)
|
||||
nameItem = self.actionsByName.setdefault(name, [])
|
||||
nameItem.append(action)
|
||||
catItem = self.actionsByCategory.setdefault(category, [])
|
||||
catItem.append(action)
|
||||
|
||||
def get(self, category=None, names=[], view=None, **kw):
|
||||
if view is None:
|
||||
raise ValueError("The 'view' argument is missing.")
|
||||
if names:
|
||||
result = []
|
||||
for n in names:
|
||||
result.extend(self.actionsByName.get(n, []))
|
||||
if category is not None:
|
||||
result = [r for r in result if r.category == category]
|
||||
elif category is not None:
|
||||
result = self.actionsByCategory.get(category, [])
|
||||
else:
|
||||
raise ValueError("One of 'name' or 'category' arguments must be given.")
|
||||
for action in sorted(result, key=lambda x: x.priority):
|
||||
action = copy(action)
|
||||
action.view = view
|
||||
for k, v in kw.items():
|
||||
setattr(action, k, v)
|
||||
for p in action.prerequisites:
|
||||
method = p
|
||||
if isinstance(method, str):
|
||||
method = getattr(view, p, None)
|
||||
if method is not None:
|
||||
method()
|
||||
yield action
|
||||
|
||||
|
||||
# TODO: register as a global utility
|
||||
actions = ActionRegistry()
|
||||
|
21
browser/action_macros.pt
Normal file
21
browser/action_macros.pt
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!-- action macros -->
|
||||
|
||||
<metal:action define-macro="action">
|
||||
<div tal:condition="action/condition">
|
||||
<a href="#" target="target_window" title="Description text"
|
||||
tal:attributes="href action/url;
|
||||
target action/targetWindow;
|
||||
title action/description;
|
||||
onClick action/onClick;"
|
||||
i18n:attributes="title"><img src="#" alt="icon"
|
||||
tal:condition="action/icon"
|
||||
tal:attributes="src string:$resourceBase${action/icon};
|
||||
alt action/description" />
|
||||
<span i18n:translate=""
|
||||
tal:condition="action/title"
|
||||
tal:content="action/title">Action Title</span></a>
|
||||
</div>
|
||||
<span id="inner.Id"
|
||||
tal:condition="action/innerHtmlId"
|
||||
tal:attributes="id action/innerHtmlId"></span>
|
||||
</metal:action>
|
|
@ -29,12 +29,7 @@
|
|||
</metal:js>
|
||||
|
||||
|
||||
<metal:portlet define-macro="multi_actions">
|
||||
<tal:sub repeat="macro macro/subMacros">
|
||||
<metal:sub use-macro="macro" />
|
||||
</tal:sub>
|
||||
</metal:portlet>
|
||||
|
||||
<!-- portlets and similar collections of actions -->
|
||||
|
||||
<metal:portlet define-macro="portlet_left">
|
||||
<div metal:use-macro="macro/template/macros/portlet" />
|
||||
|
@ -45,11 +40,27 @@
|
|||
</metal:portlet>
|
||||
|
||||
<metal:portlet define-macro="portlet">
|
||||
<div class="box">
|
||||
<h4 tal:content="macro/title"
|
||||
i18n:translate="">Navigation</h4>
|
||||
<div class="box"
|
||||
tal:define="icon macro/icon|nothing;
|
||||
url macro/url|nothing">
|
||||
<h4>
|
||||
<a tal:omit-tag="not:url"
|
||||
tal:attributes="href url"
|
||||
i18n:translate=""><img
|
||||
tal:condition="icon"
|
||||
tal:attributes="src string:$resourceBase$icon"/>
|
||||
<span tal:content="macro/title">Navigation</span></a>
|
||||
</h4>
|
||||
<div class="body">
|
||||
<div metal:use-macro="macro/subMacro" />
|
||||
</div>
|
||||
</div>
|
||||
</metal:portlet>
|
||||
|
||||
|
||||
<metal:portlet define-macro="multi_actions">
|
||||
<tal:sub repeat="macro macro/subMacros">
|
||||
<metal:sub use-macro="macro" />
|
||||
</tal:sub>
|
||||
</metal:portlet>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,12 +22,11 @@ A view configurator provides configuration data for a view controller.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app import zapi
|
||||
from zope import component
|
||||
from zope.annotation.interfaces import IAttributeAnnotatable, IAnnotations
|
||||
from zope.annotation.attribute import AttributeAnnotations
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.interface import Interface, Attribute, implements
|
||||
from zope.component import adapts
|
||||
|
||||
|
||||
# interfaces
|
||||
|
@ -64,15 +63,28 @@ class IMacroViewProperty(IViewProperty):
|
|||
|
||||
#default implementations
|
||||
|
||||
ANNOTATION_KEY = 'cybertools.browser.configurator.ViewConfigurator'
|
||||
|
||||
class ViewConfigurator(object):
|
||||
""" Simple/basic default adapter using attribute annotations as storage
|
||||
for view properties.
|
||||
""" An base class for adapters that allow the registration of view properties.
|
||||
"""
|
||||
|
||||
implements(IViewConfigurator)
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
self.viewProperties = []
|
||||
|
||||
def getActiveViewProperties(self):
|
||||
return self.viewProperties
|
||||
|
||||
|
||||
ANNOTATION_KEY = 'cybertools.browser.configurator.ViewConfigurator'
|
||||
|
||||
class AnnotationViewConfigurator(ViewConfigurator):
|
||||
""" Simple adapter using attribute annotations as storage
|
||||
for view properties.
|
||||
"""
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
@ -83,19 +95,12 @@ class ViewConfigurator(object):
|
|||
propDefs = ann.get(ANNOTATION_KEY, {})
|
||||
return [self.setupViewProperty(prop, propDef)
|
||||
for prop, propDef in propDefs.items() if propDef]
|
||||
# idea: include properties from GlobalViewConfigurator;
|
||||
# there also may be other view configurators e.g. based on
|
||||
# the class (or some sort of type) of the context object.
|
||||
# Also the view properties may be filtered by permission
|
||||
# or other conditions.
|
||||
# Note: collecting configurators may be solved by getting
|
||||
# multiple configurators (+ utilities) in the controller!
|
||||
|
||||
def getActiveViewProperties(self):
|
||||
return self.viewProperties
|
||||
|
||||
def setupViewProperty(self, prop, propDef):
|
||||
vp = zapi.queryMultiAdapter((self.context, self.request),
|
||||
vp = component.queryMultiAdapter((self.context, self.request),
|
||||
IViewProperty, name=prop)
|
||||
if vp is None:
|
||||
vp = ViewProperty(self.context, self.request)
|
||||
|
@ -104,19 +109,6 @@ class ViewConfigurator(object):
|
|||
return vp
|
||||
|
||||
|
||||
class GlobalViewConfigurator(object):
|
||||
""" A global utility that allows the registration of view properties.
|
||||
"""
|
||||
|
||||
implements(IViewConfigurator)
|
||||
|
||||
def __init__(self):
|
||||
self.viewProperties = []
|
||||
|
||||
def getActiveViewProperties(self):
|
||||
return self.viewProperties
|
||||
|
||||
|
||||
class ViewProperty(object):
|
||||
|
||||
implements(IViewProperty)
|
||||
|
@ -136,7 +128,7 @@ class ViewProperty(object):
|
|||
self.params = params
|
||||
|
||||
|
||||
class MacroViewProperty(object):
|
||||
class MacroViewProperty(ViewProperty):
|
||||
|
||||
implements(IMacroViewProperty)
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
i18n_domain="zope"
|
||||
>
|
||||
|
||||
<resourceDirectory name="cybertools.icons" directory="icons" />
|
||||
|
||||
<page for="*"
|
||||
name="main.html"
|
||||
template="main.pt"
|
||||
|
@ -25,10 +27,16 @@
|
|||
permission="zope.Public"
|
||||
/>
|
||||
|
||||
<page name="controller"
|
||||
<!--<page name="controller"
|
||||
for="zope.publisher.interfaces.browser.IBrowserView"
|
||||
class="cybertools.browser.controller.Controller"
|
||||
permission="zope.Public"
|
||||
/>-->
|
||||
|
||||
<zope:adapter
|
||||
for="* zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
factory="cybertools.browser.member.MemberInfoProvider"
|
||||
permission="zope.Public"
|
||||
/>
|
||||
|
||||
<!-- a tableless layout skin -->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -27,6 +27,8 @@ from zope.app.pagetemplate import ViewPageTemplateFile
|
|||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from cybertools.browser.configurator import IViewConfigurator, IMacroViewProperty
|
||||
from cybertools.browser.member import IMemberInfoProvider
|
||||
from cybertools.util.jeep import Jeep
|
||||
|
||||
|
||||
# layout controller: collects information about head elements, skins, portlets, etc
|
||||
|
@ -54,15 +56,11 @@ class Controller(object):
|
|||
return self.request.URL[0] + skinSetter + '/@@/'
|
||||
|
||||
def configure(self):
|
||||
#configurator = component.queryMultiAdapter((self.context, self.request),
|
||||
# IViewConfigurator)
|
||||
# idea: collect multiple configurators:
|
||||
# collect multiple configurators:
|
||||
configurators = component.getAdapters((self.context, self.request),
|
||||
IViewConfigurator)
|
||||
for conf in configurators:
|
||||
configurator = conf[1]
|
||||
#if configurator is not None:
|
||||
#for item in configurator.viewProperties:
|
||||
for item in configurator.getActiveViewProperties():
|
||||
if IMacroViewProperty.providedBy(item):
|
||||
self.macros.register(item.slot, item.idenitifier,
|
||||
|
@ -71,6 +69,12 @@ class Controller(object):
|
|||
else:
|
||||
setattr(self, item.slot, item)
|
||||
|
||||
@Lazy
|
||||
def memberInfo(self):
|
||||
provider = component.queryMultiAdapter((self.context, self.request),
|
||||
IMemberInfoProvider)
|
||||
return provider is not None and provider.data or None
|
||||
|
||||
|
||||
class Macros(dict):
|
||||
|
||||
|
@ -81,7 +85,7 @@ class Macros(dict):
|
|||
self.identifiers = set()
|
||||
|
||||
def register(self, slot, identifier=None, template=None, name=None,
|
||||
position=None, **kw):
|
||||
priority=50, **kw):
|
||||
if identifier:
|
||||
# make sure a certain resource is only registered once
|
||||
if identifier in self.identifiers:
|
||||
|
@ -91,22 +95,20 @@ class Macros(dict):
|
|||
template = self.standardTemplate
|
||||
if name is None:
|
||||
name = slot
|
||||
macro = Macro(template, name, **kw)
|
||||
macro = Macro(template, name, priority, **kw)
|
||||
entry = self.setdefault(slot, [])
|
||||
if position is None:
|
||||
entry.append(macro)
|
||||
else:
|
||||
entry.insert(position, macro)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.get(key, [])
|
||||
return list(sorted(self.get(key, []), key=lambda x: x.priority))
|
||||
|
||||
|
||||
class Macro(object):
|
||||
|
||||
def __init__(self, template, name, **kw):
|
||||
def __init__(self, template, name, priority, **kw):
|
||||
self.template = template
|
||||
self.name = name
|
||||
self.priority = priority
|
||||
for k in kw:
|
||||
setattr(self, k, kw[k])
|
||||
|
||||
|
|
BIN
browser/icons/user.png
Normal file
BIN
browser/icons/user.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 741 B |
|
@ -28,75 +28,4 @@ body {
|
|||
#menu {width:20%}
|
||||
#content {width:62%}
|
||||
#sub-section {width:17%}
|
||||
#footer {clear:left}
|
||||
|
||||
/* more general stuff */
|
||||
|
||||
.top image {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
div.box {
|
||||
margin: 12px 12px 8px 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
div.box h4 {
|
||||
font: 110% Verdana, Tahoma, Arial, Helvetica, sans-serif;
|
||||
color: #000040;
|
||||
border: none;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 4px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 3px;
|
||||
background-color: #ddd;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
table.listing {
|
||||
margin: 1px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
table.listing th {
|
||||
font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;
|
||||
color: #000040;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
margin-top: 12px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.itemViews {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 1em 0 1em 0;
|
||||
}
|
||||
|
||||
.button a, .button a:visited {
|
||||
padding: 2px 4px 2px 4px;
|
||||
background-color: #e8e8e8;
|
||||
text-decoration: None;
|
||||
color: Black;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-color: #f4f4f4 #989898 #989898 #f4f4f4;
|
||||
}
|
||||
|
||||
.button a:active {
|
||||
border-color: #989898 #f4f4f4 #f4f4f4 #989898;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
#footer { border-bottom: none; }
|
||||
|
||||
#footer {clear:left; float:left}
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
layer="cybertools.browser.liquid.Liquid" />
|
||||
<resource name="print.css" file="print.css"
|
||||
layer="cybertools.browser.liquid.Liquid" />
|
||||
<resource name="presentation.css" file="presentation.css"
|
||||
layer="cybertools.browser.liquid.Liquid" />
|
||||
<resource name="custom.css" file="custom.css"
|
||||
layer="cybertools.browser.liquid.Liquid" />
|
||||
|
||||
|
|
|
@ -28,19 +28,26 @@ from cybertools.browser.controller import Controller as BaseController
|
|||
class Controller(BaseController):
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.view = view = context # the controller is adapted to a view
|
||||
self.context = context.context
|
||||
self.request = request
|
||||
self.setupCss()
|
||||
self.setupJs()
|
||||
super(Controller, self).__init__(context, request)
|
||||
|
||||
def setupCss(self):
|
||||
macros = self.macros
|
||||
params = [('zope3_tablelayout.css', 'all'),
|
||||
('base.css', 'screen'),
|
||||
('print.css', 'print'),
|
||||
('custom.css', 'all')]
|
||||
presentationMode = self.request.get('liquid.viewmode') == 'presentation'
|
||||
params = [('zope3_tablelayout.css', 'all', 20),
|
||||
('base.css', 'screen', 25),
|
||||
('print.css', 'print', 30),
|
||||
('custom.css', 'all', 100)]
|
||||
if presentationMode:
|
||||
params.append(('presentation.css', 'all', 30))
|
||||
for param in params:
|
||||
macros.register('css', identifier=param[0],
|
||||
resourceName=param[0], media=param[1])
|
||||
resourceName=param[0], media=param[1],
|
||||
priority=param[2])
|
||||
|
||||
def setupJs(self):
|
||||
return
|
||||
|
|
21
browser/liquid/presentation.css
Normal file
21
browser/liquid/presentation.css
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
$Id$
|
||||
|
||||
*/
|
||||
|
||||
.body {
|
||||
margin: 4em;
|
||||
}
|
||||
|
||||
.top, #header, #menu, #sub-section, #footer, #xedit_icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 100%;
|
||||
color: #000077;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
color: #005599;
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
/*
|
||||
** Zope3 style sheet for CSS2-capable browsers.
|
||||
** For future skin see zope.app.boston.
|
||||
*/
|
||||
|
||||
/*
|
||||
* { border: 1px dotted red }
|
||||
**
|
||||
** $Id$
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
@ -31,7 +29,7 @@ table {
|
|||
font-size: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
a[href] {
|
||||
text-decoration: none;
|
||||
color: #369;
|
||||
background-color: transparent;
|
||||
|
@ -46,11 +44,6 @@ img {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5em 0em 1em 0em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
p a:visited {
|
||||
color: Purple;
|
||||
background-color: transparent;
|
||||
|
@ -80,7 +73,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||
clear: left;
|
||||
font: 100% bold Verdana, Helvetica, Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding-top: 0.5em;
|
||||
padding-top: 0;
|
||||
border-bottom: 1px solid #369;
|
||||
}
|
||||
|
||||
|
@ -109,7 +102,7 @@ h6 {
|
|||
}
|
||||
|
||||
ul {
|
||||
line-height: 1.5em;
|
||||
line-height: 1.2em;
|
||||
/* list-style-image: url("bullet.gif"); */
|
||||
margin-left: 2em;
|
||||
padding:0;
|
||||
|
@ -411,9 +404,6 @@ div.box h4 {
|
|||
}
|
||||
|
||||
|
||||
#content {
|
||||
}
|
||||
|
||||
#context_information {
|
||||
padding-top: 1em;
|
||||
width: 15%;
|
||||
|
@ -425,18 +415,6 @@ div.box h4 {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
#helpers {
|
||||
}
|
||||
|
||||
#inspectors {
|
||||
}
|
||||
|
||||
#footer {
|
||||
border-bottom: 1px solid black;
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
input.textType {
|
||||
width: 88%; /* Same as textarea */
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
<base href="." tal:attributes="href request/URL">
|
||||
</head>
|
||||
|
||||
<body tal:content="structure body" />
|
||||
<body class="tundra"
|
||||
tal:content="structure body" />
|
||||
|
||||
</html>
|
||||
</metal:block>
|
||||
|
|
111
browser/member.py
Normal file
111
browser/member.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
A member information provider is used to collect user/member/person attributes.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import component
|
||||
from zope.app.security.interfaces import IAuthentication
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.interface import Interface, Attribute, implements
|
||||
|
||||
from cybertools.util.jeep import Jeep
|
||||
|
||||
|
||||
# interfaces
|
||||
|
||||
class IMemberInfoProvider(Interface):
|
||||
""" Usually implemented by an adapter; provides a set of
|
||||
user/member/person properties.
|
||||
"""
|
||||
|
||||
priority = Attribute('A number denoting the priority of the provider; '
|
||||
'a provider with a high number may be overriden with a lower number.')
|
||||
|
||||
data = Attribute('A collection/ordered mapping of member property objects '
|
||||
'for the currently logged-in user.')
|
||||
|
||||
def getData(principalId):
|
||||
""" Return the member properties for the principal identified by
|
||||
the principal id given.
|
||||
"""
|
||||
|
||||
def getDataForCategory(category, principalId=None):
|
||||
""" Return a collection of the properties for the category given.
|
||||
If no principal id is given use the currently logged-in user.
|
||||
"""
|
||||
|
||||
|
||||
class IMemberProperty(Interface):
|
||||
|
||||
name = Attribute('The name/identifier of the property.')
|
||||
title = Attribute('A short and descriptive title.')
|
||||
category = Attribute('A string denoting a category or classification.')
|
||||
|
||||
|
||||
#default implementation
|
||||
|
||||
class MemberProperty(object):
|
||||
|
||||
implements(IMemberProperty)
|
||||
|
||||
def __init__(self, name, value, title=None, category='default'):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.title = title or name
|
||||
self.category = category
|
||||
|
||||
|
||||
class MemberInfoProvider(object):
|
||||
|
||||
implements(IMemberInfoProvider)
|
||||
|
||||
defaultData = Jeep((MemberProperty('id', '???', u'ID'),
|
||||
MemberProperty('title', u'unknown', u'Title'),
|
||||
MemberProperty('description', u'',
|
||||
u'Description'),
|
||||
))
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
@Lazy
|
||||
def data(self):
|
||||
return self.getData()
|
||||
|
||||
def getData(self, principalId=None):
|
||||
if principalId is None:
|
||||
principal = self.request.principal
|
||||
else:
|
||||
pau = component.getUtility(IAuthentication)
|
||||
principal = pau.getPrincipal(principalId)
|
||||
if principal is not None:
|
||||
return self.getPrincipalData(principal)
|
||||
else:
|
||||
return self.defaultData
|
||||
|
||||
def getPrincipalData(self, principal):
|
||||
return Jeep((MemberProperty('id', principal.id, u'ID'),
|
||||
MemberProperty('title', principal.title, u'Title'),
|
||||
MemberProperty('description', principal.description,
|
||||
u'Description'),
|
||||
))
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -58,14 +58,19 @@ class GenericView(object):
|
|||
# make the (one and only controller) available via the request
|
||||
viewAnnotations = self.request.annotations.setdefault('cybertools.browser', {})
|
||||
viewAnnotations['controller'] = controller
|
||||
if getattr(controller, 'skinName', None) and controller.skinName.value:
|
||||
self.setSkin(controller.skinName.value)
|
||||
#if getattr(controller, 'skinName', None) and controller.skinName.value:
|
||||
# self.setSkin(controller.skinName.value)
|
||||
controller.skin = self.skin
|
||||
# this is the place to register special macros with the controller:
|
||||
self.setupController()
|
||||
def getController(self):
|
||||
viewAnnotations = self.request.annotations.setdefault('cybertools.browser', {})
|
||||
return viewAnnotations.get('controller', None)
|
||||
cont = viewAnnotations.get('controller', None)
|
||||
if cont is None:
|
||||
cont = component.queryMultiAdapter((self, self.request), name='controller')
|
||||
if cont is not None:
|
||||
self.setController(cont)
|
||||
return cont
|
||||
controller = property(getController, setController)
|
||||
|
||||
def __init__(self, context, request):
|
||||
|
@ -119,4 +124,3 @@ class GenericView(object):
|
|||
applySkin(self.request, skin)
|
||||
self.skin = skin
|
||||
|
||||
|
||||
|
|
|
@ -167,5 +167,6 @@ Macros / renderers
|
|||
|
||||
>>> fieldRenderers = form.fieldRenderers
|
||||
>>> sorted(fieldRenderers.keys())
|
||||
[u'field', u'field_spacer', u'fields', u'form', u'input_date', u'input_dropdown',
|
||||
u'input_fileupload', u'input_password', u'input_textarea', u'input_textline']
|
||||
[u'field', u'field_spacer', u'fields', u'form', u'input_checkbox',
|
||||
u'input_date', u'input_dropdown', u'input_fileupload', u'input_html',
|
||||
u'input_password', u'input_textarea', u'input_textline']
|
||||
|
|
|
@ -80,20 +80,27 @@
|
|||
<metal:textline define-macro="input_textline">
|
||||
<input type="text" name="field" style="width: 450px"
|
||||
tal:define="width field/width|nothing"
|
||||
tal:attributes="name name;
|
||||
tal:attributes="name name; id name;
|
||||
style python:
|
||||
'width: %s' % (width and str(width)+'px' or '450px');
|
||||
value data/?name|string:" />
|
||||
value data/?name|string:;
|
||||
required field/required_js;" />
|
||||
</metal:textline>
|
||||
|
||||
|
||||
<metal:textline define-macro="input_date">
|
||||
<input type="text" name="field" style="width: 450px"
|
||||
<input type="text" name="field" style="width: 8em"
|
||||
dojoType="dijit.form.DateTextBox"
|
||||
tal:define="width field/width|nothing"
|
||||
tal:attributes="name name;
|
||||
style python:
|
||||
'width: %s' % (width and str(width)+'px' or '450px');
|
||||
value data/?name|string:" />
|
||||
value data/?name|string:;
|
||||
required field/required_js" />
|
||||
<input type="text" name="field" style="width: 6em"
|
||||
dojoType="dijit.form.TimeTextBox"
|
||||
tal:define="width field/width|nothing"
|
||||
tal:attributes="name name;
|
||||
value data/?name|string:;
|
||||
required field/required_js" />
|
||||
</metal:textline>
|
||||
|
||||
|
||||
|
@ -120,12 +127,24 @@
|
|||
</metal:textarea>
|
||||
|
||||
|
||||
<metal:html define-macro="input_html">
|
||||
<metal:textarea use-macro="view/fieldRenderers/input_textarea" />
|
||||
</metal:html>
|
||||
|
||||
|
||||
<metal:upload define-macro="input_fileupload">
|
||||
<input type="file" name="field"
|
||||
tal:attributes="name name;" />
|
||||
</metal:upload>
|
||||
|
||||
|
||||
<metal:checkbox define-macro="input_checkbox">
|
||||
<input type="checkbox" name="field" value="true"
|
||||
tal:attributes="name name;
|
||||
checked data/?name|nothing" />
|
||||
</metal:checkbox>
|
||||
|
||||
|
||||
<metal:dropdown define-macro="input_dropdown">
|
||||
<select name="field" style="width: auto"
|
||||
tal:define="width field/width|nothing"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,10 +42,12 @@ class SchemaFactory(object):
|
|||
|
||||
fieldMapping = {
|
||||
schema.TextLine: ('textline',),
|
||||
schema.ASCIILine: ('textline',),
|
||||
schema.Password: ('password',),
|
||||
schema.ASCII: ('textline',),
|
||||
schema.Text: ('textarea',),
|
||||
schema.ASCII: ('textarea',),
|
||||
schema.Date: ('date',),
|
||||
schema.Datetime: ('date',),
|
||||
schema.Int: ('number',),
|
||||
schema.Bool: ('checkbox',),
|
||||
schema.Choice: ('dropdown',),
|
||||
|
@ -68,7 +70,7 @@ class SchemaFactory(object):
|
|||
fieldType=info[0],
|
||||
required=field.required,
|
||||
default=field.default,
|
||||
#default_method=getattr(field, 'default_method', None),
|
||||
default_method=getattr(field, 'default_method', None),
|
||||
vocabulary=voc,
|
||||
title=field.title,
|
||||
description=field.description,
|
||||
|
|
|
@ -22,9 +22,13 @@ Schema fields and related classes.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from time import strptime, strftime
|
||||
from zope.interface import implements
|
||||
from zope.component import adapts
|
||||
from zope import component
|
||||
from zope.i18n.format import DateTimeParseError
|
||||
from zope.i18n.locales import locales
|
||||
|
||||
from cybertools.composer.base import Component
|
||||
from cybertools.composer.schema.interfaces import IField, IFieldInstance
|
||||
|
@ -44,6 +48,7 @@ class Field(Component):
|
|||
vocabulary = None
|
||||
renderFactory = None
|
||||
default = None
|
||||
default_method = None
|
||||
|
||||
def __init__(self, name, title=None, fieldType='textline', **kw):
|
||||
assert name
|
||||
|
@ -60,8 +65,8 @@ class Field(Component):
|
|||
return self.__name__
|
||||
|
||||
def getDefaultValue(self):
|
||||
if callable(self.default):
|
||||
return self.default()
|
||||
if callable(self.default_method):
|
||||
return self.default_method()
|
||||
return self.default
|
||||
def setDefaultValue(self, value):
|
||||
self.default = value
|
||||
|
@ -79,6 +84,10 @@ class Field(Component):
|
|||
def storeData(self):
|
||||
return not self.nostore and self.getFieldTypeInfo().storeData
|
||||
|
||||
@property
|
||||
def required_js(self):
|
||||
return self.required and 'true' or 'false'
|
||||
|
||||
def getTitleValue(self):
|
||||
return self.title or self.name
|
||||
|
||||
|
@ -105,6 +114,8 @@ class FieldInstance(object):
|
|||
implements(IFieldInstance)
|
||||
adapts(IField)
|
||||
|
||||
clientInstance = None
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self.name = self.__name__ = context.name
|
||||
|
@ -112,6 +123,15 @@ class FieldInstance(object):
|
|||
self.severity = 0
|
||||
self.change = None
|
||||
|
||||
@property
|
||||
def default(self):
|
||||
dm = self.context.default_method
|
||||
if dm and isinstance(dm, str) and self.clientInstance:
|
||||
method = getattr(self.clientInstance.context, dm, None)
|
||||
if method:
|
||||
return method()
|
||||
return self.context.defaultValue
|
||||
|
||||
def marshall(self, value):
|
||||
return value or u''
|
||||
#return toStr(value)
|
||||
|
@ -156,11 +176,47 @@ class NumberFieldInstance(FieldInstance):
|
|||
self.setError('required_missing')
|
||||
else:
|
||||
try:
|
||||
int(value)
|
||||
self.unmarshall(value)
|
||||
except (TypeError, ValueError):
|
||||
self.setError('invalid_number')
|
||||
|
||||
|
||||
class DateFieldInstance(NumberFieldInstance):
|
||||
|
||||
def marshall(self, value):
|
||||
if value is None:
|
||||
return ''
|
||||
return strftime('%Y-%m-%dT%H:%M', value.timetuple())
|
||||
|
||||
def display(self, value):
|
||||
if value is None:
|
||||
return ''
|
||||
view = self.clientInstance.view
|
||||
langInfo = view and view.languageInfo or None
|
||||
if langInfo:
|
||||
locale = locales.getLocale(langInfo.language)
|
||||
fmt = locale.dates.getFormatter('dateTime', 'short')
|
||||
return fmt.format(value)
|
||||
return str(value)
|
||||
|
||||
def unmarshall(self, value):
|
||||
if not value:
|
||||
return None
|
||||
value = ''.join(value)
|
||||
return datetime(*(strptime(value, '%Y-%m-%dT%H:%M:%S')[:6]))
|
||||
|
||||
def validate(self, value, data=None):
|
||||
if value in ('', None):
|
||||
if self.context.required:
|
||||
self.setError('required_missing')
|
||||
else:
|
||||
try:
|
||||
self.unmarshall(value)
|
||||
except (TypeError, ValueError, DateTimeParseError), e:
|
||||
print '*** invalid_datetime:', value, e
|
||||
self.setError('invalid_datetime')
|
||||
|
||||
|
||||
class FileUploadFieldInstance(FieldInstance):
|
||||
|
||||
def marshall(self, value):
|
||||
|
@ -177,6 +233,19 @@ class EmailFieldInstance(FieldInstance):
|
|||
self.setError('invalid_email_address')
|
||||
|
||||
|
||||
class BooleanFieldInstance(FieldInstance):
|
||||
|
||||
def marshall(self, value):
|
||||
return value
|
||||
|
||||
def display(self, value):
|
||||
#return value and _(u'Yes') or _(u'No')
|
||||
return value and u'X' or u'-'
|
||||
|
||||
def unmarshall(self, value):
|
||||
return bool(value)
|
||||
|
||||
|
||||
class CalculatedFieldInstance(FieldInstance):
|
||||
|
||||
def marshall(self, value):
|
||||
|
|
|
@ -52,8 +52,8 @@ class Instance(BaseInstance):
|
|||
continue
|
||||
fi = f.getFieldInstance(self)
|
||||
name = f.name
|
||||
value = getattr(self.context, name, f.defaultValue)
|
||||
#value = getattr(self.context, name, u'')
|
||||
#value = getattr(self.context, name, f.defaultValue)
|
||||
value = getattr(self.context, name) or fi.default
|
||||
value = (mode == 'view' and fi.display(value)) or fi.marshall(value)
|
||||
result[name] = value
|
||||
return result
|
||||
|
@ -103,7 +103,7 @@ class Editor(BaseInstance):
|
|||
for f in self.template.components:
|
||||
if f.readonly:
|
||||
continue
|
||||
fi = f.getFieldInstance()
|
||||
fi = f.getFieldInstance(self)
|
||||
value = data.get(f.name)
|
||||
fi.validate(value, data)
|
||||
formState.fieldInstances.append(fi)
|
||||
|
|
|
@ -84,14 +84,15 @@ fieldTypes = SimpleVocabulary((
|
|||
FieldType('textline', 'textline', u'Textline'),
|
||||
FieldType('password', 'password', u'Password'),
|
||||
FieldType('textarea', 'textarea', u'Textarea'),
|
||||
FieldType('html', 'html', u'HTML Text'),
|
||||
FieldType('number', 'number', u'Number',
|
||||
inputRenderer='input_textline', instanceName='number'),
|
||||
FieldType('date', 'date', u'Date'),
|
||||
FieldType('date', 'date', u'Date', instanceName='date'),
|
||||
FieldType('email', 'email', u'E-Mail Address',
|
||||
inputRenderer='input_textline', instanceName='email'),
|
||||
FieldType('fileupload', 'fileupload', u'File upload',
|
||||
instanceName='fileupload'),
|
||||
#FieldType('checkbox', 'checkbox', u'Checkbox'),
|
||||
FieldType('checkbox', 'checkbox', u'Checkbox', instanceName='boolean'),
|
||||
FieldType('dropdown', 'dropdown', u'Drop-down selection'),
|
||||
#FieldType('listbox', 'listbox', u'List box (multiple selection)'),
|
||||
FieldType('calculated', 'display', u'Calculated Value',
|
||||
|
|
|
@ -90,6 +90,8 @@ formErrors = dict(
|
|||
u'Please enter data for required field.'),
|
||||
invalid_number=FormError(u'Invalid number',
|
||||
u'Please enter a number, only digits allowed.'),
|
||||
invalid_datetime=FormError(u'Invalid date/time',
|
||||
u'Please enter a string denoting a valid date/time.'),
|
||||
invalid_email_address=FormError(u'Invalid E-Mail Address',
|
||||
u'Please enter a valid email address.'),
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -24,14 +24,18 @@ $Id$
|
|||
|
||||
import csv
|
||||
from cStringIO import StringIO
|
||||
import itertools
|
||||
from zope import component
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from cybertools.composer.interfaces import IInstance
|
||||
from cybertools.composer.schema.interfaces import ISchema
|
||||
from cybertools.stateful.interfaces import IStateful
|
||||
|
||||
|
||||
class RegistrationsExportCsv(object):
|
||||
|
||||
encoding = 'ISO8859-15'
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
@ -55,32 +59,75 @@ class RegistrationsExportCsv(object):
|
|||
state = IStateful(reg).getStateObject()
|
||||
if state.name == 'temporary' and not withTemporary:
|
||||
continue
|
||||
yield [encode(service.title) or service.name,
|
||||
yield [self.encode(service.title) or service.name,
|
||||
clientName,
|
||||
encode(data.get('standard.organization', '')),
|
||||
encode(data.get('standard.lastName', '')),
|
||||
encode(data.get('standard.firstName', '')),
|
||||
encode(data.get('standard.email', '')),
|
||||
self.encode(data.get('standard.organization', '')),
|
||||
self.encode(data.get('standard.lastName', '')),
|
||||
self.encode(data.get('standard.firstName', '')),
|
||||
self.encode(data.get('standard.email', '')),
|
||||
reg.number,
|
||||
state.title
|
||||
]
|
||||
|
||||
def getAllDataInColumns(self):
|
||||
""" Yield all data available, with a column for each service and
|
||||
columns for all data fields of all data templates.
|
||||
"""
|
||||
withTemporary = self.request.get('with_temporary')
|
||||
context = self.context
|
||||
services = context.getServices()
|
||||
schemas = [s for s in context.getClientSchemas() if ISchema.providedBy(s)]
|
||||
yield (['Client ID']
|
||||
+ list(itertools.chain(*[[self.encode(f.title)
|
||||
for f in s.fields]
|
||||
for s in schemas]))
|
||||
+ [self.encode(s.title) for s in services])
|
||||
clients = context.getClients()
|
||||
for name, client in clients.items():
|
||||
hasRegs = False
|
||||
regs = []
|
||||
for service in services:
|
||||
reg = service.registrations.get(name)
|
||||
if reg is None:
|
||||
regs.append(0)
|
||||
else:
|
||||
state = IStateful(reg).getStateObject()
|
||||
if state.name == 'temporary' and not withTemporary:
|
||||
regs.append(0)
|
||||
else:
|
||||
number = reg.number
|
||||
regs.append(reg.number)
|
||||
if number:
|
||||
hasRegs = True
|
||||
if not hasRegs:
|
||||
continue
|
||||
result = [name]
|
||||
for schema in schemas:
|
||||
instance = IInstance(client)
|
||||
instance.template = schema
|
||||
data = instance.applyTemplate()
|
||||
for f in schema.fields:
|
||||
result.append(self.encode(data.get(f.name, '')))
|
||||
result += regs
|
||||
yield result
|
||||
|
||||
def render(self):
|
||||
methodName = self.request.get('get_data_method', 'getAllDataInColumns')
|
||||
method = getattr(self, methodName, self.getData)
|
||||
output = StringIO()
|
||||
csv.writer(output).writerows(self.getData())
|
||||
csv.writer(output, dialect='excel', delimiter=';').writerows(method())
|
||||
result = output.getvalue()
|
||||
self.setHeaders(len(result))
|
||||
return result
|
||||
|
||||
def render2(self):
|
||||
# using cybertools.reporter.resultset
|
||||
rs = self.getData() # returns a ResultSet
|
||||
rs = self.getData() # should return a ResultSet
|
||||
result = rs.asCsv()
|
||||
self.setHeaders(len(result))
|
||||
return result
|
||||
|
||||
|
||||
def encode(text, encoding='UTF-8'):
|
||||
def encode(self, text):
|
||||
if type(text) is unicode:
|
||||
text = text.encode(encoding)
|
||||
text = text.encode(self.encoding)
|
||||
return text
|
||||
|
|
|
@ -204,10 +204,10 @@ class CheckoutView(ServiceManagerView):
|
|||
regs = sorted(regs.getRegistrations(), key=self.sortKey)
|
||||
for reg in regs:
|
||||
service = reg.service
|
||||
result.append(dict(service=service.title,
|
||||
result.append(dict(service=service.title or '???',
|
||||
fromTo=self.getFromTo(service),
|
||||
location=service.location,
|
||||
locationUrl=service.locationUrl,
|
||||
location=service.location or '',
|
||||
locationUrl=service.locationUrl or '',
|
||||
number=reg.number,
|
||||
serviceObject=service))
|
||||
return result
|
||||
|
@ -225,7 +225,7 @@ class CheckoutView(ServiceManagerView):
|
|||
result = []
|
||||
for info in self.getRegistrationsInfo():
|
||||
location, locationUrl = info['location'], info['locationUrl']
|
||||
if locationUrl.startswith('/'):
|
||||
if locationUrl and locationUrl.startswith('/'):
|
||||
locationUrl = self.request.get('SERVER_URL') + locationUrl
|
||||
locationInfo = (locationUrl and '%s (%s)' % (location, locationUrl)
|
||||
or location)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2005 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -37,7 +37,7 @@ class CachedImage(object):
|
|||
def __init__(self, path, name=None):
|
||||
self.path = path
|
||||
if name is None:
|
||||
self.name = randomname.generateName(lambda x: x not in cachedImages)
|
||||
self.name = randomname.generateName(lambda x: x not in cachedImages.keys())
|
||||
else:
|
||||
self.name = name
|
||||
self.timeStamp = int(time.time())
|
||||
|
|
|
@ -33,7 +33,7 @@ def htmlToText(html):
|
|||
data = []
|
||||
soup = BeautifulSoup(html).html
|
||||
collectText([soup], data)
|
||||
text = u' '.join(data).replace('\n', '').replace(' ', '')
|
||||
text = u' '.join(data).replace(u'\n', u'').replace(u' ', u'')
|
||||
return text
|
||||
|
||||
def collectText(tags, data):
|
||||
|
|
|
@ -45,4 +45,5 @@ class PptTransform(base.BaseFileTransform):
|
|||
else:
|
||||
html = self.execute('ppthtml "%s" 2> /dev/null' % filename)
|
||||
data = htmlToText(html)
|
||||
return data.decode('ISO8859-15')
|
||||
return data
|
||||
#return data.decode('ISO8859-15')
|
||||
|
|
|
@ -4,6 +4,9 @@ Setting Configuration Options
|
|||
|
||||
$Id$
|
||||
|
||||
(TO DO / exercises: try to formulate a typical buildout.cfg, a configure.zcml,
|
||||
or a generic setup configuration file using this syntax.)
|
||||
|
||||
>>> from cybertools import util
|
||||
>>> from cybertools.util.config import Configurator
|
||||
>>> config = Configurator()
|
||||
|
@ -93,6 +96,30 @@ The simplified syntax
|
|||
|
||||
>>> #print config
|
||||
|
||||
A better simplified syntax
|
||||
--------------------------
|
||||
|
||||
Open a section with the ``use`` method.
|
||||
|
||||
use(ui.web)
|
||||
port = 11080
|
||||
|
||||
use(crawl[1])
|
||||
type = 'outlook'
|
||||
folder = 'inbox'
|
||||
|
||||
or - even more better...
|
||||
|
||||
use(ui.web,
|
||||
port=11080,
|
||||
)
|
||||
|
||||
use(crawl[1],
|
||||
type='outlook',
|
||||
folder='inbox',
|
||||
)
|
||||
|
||||
|
||||
Cleaning up
|
||||
-----------
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue