from interfaces import * |
from interfaces import * |
from xml.sax.saxutils import quoteattr, escape |
from xml.sax.saxutils import quoteattr, escape |
from publish import TraversalPath |
from publish import TraversalPath |
from peak.util import SOX |
from peak.util import SOX, imports |
from places import Decorator |
from places import Decorator |
from environ import traverseItem, traverseDefault |
from environ import traverseItem, traverseDefault |
|
from errors import NotFound |
|
|
__all__ = [ |
__all__ = [ |
'TEMPLATE_NS', 'DOMLETS_PROPERTY', 'TemplateDocument' |
'TEMPLATE_NS', 'DOMLETS_PROPERTY', 'TemplateDocument' |
unicodeJoin = u''.join |
unicodeJoin = u''.join |
|
|
|
|
|
|
def infiniter(sequence): |
def infiniter(sequence): |
while 1: |
while 1: |
for item in sequence: |
for item in sequence: |
return traverseDefault(ctx, self.ob, 'attr', name, name, default) |
return traverseDefault(ctx, self.ob, 'attr', name, name, default) |
|
|
|
|
|
class DOMletMethod(object): |
|
"""Bind an 'IDOMletRenderable' to a specific context""" |
|
|
|
protocols.advise( |
|
instancesProvide = [IDOMletRenderable] |
|
) |
|
|
|
__slots__ = 'template','ctx' |
|
|
|
def __init__(self,ctx,template): |
|
self.ctx = ctx |
|
self.template = template |
|
|
|
def renderFor(self,ctx,state): |
|
return self.template.renderFor(self.ctx,state) |
|
|
|
|
|
|
|
|
|
|
|
|
|
class Parameters: |
|
"""'params' object for templates""" |
|
|
|
protocols.advise( instancesProvide = [IWebTraversable] ) |
|
|
|
def __init__(self,ctx,data): |
|
self.ctx = ctx |
|
self.data = data |
|
self.cache = {} |
|
|
|
def traverseTo(self, name, ctx, default=NOT_GIVEN): |
|
try: |
|
item = self.cache[name] |
|
except KeyError: |
|
try: |
|
item = self.data[name] |
|
except KeyError: |
|
if default is not NOT_GIVEN: |
|
return default |
|
raise NotFound(ctx,name,self) |
|
else: |
|
tmpl = IDOMletRenderable(item,None) |
|
if tmpl is not None: |
|
item = self.cache[name] = DOMletMethod(self.ctx,tmpl) |
|
else: |
|
path = adapt(item,TraversalPath,None) |
|
if path is not None: |
|
self.data[name] = path |
|
return path.traverse(self.ctx) |
|
return ctx.childContext(name,item) |
|
|
|
|
|
def beforeHTTP(self, ctx): |
|
return ctx |
|
|
|
def getURL(self,ctx): |
|
return ctx.traversedURL |
|
|
|
|
|
|
def nodeIs(mode, parser, data, name, value): |
def nodeIs(mode, parser, data, name, value): |
data['attributes'].remove((name,value)) |
data['attributes'].remove((name,value)) |
data[mode+'.is'] = value |
data[mode+'.is'] = value |
parent = data['previous']['pwt.content'] |
|
data.setdefault(mode+'.register',[]).append( |
data.setdefault(mode+'.register',[]).append( |
lambda ob: parent.addParameter(value,ob) |
lambda ob: binding.getParentComponent(ob).addParameter(value,ob) |
) |
) |
|
|
|
|
|
|
def setupElement(parser,data): |
def setupElement(parser,data): |
|
|
d = dict(data.get('attributes',())) |
d = dict(data.get('attributes',())) |
data['pwt.content'] = data['pwt_document'] |
data['pwt.content'] = data['pwt_document'] |
|
|
|
|
|
def withParam(parser,data,name,value): |
|
data['attributes'].remove((name,value)) |
|
data.setdefault('content.register',[]).append( |
|
lambda ob: ob.addParameter(name.split(':',1)[-1],value) |
|
) |
|
|
|
|
|
|
instancesProvide = [IDOMletElement], |
instancesProvide = [IDOMletElement], |
) |
) |
|
|
security.allow(security.Anybody) |
|
|
|
children = binding.Make(list) |
children = binding.Make(list) |
params = binding.Make(dict) |
params = binding.Make(dict) |
|
|
|
|
staticText = binding.Make(staticText, suggestParent=False) |
staticText = binding.Make(staticText, suggestParent=False) |
|
|
|
|
|
|
def optimizedChildren(self): |
def optimizedChildren(self): |
|
|
"""Child nodes with as many separate text nodes combined as possible""" |
"""Child nodes with as many separate text nodes combined as possible""" |
_openTag = _closeTag = _emptyTag = '' |
_openTag = _closeTag = _emptyTag = '' |
|
|
|
|
|
class Uses(Element): |
|
|
|
"""Render child elements with target data, or skip element altogether""" |
|
|
|
staticText = None |
|
render_if = True |
|
|
|
def renderFor(self, data, state): |
|
try: |
|
if self.dataSpec: |
|
data, state = self._traverse(data, state) |
|
except (web.NotFound,web.NotAllowed): |
|
if self.render_if: |
|
return |
|
else: |
|
if not self.render_if: |
|
return |
|
|
|
state.write(self._openTag) |
|
|
|
for child in self.optimizedChildren: |
|
child.renderFor(data,state) |
|
|
|
state.write(self._closeTag) |
|
|
|
|
|
class Unless(Uses): |
|
|
|
"""Skip child elements if target data is available""" |
|
|
|
render_if = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
classProvides = [naming.IObjectFactory], |
classProvides = [naming.IObjectFactory], |
) |
) |
|
|
|
|
acceptParams = '*', # handle any top-level parameters |
acceptParams = '*', # handle any top-level parameters |
|
|
|
|
def renderFor(self, ctx, state): |
def renderFor(self, ctx, state): |
return super(TemplateDocument,self).renderFor(ctx.parentContext(),state) |
if not self.fragment: |
|
raise TypeError("Can't be used as a fragment") |
|
return self.fragment.renderFor(ctx.parentContext(),state) |
|
|
def handle_http(self, ctx): |
def handle_http(self, ctx): |
name = ctx.shift() |
name = ctx.shift() |
if name is not None: |
if name is not None: |
raise web.NotFound(ctx,name,self) # No traversal to subobjects! |
raise web.NotFound(ctx,name,self) # No traversal to subobjects! |
|
if not self.page: |
|
raise web.UnsupportedMethod(ctx) # We're not a page! |
data = [] |
data = [] |
self.renderFor( |
self.page.renderFor( |
ctx, DOMletState(self, write=data.append) |
ctx.parentContext(), DOMletState(self, write=data.append) |
) |
) |
# XXX set content-type header |
h = [] |
return '200 OK', [], [str(unicodeJoin(data))] # XXX encoding |
if self.content_type: |
|
h.append(('Content-type',self.content_type)) |
|
return '200 OK', h, [str(unicodeJoin(data))] # XXX encoding |
|
|
|
|
def getObjectInstance(klass, context, refInfo, name, attrs=None): |
def getObjectInstance(klass, context, refInfo, name, attrs=None): |
getObjectInstance = classmethod(getObjectInstance) |
getObjectInstance = classmethod(getObjectInstance) |
|
|
|
|
|
content_type = binding.Make(lambda self: |
|
str(self.params.get('content-type')) |
|
) |
|
|
|
def layoutDOMlet(self,d,attrName): |
|
|
|
if attrName+'-layout' in self.params: |
|
path = self.params[attrName+'-layout'] + '' # ensure stringness |
|
if path=='/nothing': |
|
return None |
|
elif path=='/default': |
|
return super(TemplateDocument,self) |
|
else: |
|
return Replace(self, dataSpec=path, params=self.params.copy()) |
|
|
|
if attrName in self.params: |
|
return IDOMletRenderable(self.params[attrName]) |
|
|
|
if attrName=='fragment': |
|
# It's okay to be a fragment by default |
|
return super(TemplateDocument,self) |
|
|
|
fragment = page = binding.Make(layoutDOMlet) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def renderFor(self,data,state): |
def renderFor(self,data,state): |
|
|
if self.dataSpec: |
if self.dataSpec: |
data, state = self._traverse(data, state) |
ctx, state = self._traverse(data, state) |
|
|
if self.params: |
if self.params: |
state = state.withData(params=self.params) |
state = state.withData(params=Parameters(data,self.params)) |
|
|
current = data.current |
current = ctx.current |
|
|
domlet = IDOMletNode(current,None) |
domlet = IDOMletRenderable(current,None) |
if domlet is not None: |
if domlet is not None: |
return domlet.renderFor(data,state) |
return domlet.renderFor(ctx,state) |
|
|
# XXX dyn var comp goes here |
# XXX dyn var comp goes here |
# XXX if NOT_FOUND -> return |
# XXX if NOT_FOUND -> return |
_openTag = _closeTag = _emptyTag = '' |
_openTag = _closeTag = _emptyTag = '' |
|
|
|
|
|
class Expects(Element): |
|
|
|
"""Render child elements with target data, or skip element altogether""" |
|
|
|
staticText = None |
|
|
|
dataSpec = '' # to disable conversion to path |
|
|
|
protocol = binding.Make( |
|
lambda self: imports.importString(self.dataSpec),uponAssembly=True |
|
) |
|
|
|
def renderFor(self, data, state): |
|
|
|
data = data.clone(current=adapt(data.current,self.protocol)) |
|
|
|
state.write(self._openTag) |
|
for child in self.optimizedChildren: |
|
child.renderFor(data,state) |
|
state.write(self._closeTag) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|