[Subversion] / PEAK / src / peak / web / templates.py  

Diff of /PEAK/src/peak/web/templates.py

Parent Directory | Revision Log

version 1315, Sat Aug 2 20:41:06 2003 UTC version 2003, Thu Feb 3 16:19:55 2005 UTC
Line 2 
Line 2 
   
 TODO  TODO
   
  - implement interaction wrapper for "/skin", "/request", etc. data paths   - Address traversal nesting for referenced data
   
    - Dynamic attributes, independent of element?
   
    - Phase out old PWT syntax
   
  - implement sub-template support (convert doc->DOMlet in another doc)   - implement sub-template support (convert doc->DOMlet in another doc)
   
Line 20 
Line 24 
 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, imports
   from places import Decorator
   from environ import traverseItem, traverseDefault
   from errors import NotFound
   
 __all__ = [  __all__ = [
     'TEMPLATE_NS', 'DOMLETS_PROPERTY', 'DOMletParser', 'TemplateDocument'      'TEMPLATE_NS', 'DOMLETS_PROPERTY', 'TemplateDocument'
 ]  ]
   
 TEMPLATE_NS = 'http://peak.telecommunity.com/DOMlets/'  TEMPLATE_NS = 'http://peak.telecommunity.com/DOMlets/'
Line 30 
Line 38 
   
 unicodeJoin = u''.join  unicodeJoin = u''.join
   
   
 def infiniter(sequence):  def infiniter(sequence):
     while 1:      while 1:
         for item in sequence:          for item in sequence:
             yield item              yield item
   
 def isNull(ob):  
     return ob is NOT_FOUND or ob is NOT_ALLOWED  
   
   
 class DOMletState(binding.Component):  
   
     """Execution state for a DOMlet"""  
   
     protocols.advise(  
         instancesProvide = [IDOMletState],  
     )  
   
     interaction = binding.requireBinding("Current 'IWebInteraction'")  
   
     write = binding.requireBinding("Unicode output stream write() method")  
   
   
     def findState(self, iface):  
   
         """Find nearest DOMletState implementing 'iface'"""  class DOMletVars(Decorator):
   
         for c in config.iterParents(self):  
             state = adapt(c,iface,None)  
             if state is not None:  
                 return state  
   
       state = None
   
       def traverseTo(self, name, ctx, default=NOT_GIVEN):
           loc = traverseItem(ctx, self.state, 'item', name, name, NOT_FOUND)
           if loc is not NOT_FOUND:
               return loc
   
           # attribute is absent or private, fall through to underlying object
           return traverseDefault(ctx, self.ob, 'attr', name, name, default)
   
   
   class DOMletMethod(object):
       """Bind an 'IDOMletRenderable' to a specific context"""
   
   
   
   
   
   
   
   
   
   
   
   
   
 class DOMletAsWebPage(binding.Component):  
   
     """Render a template component"""  
   
     protocols.advise(      protocols.advise(
         instancesProvide = [IWebPage],          instancesProvide = [IDOMletRenderable]
         asAdapterForProtocols = [IDOMletNode],  
         factoryMethod = 'fromNode'  
     )      )
   
     templateNode = binding.requireBinding("""Node to render""")      __slots__ = 'template','ctx'
   
     def fromNode(klass, subject, protocol):      def __init__(self,ctx,template):
         return klass(templateNode = subject)          self.ctx = ctx
           self.template = template
     fromNode = classmethod(fromNode)  
   
     def render(self, interaction):  
         myOwner = self.getParentComponent()  
         data = []  
         self.templateNode.renderFor(  
             myOwner,  
             DOMletState(  
                 myOwner, interaction=interaction, write=data.append  
             )  
         )  
         return unicodeJoin(data)  
   
       def renderFor(self,ctx,state):
           return self.template.renderFor(self.ctx,state)
   
   
   
Line 115 
Line 80 
   
   
   
   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
   
 class DOMletParser(binding.Component):      def getURL(self,ctx):
           return ctx.traversedURL
     """Parser that assembles a Document"""  
   
     def parser(self,d,a):  
   
         from xml.parsers.expat import ParserCreate  
         p = ParserCreate()  
   
         p.ordered_attributes = True  
         p.returns_unicode = True  
         p.specified_attributes = True  
   
         p.StartDoctypeDeclHandler = self.startDoctype  
         p.StartElementHandler = self.startElement  
         p.EndElementHandler = self.endElement  
         p.CharacterDataHandler = self.characters  
         p.StartNamespaceDeclHandler = self.startNS  
         p.EndNamespaceDeclHandler = self.endNS  
         p.CommentHandler = self.comment  
   
         # We don't use:  
         # .StartNamespaceDeclHandler  
         # .EndNamespaceDeclHandler  
         # .XmlDeclHandler(version, encoding, standalone)  
         # .ElementDeclHandler(name, model)  
         # .AttlistDeclHandler(elname, attname, type, default, required)  
         # .EndDoctypeDeclHandler()  
         # .ProcessingInstructionHandler(target, data)  
         # .UnparsedEntityDeclHandler(entityN,base,systemId,publicId,notationN)  
         # .EntityDeclHandler(  
         #      entityName, is_parameter_entity, value, base,  
         #      systemId, publicId, notationName)  
         # .NotationDeclHandler(notationName, base, systemId, publicId)  
         # .StartCdataSectionHandler()  
         # .EndCdataSectionHandler()  
         # .NotStandaloneHandler()  
         return p  
   
     parser = binding.Once(parser)  class DOMletState(binding.Component):
   
     domlets = binding.New(list) # "nearest explicit DOMlet" stack      """Execution state for a DOMlet"""
     stack   = binding.New(list) # "DOMlet being assembled" stack  
     nsUri   = binding.New(dict) # URI stack for each NS prefix  
   
     myNs = binding.Once(        # prefixes that currently map to TEMPLATE_NS      protocols.advise(
         lambda self,d,a: dict(          instancesProvide = [IDOMletState],
             [(p,1) for (p,u) in self.nsUri.items() if u and u[-1]==TEMPLATE_NS]  
         )  
     )      )
   
       write = binding.Require("Unicode output stream write() method")
   
     def parseFile(self, stream, document=None):      data = binding.Make(dict)
         if document is None:  
             document = TemplateDocument(self.getParentComponent())  
         self.stack.append(document)  
         self.domlets.append(document)  
         self.parser.ParseFile(stream)  
   
   
     def comment(self,data):  
         self.buildLiteral(u'<!--%s-->' % data)  
   
   
     def startNS(self, prefix, uri):  
         self.nsUri.setdefault(prefix,[]).append(uri)  
         if uri==TEMPLATE_NS:  
             self._delBinding('myNs')  
   
   
     def endNS(self, prefix):  
         uri = self.nsUri[prefix].pop()  
         if uri==TEMPLATE_NS:  
             self._delBinding('myNs')  
   
   
   
   
   
   
   
   
     nsStack = binding.New(list)  
   
     def pushNSinfo(self,attrs):  
   
         prefixes = []  
   
         for i in range(0,len(attrs),2):  
   
             k,v = attrs[i], attrs[i+1]  
   
             if not k.startswith('xmlns'):  
                 continue  
   
             rest = k[5:]  
             if not rest:  
                 ns = ''  
             elif rest.startswith(':'):  
                 ns = rest[1:]  
             else:  
                 continue  
   
             self.startNS(ns,v)  
             prefixes.append(ns)  
   
         self.nsStack.append(prefixes)  
   
   
     def popNSinfo(self):  
         map(self.endNS, self.nsStack.pop())  
   
   
   
   
   
   
       def __getitem__(self,key):
           return self.data[key]
   
       def withData(self,**kw):
           data = self.data.copy()
           data.update(kw)
           return self.__class__(self,data=data,write=self.write)
   
       def wrapContext(self,ctx):
           return DOMletVars(ob=ctx, state=self)
   
       def findState(self, iface):
   
           """Find nearest DOMletState implementing 'iface'"""
   
           for c in binding.iterParents(self):     # XXX not covered by tests!
               state = adapt(c,iface,None)
               if state is not None:
                   return state
   
     def startElement(self, name, attrs):  
   
         self.pushNSinfo(attrs)  
   
         a = []  
         append = a.append  
         myNs = self.myNs or ('',)   # use unprefixed NS if no NS defined  
   
         top = self.stack[-1]  
         factory = top.tagFactory  
         domletName = dataSpec = paramName = None  
   
         for i in range(0,len(attrs),2):  
   
             k,v = attrs[i], attrs[i+1]  
   
             if ':' in k:  
                 ns, n = k.split(':',1)  
             else:  
                 ns, n = '', k  
   
             if n=='domlet' and ns in myNs:  
                 # XXX if domletName is not None or dataSpec is not None:  
                 # XXX     raise ???  
                 if ':' in v:  
                     domletName, dataSpec = v.split(':',1)  
                 else:  
                     domletName, dataSpec = v, ''  
   
                 if domletName:  
                     factory = DOMLETS_PROPERTY.of(top)[domletName]  
                     factory = adapt(factory, IDOMletElementFactory)  
   
             elif n=='define' and ns in myNs:  def startElement(parser,data):
                 # XXX if paramName is not None:  
                 # XXX     raise ???  
                 paramName = v  
             else:  
                 append((k,v))  
   
       parent = data['previous']['pwt.content']
       factory = data.get('this.factory', parent.tagFactory)
   
         element = factory(top, tagName=name, attribItems=a,      data['pwt.content'] = outer = factory(parent,
             domletProperty = domletName or None,          tagName=data['name'],
             dataSpec  = dataSpec or '',          attribItems=data['attributes'],
             paramName = paramName or None,          domletProperty = data.get('this.domlet'),
             # XXX nonEmpty=False          dataSpec  = data.get('this.data',''),
           paramName = data.get('this.is'),
       )
   
       inner = data.get('content.factory') or ('content.register' in data and parent.tagFactory)
       if inner:
           data['pwt.this'] = outer
           data['pwt.content'] = inner(outer,
               tagName='',
               attribItems=[],
               domletProperty = data.get('content.domlet'),
               dataSpec=data.get('content.data',''),
               paramName = data.get('content.is'),
         )          )
   
         if paramName:  
             self.domlets[-1].addParameter(paramName,element)  
   
         if domletName:  def finishElement(parser,data):
             # New explicit DOMlet, put it on the explicit DOMlet stack      content = data['pwt.content']
             self.domlets.append(element)      for f in data.get('content.register',()):
           f(content)
       if 'pwt.this' in data:
           this = data['pwt.this']
           this.addChild(content)
         else:          else:
             # Push the previous "nearest enclosing explicit DOMlet"          this = content
             self.domlets.append(self.domlets[-1])      for f in data.get('this.register',()):
           f(this)
         self.stack.append(element)      if 'previous' in data:
           data['previous']['pwt.content'].addChild(this)
       return this
     def endElement(self, name):  
         self.domlets.pop()  
         last = self.stack.pop()  
         self.stack[-1].addChild(last)  
         self.popNSinfo()  
   
   
     def buildLiteral(self,xml):  def negotiateDomlet(parser, data, name, value):
         top = self.stack[-1]      data['attributes'].remove((name,value))
         literal = top.literalFactory(top, xml=xml)      if ':' in value:
         top.addChild(literal)          data['this.domlet'],data['this.data'] = value.split(':',1)
           domlet = data['this.domlet']
   
     def characters(self, data):  
         top = self.stack[-1]  
         text = top.textFactory(top, xml=escape(data))  
         top.addChild(text)  
   
   
   
   
     def startDoctype(self, doctypeName, systemId, publicId, has_internal):  
   
         if publicId:  
             p = ' PUBLIC %s %s' % (quoteattr(publicId),quoteattr(systemId))  
         elif systemId:  
             p = ' SYSTEM %s' % quoteattr(systemId)  
         else:          else:
             p = ''          data['this.domlet'] = domlet = value
   
         # we ignore internal DTD subsets; they're not useful for HTML  
         xml = u'<!DOCTYPE %s%s>\n' % (doctypeName, p)  
   
         self.buildLiteral(xml)  
   
   
   
       factory = DOMLETS_PROPERTY.of(data['previous']['pwt.content'])[domlet]
       if data.setdefault('this.factory',factory) is not factory:
           parser.err('More than one "domlet" or "this:" replacement defined')
   
   
   def negotiateDefine(parser, data, name, value):
       data['attributes'].remove((name,value))
       data['this.is'] = value
       parent = data['previous']['pwt.content']
       data.setdefault('this.register',[]).append(
           lambda ob: parent.addParameter(value,ob)
       )
   
   
   def negotiatorFactory(domletFactory):
       def negotiate(mode, parser, data, name, value):
           data['attributes'].remove((name,value))
           factory = data.setdefault(mode+'.factory',domletFactory)
           if factory is not domletFactory:
               parser.err('More than one "domlet" or "this:" replacement defined')
           data[mode+'.data'] = value
           data[mode+'.domlet'] = parser.splitName(name)[1]
       return negotiate
   
   def nodeIs(mode, parser, data, name, value):
       data['attributes'].remove((name,value))
       data[mode+'.is'] = value
       data.setdefault(mode+'.register',[]).append(
           lambda ob: binding.getParentComponent(ob).addParameter(value,ob)
       )
   
   
   
   def setupElement(parser,data):
   
       d = dict(data.get('attributes',()))
   
       if 'domlet' in d:
           negotiateDomlet(parser,data,'domlet',d['domlet'])
   
       if 'define' in d:
           negotiateDefine(parser,data,'define',d['define'])
   
       def text(xml):
           top = data['pwt.content']
           top.addChild(top.textFactory(top,xml=escape(xml)))
   
       def literal(xml):
           top = data['pwt.content']
           top.addChild(top.literalFactory(top,xml=xml))
   
       data['start'] = startElement
       data['finish'] = finishElement
       data['text'] = text
       data['literal'] = literal
   
   
   def setupDocument(parser,data):
       setupElement(parser,data)
       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)
       )
   
   
   
Line 378 
Line 296 
   
     xml = u''      xml = u''
   
     staticText = binding.bindTo('xml')      staticText = binding.Obtain('xml')
   
     def renderFor(self, data, state):      def renderFor(self, data, state):
         state.write(self.xml)          state.write(self.xml)
Line 415 
Line 333 
         instancesProvide = [IDOMletElement],          instancesProvide = [IDOMletElement],
     )      )
   
     children       = binding.New(list)      children       = binding.Make(list)
     params         = binding.New(dict)      params         = binding.Make(dict)
   
     tagName        = binding.requireBinding("Tag name of element")      tagName        = binding.Require("Tag name of element")
     attribItems    = binding.requireBinding("Attribute name,value pairs")      attribItems    = binding.Require("Attribute name,value pairs")
     nonEmpty       = False      nonEmpty       = False
     domletProperty = None      domletProperty = None
     dataSpec       = binding.Constant('', adaptTo=TraversalPath)      dataSpec       = binding.Make(lambda: '', adaptTo=TraversalPath)
     paramName      = None      paramName      = None
       acceptParams   = ()
       multiParams    = ()
   
     # IDOMletNode      # IDOMletNode
   
     def staticText(self, d, a):      def staticText(self):
   
         """Note: replace w/staticText = None in dynamic element subclasses"""          """Note: replace w/staticText = None in dynamic element subclasses"""
   
Line 443 
Line 363 
         else:          else:
             return self._emptyTag              return self._emptyTag
   
     staticText = binding.Once(staticText, suggestParent=False)      staticText = binding.Make(staticText, suggestParent=False)
   
   
   
       def optimizedChildren(self):
   
     def optimizedChildren(self, d, a):  
   
         """Child nodes with as many separate text nodes combined as possible"""          """Child nodes with as many separate text nodes combined as possible"""
   
Line 474 
Line 392 
         flush()          flush()
         return all          return all
   
     optimizedChildren = binding.Once(optimizedChildren)      optimizedChildren = binding.Make(optimizedChildren)
   
   
     def _traverse(self, data, state):      def _traverse(self, data, state):
           return self.dataSpec.traverse(data,state.wrapContext), state
   
   
   
   
   
         if isNull(data):  
             return data, state  
   
         return self.dataSpec.traverse(  
             data, state.interaction, lambda o,i: self._wrapInteraction(i)  
         ), state  
   
   
   
Line 522 
Line 440 
         self.children.append(node)          self.children.append(node)
   
   
   
   
   
   
   
   
   
   
   
     def addParameter(self, name, element):      def addParameter(self, name, element):
         """Declare 'element' as part of parameter 'name'"""          """Declare 'element' as part of parameter 'name'"""
   
         self.params.setdefault(name,[]).append(element)          if not self.acceptParams:
               return self.getParentComponent().addParameter(name,element)
   
           if name not in self.acceptParams and '*' not in self.acceptParams:
               # XXX need line info
               raise SyntaxError("Unrecognized parameter: %r" % name)
   
           is_multi = (
               name in self.multiParams or
               name not in self.acceptParams and '*' in self.multiParams
           )
   
           if name in self.params:
   
               if not is_multi:
                   raise SyntaxError(
                       "Multiple definitions for parameter: %r" % name
                   )   # XXX need line info
   
     # Override in subclasses              self.params[name].append(element)
   
     def _wrapInteraction(self,interaction):          elif is_multi:
         # XXX This should wrap the interaction in an IWebTraversable simulator,              self.params[name] = [element]
         # XXX which should include access to this element's parameters as well  
         # XXX as interaction variables.  
         raise NotImplementedError  
   
           else:
               self.params[name] = element
   
     _emptyTag = binding.Once(  
         lambda self,d,a: self._openTag[:-1]+u' />'  
   
   
   
   
   
   
   
   
   
       # Override in subclasses
   
       _emptyTag = binding.Make(
           lambda self: self.tagName and self._openTag[:-1]+u' />' or ''
     )      )
   
     _closeTag = binding.Once(      _closeTag = binding.Make(
         lambda self,d,a: u'</%s>' % self.tagName          lambda self: self.tagName and u'</%s>' % self.tagName or ''
     )      )
   
     _openTag = binding.Once(      _openTag = binding.Make(
         lambda self,d,a: u'<%s%s>' % ( self.tagName,          lambda self: self.tagName and u'<%s%s>' % ( self.tagName,
             unicodeJoin([              unicodeJoin([
                 u' %s=%s' % (k,quoteattr(v)) for (k,v) in self.attribItems                  u' %s=%s' % (k,quoteattr(v)) for (k,v) in self.attribItems
             ])              ])
         )          ) or ''
     )      )
   
   
     tagFactory     = None # real value is set below      tagFactory     = None # real value is set below
     textFactory    = Literal      textFactory    = Literal
     literalFactory = Literal      literalFactory = Literal
Line 572 
Line 525 
   
   
   
 class TemplateDocument(Element):  
   
     """Document-level template element"""  
   
   
   
   
   class TaglessElement(Element):
   
       """Element w/out tags"""
   
     _openTag = _closeTag = _emptyTag = ''      _openTag = _closeTag = _emptyTag = ''
   
     parserClass = DOMletParser  
   
     def parseFile(self, stream):  class Uses(Element):
         parser = self.parserClass(self)  
         parser.parseFile(stream,self)  
   
       """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
   
   
   
   class TemplateDocument(TaglessElement):
   
       """Document-level template element"""
   
       protocols.advise(
           instancesProvide = [IHTTPHandler],
           classProvides = [naming.IObjectFactory],
       )
   
       acceptParams = '*',     # handle any top-level parameters
   
       def renderFor(self, ctx, 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):
           name = ctx.shift()
           if name is not None:
               raise web.NotFound(ctx,name,self)   # No traversal to subobjects!
           if not self.page:
               raise web.UnsupportedMethod(ctx)    # We're not a page!
           data = []
           self.page.renderFor(
               ctx.parentContext(), DOMletState(self, write=data.append)
           )
           h = []
           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):
           url, = refInfo.addresses
           return config.processXML(
               web.TEMPLATE_SCHEMA(context),str(url),pwt_document=klass(context),
           )
   
       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)
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   class Replace(Element):
   
       staticText = None
       acceptParams = '*',
       escaped = True
   
       def renderFor(self,data,state):
   
           if self.dataSpec:
               ctx, state = self._traverse(data, state)
   
           if self.params:
               state = state.withData(params=Parameters(data,self.params))
   
           current = ctx.current
   
           domlet = IDOMletRenderable(current,None)
           if domlet is not None:
               return domlet.renderFor(ctx,state)
   
           # XXX dyn var comp goes here
           # XXX if NOT_FOUND -> return
           # XXX if NOT_GIVEN -> render original content
   
           current = unicode(current)
           if self.escaped:
               current = escape(current)
   
           state.write(current)
   
   
   class ReplaceXML(Replace):
       escaped = False
   
   
   
Line 618 
Line 700 
     """Abstract base for elements that replace their contents"""      """Abstract base for elements that replace their contents"""
   
     staticText = None      staticText = None
     children   = optimizedChildren = binding.bindTo('contents')      children   = optimizedChildren = binding.Obtain('contents')
     contents   = binding.requireBinding("nodes to render in element body")      contents   = binding.Require("nodes to render in element body")
   
     def addChild(self, node):      def addChild(self, node):
         pass    # ignore children, only parameters count with us          pass    # ignore children, only parameters count with us
Line 627 
Line 709 
   
 class Text(ContentReplacer):  class Text(ContentReplacer):
   
     """Replace element contents w/data"""      """Replace element contents w/data (XML-quoted)"""
   
     def renderFor(self, data, state):      def renderFor(self, data, state):
   
         if self.dataSpec:          if self.dataSpec:
             data, state = self._traverse(data, state)              data, state = self._traverse(data, state)
   
         write = state.write          write = state.write
           write(self._openTag)
           write(escape(unicode(data.current)))
           write(self._closeTag)
   
   
   class XML(ContentReplacer):
   
       """Replace element contents w/data (XML structure)"""
   
       def renderFor(self, data, state):
           if self.dataSpec:
               data, state = self._traverse(data, state)
   
           write = state.write
         write(self._openTag)          write(self._openTag)
           write(unicode(data.current))
           write(self._closeTag)
   
   
   
   class TaglessText(Text):
   
       """Text w/out open/close tag"""
   
       _openTag = _closeTag = _emptyTag = ''
   
   
   class TaglessXML(XML):
   
       """XML w/out open/close tag"""
   
       _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):
   
         if not isNull(data):          data = data.clone(current=adapt(data.current,self.protocol))
             write(unicode(data.getObject(state.interaction)))  
           state.write(self._openTag)
           for child in self.optimizedChildren:
               child.renderFor(data,state)
           state.write(self._closeTag)
   
   
   
   
   
   
   
   class URLAttribute(Element):
   
       """Put the URL in an attribute"""
   
       staticText = None
   
       def renderFor(self, data, state):
   
           if self.dataSpec:
               data, state = self._traverse(data, state)
   
           url = unicode(data.url)
   
           if not self.optimizedChildren and not self.nonEmpty:
               state.write(self._emptyTag % locals())
               return
   
           state.write(self._openTag % locals())
           for child in self.optimizedChildren:
               child.renderFor(data,state)
           state.write(self._closeTag)
   
   
   class URLText(ContentReplacer):
   
       """Write absolute URL as body text"""
   
       def renderFor(self, data, state):
   
           if self.dataSpec:
               data, state = self._traverse(data, state)
   
           write = state.write
   
           write(self._openTag)
           write(unicode(data.url))
         write(self._closeTag)          write(self._closeTag)
   
   class TaglessURLText(URLText):
       _openTag = _closeTag = _emptyTag = ''
   
   def URLTag(parentComponent, componentName=None, domletProperty=None, **kw):
   
       """Create a URLText or URLAttribute DOMlet based on parameters"""
   
       kw['domletProperty'] = domletProperty
       prop = (domletProperty or '').split('.')
   
       if len(prop)==1 or prop[-1]=='text':
           return URLText(parentComponent, componentName, **kw)
   
       elif prop[-1]=='notag':
           kw['_openTag'] = kw['_closeTag'] = ''
           return URLText(parentComponent, componentName, **kw)
   
       else:
           attrName = prop[-1].replace('+',':')
           attrs = [(k,v.replace('%','%%')) for (k,v) in kw.get('attribItems',())]
           d = dict(attrs)
   
           if attrName not in d:
               attrs.append((attrName,'%(url)s'))
           else:
               attrs = [
                   tuple([k]+((k!=attrName) and [v] or ['%(url)s']))
                       for (k,v) in attrs
               ]
   
           kw['attribItems'] = attrs
           return URLAttribute(parentComponent, componentName, **kw)
   
   protocols.adviseObject(URLTag, provides=[IDOMletElementFactory])
   
   
   
Line 656 
Line 861 
   
 class List(ContentReplacer):  class List(ContentReplacer):
   
       acceptParams = 'listItem','header','emptyList','footer'
       multiParams = 'listItem',
   
     def renderFor(self, data, state):      def renderFor(self, data, state):
   
         if self.dataSpec:          if self.dataSpec:
             data, state = self._traverse(data, state)              data, state = self._traverse(data, state)
   
         state.write(self._openTag)          state.write(self._openTag)
           nextPattern = infiniter(self.params['listItem']).next
         i = infiniter(self.params['listItem'])          allowed     = data.allows
         interaction = state.interaction  
         pathProtocol = interaction.pathProtocol  
         suggest = binding.suggestParentComponent  
         ct = 0          ct = 0
   
         if not isNull(data):          # XXX this should probably use an iteration location, or maybe
           # XXX put some properties in execution context for loop vars?
   
             for item in data.getObject(interaction):          for item in data.current:
                 if not interaction.allows(item):  
                     continue  
   
                 loc = adapt(item, pathProtocol, None)              if not allowed(item):
                 if loc is None:  
                     continue                      continue
   
                 # XXX this should probably use an iteration location, or maybe              if not ct:
                 # XXX put some properties in execution context for loop vars?                  if 'header' in self.params:
                 suggest(data,None,loc)  # XXX use numeric name?                      self.params['header'].renderFor(data,state)
                 i.next().renderFor(loc, state)  
               loc = data.childContext(str(ct), item)
               nextPattern().renderFor(loc, state)
                 ct += 1                  ct += 1
   
         if not ct:          if not ct:
             # Handle list being empty              # Handle list being empty
             for child in self.params.get('emptyList',()):              if 'emptyList' in self.params:
                 child.renderFor(data, state)                  self.params['emptyList'].renderFor(data,state)
           else:
               if 'footer' in self.params:
                   self.params['footer'].renderFor(data,state)
   
         state.write(self._closeTag)          state.write(self._closeTag)
   
   class TaglessList(List):
       _openTag = _closeTag = _emptyTag = ''
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   


Generate output suitable for use with a patch program
Legend:
Removed from v.1315  
changed lines
  Added in v.2003

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help