5
from zope.security.proxy import ProxyFactory
7
from chameleon.i18n import fast_translate
8
from chameleon.zpt import template
9
from chameleon.tales import StringExpr
10
from chameleon.tales import NotExpr
11
from chameleon.compiler import ExpressionEvaluator
13
from z3c.pt import expressions
16
from Missing import MV
24
BOOLEAN_HTML_ATTRS = frozenset([
25
# List of Boolean attributes in HTML that should be rendered in
26
# minimized form (e.g. <img ismap> rather than <img ismap="">)
27
# From http://www.w3.org/TR/xhtml1/#guidelines (C.10)
28
# TODO: The problem with this is that this is not valid XML and
29
# can't be parsed back!
30
"compact", "nowrap", "ismap", "declare", "noshade", "checked",
31
"disabled", "readonly", "multiple", "selected", "noresize",
36
class OpaqueDict(dict):
37
def __new__(cls, dictionary):
38
inst = dict.__new__(cls)
39
inst.dictionary = dictionary
43
def __getitem__(self):
44
return self.dictionary.__getitem__
48
return self.dictionary.__len__
51
return "{...} (%d entries)" % len(self)
53
sys_modules = ProxyFactory(OpaqueDict(sys.modules))
56
class DummyRegistry(object):
57
"""This class is for B/W with Chameleon 1.x API."""
64
class BaseTemplate(template.PageTemplate):
68
registry = DummyRegistry()
71
'python': expressions.PythonExpr,
74
'exists': expressions.ExistsExpr,
75
'path': expressions.PathExpr,
76
'provider': expressions.ProviderExpr,
77
'nocall': expressions.NocallExpr,
80
default_expression = "path"
87
def boolean_attributes(self):
88
if self.content_type == 'text/xml':
91
return BOOLEAN_HTML_ATTRS
97
'modules': sys_modules,
100
tales = ExpressionEvaluator(self.engine, builtins)
101
builtins['tales'] = tales
105
def bind(self, ob, request=None):
106
def render(request=request, **kwargs):
107
context = self._pt_get_context(ob, request, kwargs)
108
return self.render(**context)
110
return BoundPageTemplate(self, render)
112
def render(self, target_language=None, **context):
113
# We always include a ``request`` variable; it is (currently)
114
# depended on in various expression types and must be defined
115
request = context.setdefault('request', None)
117
if target_language is None:
118
if hasattr(request, "get"):
119
target_language = request.get("LANGUAGE", None)
120
if target_language is None:
122
target_language = i18n.negotiate(request)
124
target_language = None
126
context['target_language'] = target_language
128
# bind translation-method to request
130
msgid, domain=None, mapping=None,
131
target_language=None, default=None):
133
# Special case handling of Zope2's Missing.MV
134
# (Missing.Value) used by the ZCatalog but is
137
return fast_translate(
138
msgid, domain, mapping, request, target_language, default)
139
context["translate"] = translate
141
if request is not None and not isinstance(request, basestring):
142
content_type = self.content_type or 'text/html'
143
response = request.response
144
if response and not response.getHeader("Content-Type"):
146
"Content-Type", content_type)
148
base_renderer = super(BaseTemplate, self).render
149
return base_renderer(**context)
151
def __call__(self, *args, **kwargs):
152
bound_pt = self.bind(self)
153
return bound_pt(*args, **kwargs)
155
def _pt_get_context(self, instance, request, kwargs):
165
class BaseTemplateFile(BaseTemplate, template.PageTemplateFile):
166
"""If ``filename`` is a relative path, the module path of the
167
class where the instance is used to get an absolute path."""
171
def __init__(self, filename, path=None, content_type=None, **kwargs):
173
filename = os.path.join(path, filename)
175
if not os.path.isabs(filename):
177
frame = sys._getframe(depth)
178
package_name = frame.f_globals.get('__name__', None)
179
if package_name is not None and \
180
package_name != self.__module__:
181
module = sys.modules[package_name]
183
path = module.__path__[0]
184
except AttributeError:
185
path = module.__file__
186
path = path[:path.rfind(os.sep)]
189
package_path = frame.f_globals.get('__file__', None)
190
if package_path is not None:
191
path = os.path.dirname(package_path)
195
filename = os.path.join(path, filename)
197
template.PageTemplateFile.__init__(
198
self, filename, **kwargs)
200
# Set content-type last, so that we can override whatever was
201
# magically sniffed from the source template.
202
self.content_type = content_type
205
class PageTemplate(BaseTemplate):
206
"""Page Templates using TAL, TALES, and METAL.
208
This class is suitable for standalone use or class
209
property. Keyword-arguments are passed into the template as-is.
211
Initialize with a template string."""
215
def __get__(self, instance, type):
216
if instance is not None:
217
return self.bind(instance)
221
class PageTemplateFile(BaseTemplateFile, PageTemplate):
222
"""Page Templates using TAL, TALES, and METAL.
224
This class is suitable for standalone use or class
225
property. Keyword-arguments are passed into the template as-is.
227
Initialize with a filename."""
232
class ViewPageTemplate(PageTemplate):
233
"""Template class suitable for use with a Zope browser view; the
234
variables ``view``, ``context`` and ``request`` variables are
235
brought in to the local scope of the template automatically, while
236
keyword arguments are passed in through the ``options``
237
dictionary. Note that the default expression type for this class
238
is 'path' (standard Zope traversal)."""
240
def _pt_get_context(self, view, request, kwargs):
241
context = kwargs.get('context')
243
context = view.context
244
request = request or kwargs.get('request') or view.request
253
def __call__(self, _ob=None, context=None, request=None, **kwargs):
254
kwargs.setdefault('context', context)
255
kwargs.setdefault('request', request)
256
bound_pt = self.bind(_ob)
257
return bound_pt(**kwargs)
260
class ViewPageTemplateFile(ViewPageTemplate, PageTemplateFile):
261
"""If ``filename`` is a relative path, the module path of the
262
class where the instance is used to get an absolute path."""
267
class BoundPageTemplate(object):
268
"""When a page template class is used as a property, it's bound to
269
the class instance on access, which is implemented using this
272
def __init__(self, pt, render):
273
object.__setattr__(self, 'im_self', pt)
274
object.__setattr__(self, 'im_func', render)
276
macros = property(lambda self: self.im_self.macros)
277
filename = property(lambda self: self.im_self.filename)
279
def __call__(self, *args, **kw):
280
kw.setdefault('args', args)
281
return self.im_func(**kw)
283
def __setattr__(self, name, v):
284
raise AttributeError("Can't set attribute", name)
287
return "<%s.Bound%s %r>" % (
288
type(self.im_self).__module__,
289
type(self.im_self).__name__, self.filename)