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

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

Parent Directory | Revision Log

version 1274, Mon Jul 21 00:07:30 2003 UTC version 1275, Mon Jul 21 00:55:16 2003 UTC
Line 1 
Line 1 
   """XML/XHTML Templates for 'peak.web', similar to Twisted's Woven
   
   TODO
   
    - implement interaction wrapper for "/skin", "/request", etc. model paths
   
    - implement sub-template support (convert template->view in another template)
   
    - add hooks for views to validate the list of supplied patterns
   
    - 'list' view needs iteration variables, maybe paging
   
    - need translation views, among lots of other kinds of views
   
    - support DTD fragments, and the rest of the XML standard
   """
   
 from __future__ import generators  from __future__ import generators
 from peak.api import *  from peak.api import *
 from interfaces import *  from interfaces import *
 from xml.sax.saxutils import quoteattr  from xml.sax.saxutils import quoteattr, escape
 from publish import LocationPath  from publish import LocationPath
   
 __all__ = [  __all__ = [
     # really only the parser, bindings, etc. should be public      'TEMPLATE_NS', 'VIEWS_PROPERTY', 'TemplateParser', 'TemplateDocument'
 ]  ]
   
   TEMPLATE_NS = 'http://peak.telecommunity.com/peak.web.templates/'
   VIEWS_PROPERTY = PropertyName('peak.web.views')
   
 unicodeJoin = u''.join  unicodeJoin = u''.join
   
Line 20 
Line 39 
     return ob is NOT_FOUND or ob is NOT_ALLOWED      return ob is NOT_FOUND or ob is NOT_ALLOWED
   
   
   class TemplateAsMethod(binding.Component):
   
       """Render a template component"""
   
       protocols.advise(
           instancesProvide = [IWebMethod],
           asAdapterForProtocols = [ITemplateNode],
           factoryMethod = 'fromNode'
       )
   
       templateNode = binding.requireBinding("""Node to render""")
   
       def fromNode(klass, subject, protocol):
           return klass(templateNode = subject)
   
       fromNode = classmethod(fromNode)
   
       def render(self, interaction):
           myLocation = self.getParentComponent()
           myOwner = myLocation.getParentComponent()
           data = []
           self.templateNode.renderTo(
               interaction, data.append, myOwner, interaction
           )
           return unicodeJoin(data)
   
   
   
Line 36 
Line 80 
   
   
   
   class TemplateParser(binding.Component):
   
       """Parser that assembles a TemplateDocument"""
   
       def parser(self,d,a):
   
 class TemplateAsMethod(binding.Component):          from xml.parsers.expat import ParserCreate
           p = ParserCreate()
   
     """Render a template component"""          p.ordered_attributes = True
           p.returns_unicode = True
           p.specified_attributes = True
   
     protocols.advise(          p.StartDoctypeDeclHandler = self.startDoctype
         instancesProvide = [IWebMethod],          p.StartElementHandler = self.startElement
         asAdapterForProtocols = [ITemplateNode],          p.EndElementHandler = self.endElement
         factoryMethod = 'fromNode'          p.CharacterDataHandler = self.characters
           p.StartNamespaceDeclHandler = self.startNS
           p.EndNamespaceDeclHandler = self.endNS
           p.CommentHandler = self.comment
   
           # We don't use:
           # .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)
   
   
   
       views = binding.New(list)
       stack = binding.New(list)
       nsUri = binding.New(dict)
       myNs  = binding.New(dict)
   
       myNs = binding.Once(
           lambda self,d,a: dict(
               [(p,1) for (p,u) in self.nsUri.items() if u and u[-1]==TEMPLATE_NS]
           )
     )      )
   
     templateNode = binding.requireBinding("""Node to render""")  
   
     def fromNode(klass, subject, protocol):      def parseFile(self, stream, document=None):
         return klass(templateNode = subject)          if document is None:
               document = TemplateDocument(self.getParentComponent())
           self.stack.append(document)
           self.views.append(document)
           self.parser.ParseFile(stream)
   
     fromNode = classmethod(fromNode)  
   
     def render(self, interaction):      def comment(self,data):
         data = []          self.buildLiteral(u'<!--%s-->' % data)
         self.templateNode.renderTo(  
             interaction, data.append, self.getParentComponent(), interaction  
       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')
   
   
   
   
   
   
   
       def startElement(self, name, attrs):
   
           a = []
           append = a.append
           myNs = self.myNs
   
           top = self.stack[-1]
           factory = top.tagFactory
           model = ''
           view = pattern = 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 myNs:
                   if ns not in myNs:
                       append((k,v))
                       continue
               elif ns:
                   append((k,v))
                   continue
   
               if k=='view':
                   view = v
                   factory = VIEWS_PROPERTY.of(top)[v]
                   factory = adapt(factory, ITemplateElementFactory)
                   continue
               elif k=='model':
                   model = v
                   continue
               elif k=='pattern':
                   pattern = v
                   continue
   
               append((k,v))
               continue
   
           tag = factory(top, tagName=name, attribItems=a,
               # XXX nonEmpty=False,
               viewProperty=view, modelPath=model, patternName=pattern
         )          )
         return unicodeJoin(data)  
           if pattern:
               self.views[-1].addPattern(pattern,tag)
   
           if view:
               # New view, put it on the view stack
               self.views.append(tag)
           else:
               # Duplicate the old view
               self.views.append(self.views[-1])
   
           self.stack.append(tag)
   
   
       def endElement(self, name):
           self.views.pop()
           last = self.stack.pop()
           self.stack[-1].addChild(last)
   
   
       def buildLiteral(self,xml):
           top = self.stack[-1]
           literal = top.literalFactory(top, xml=xml)
           top.addChild(literal)
   
   
       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:
               p = ''
   
           # we ignore internal DTD subsets; they're not useful for HTML
           xml = u'<!DOCTYPE %s%s>\n' % (doctypeName, p)
   
           self.buildLiteral(xml)
   
   
   
   
   
   
   
   
   
   
   
   
   
Line 129 
Line 334 
     )      )
   
     children   = binding.New(list)      children   = binding.New(list)
     paterns    = binding.New(list)  
     patternMap = binding.New(dict)      patternMap = binding.New(dict)
   
     tagName      = binding.requireBinding("Tag name of element")      tagName      = binding.requireBinding("Tag name of element")
     attribItems  = binding.requireBinding("Attribute name,value pairs")      attribItems  = binding.requireBinding("Attribute name,value pairs")
     nonEmpty     = False      nonEmpty     = False
     viewProperty = None      viewProperty = None
     modelPath    = binding.Constant(None, adaptTo=LocationPath)      modelPath    = binding.Constant('', adaptTo=LocationPath)
     patternName  = None      patternName  = None
   
     # ITemplateNode      # ITemplateNode
Line 147 
Line 351 
   
         texts = [child.staticText for child in self.optimizedChildren]          texts = [child.staticText for child in self.optimizedChildren]
   
         if None in texts or self.isDynamic:          if None in texts:
             return None              return None
   
         if texts or self.nonEmpty:          if texts or self.nonEmpty:
Line 162 
Line 366 
   
   
   
   
     def optimizedChildren(self, d, a):      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 240 
Line 445 
     def addPattern(self, name, element):      def addPattern(self, name, element):
         """Declare 'element' as part of pattern 'name'"""          """Declare 'element' as part of pattern 'name'"""
   
         self.patterns.append( (name,element) )          # self.patterns.append( (name,element) )
         self.patternMap.setdefault(name,[]).append(element)          self.patternMap.setdefault(name,[]).append(element)
   
   
Line 278 
Line 483 
         )          )
     )      )
   
     tagFactory     = classAttr(binding.bindTo('TemplateElement'))      tagFactory     = None # real value is set below
     textFactory    = TemplateLiteral      textFactory    = TemplateLiteral
     literalFactory = TemplateLiteral      literalFactory = TemplateLiteral
   
   TemplateElement.tagFactory = TemplateElement
   
   
   class TemplateDocument(TemplateElement):
   
       """Document-level template element"""
   
       _openTag = _closeTag = _emptyTag = ''
   
       parserClass = TemplateParser
   
       def parseFile(self, stream):
           parser = self.parserClass(self)
           parser.parseFile(stream,self)
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   


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

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help