Commit 6df1df2d authored by Andreas Jung's avatar Andreas Jung

replaced ZopePageTemplate implementation with Z3 ZPT

(PageTemplateFile needs more migration work)
parent e3889401
...@@ -10,41 +10,56 @@ ...@@ -10,41 +10,56 @@
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE
# #
############################################################################## ##############################################################################
"""Zope Page Template module
Zope object encapsulating a Page Template. """ Zope Page Template module (wrapper for the Zope 3 ZPT implementation) """
"""
__version__='$Revision: 1.48 $'[11:-2] __version__='$Revision: 1.48 $'[11:-2]
import os, AccessControl, Acquisition, sys, types import re
from types import StringType import os
from Globals import DTMLFile, ImageFile, MessageDialog, package_home import Acquisition
from Globals import ImageFile, package_home, InitializeClass
from OFS.SimpleItem import SimpleItem from OFS.SimpleItem import SimpleItem
from OFS.content_types import guess_content_type
from DateTime.DateTime import DateTime from DateTime.DateTime import DateTime
from Shared.DC.Scripts.Script import Script, BindingsUI from Shared.DC.Scripts.Script import Script
from Shared.DC.Scripts.Signature import FuncCode from Shared.DC.Scripts.Signature import FuncCode
from AccessControl import getSecurityManager
try:
from AccessControl import Unauthorized
except ImportError:
Unauthorized = "Unauthorized"
from OFS.History import Historical, html_diff from OFS.History import Historical, html_diff
from OFS.Cache import Cacheable from OFS.Cache import Cacheable
from OFS.Traversable import Traversable from OFS.Traversable import Traversable
from OFS.PropertyManager import PropertyManager from OFS.PropertyManager import PropertyManager
from PageTemplate import PageTemplate
from Expressions import SecureModuleImporter from AccessControl import getSecurityManager, safe_builtins, ClassSecurityInfo
from PageTemplateFile import PageTemplateFile from AccessControl.Permissions import view, ftp_access, change_page_templates, view_management_screens
from webdav.Lockable import ResourceLockedError from webdav.Lockable import ResourceLockedError
from webdav.WriteLockInterface import WriteLockInterface from webdav.WriteLockInterface import WriteLockInterface
from zope.pagetemplate.pagetemplate import PageTemplate
from zope.pagetemplate.pagetemplatefile import sniff_type
# regular expression to extract the encoding from the XML preamble
encoding_reg= re.compile('<\?xml.*?encoding="(.*?)".*?\?>', re.M)
preferred_encodings = ['utf-8', 'iso-8859-15']
if os.environ.has_key('ZPT_PREFERRED_ENCODING'):
preferred_encodings.insert(0, os.environ['ZPT_PREFERRED_ENCODING'])
class SecureModuleImporter:
__allow_access_to_unprotected_subobjects__ = 1
def __getitem__(self, module):
mod = safe_builtins['__import__'](module)
path = module.split('.')
for name in path[1:]:
mod = getattr(mod, name)
return mod
class Src(Acquisition.Explicit): class Src(Acquisition.Explicit):
" " """ I am scary code """
PUT = document_src = Acquisition.Acquired
index_html = None index_html = None
PUT = document_src = Acquisition.Acquired
def __before_publishing_traverse__(self, ob, request): def __before_publishing_traverse__(self, ob, request):
if getattr(request, '_hacked_path', 0): if getattr(request, '_hacked_path', 0):
...@@ -55,9 +70,31 @@ class Src(Acquisition.Explicit): ...@@ -55,9 +70,31 @@ class Src(Acquisition.Explicit):
return self.document_src(REQUEST) return self.document_src(REQUEST)
def sniffEncoding(text, default_encoding='utf-8'):
""" try to determine the encoding from html or xml """
if text.startswith('<?xml'):
mo = encoding_reg.search(text)
if mo:
return mo.group(1)
return default_encoding
def guess_type(filename, text):
content_type, dummy = guess_content_type(filename, text)
if content_type in ('text/html', 'text/xml'):
return content_type
return sniff_type(text) or 'text/html'
_default_content_fn = os.path.join(package_home(globals()), 'pt', 'default.html')
class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
Traversable, PropertyManager): Traversable, PropertyManager):
"Zope wrapper for Page Template using TAL, TALES, and METAL" """ Z2 wrapper class for Zope 3 page templates """
__implements__ = (WriteLockInterface,) __implements__ = (WriteLockInterface,)
...@@ -67,8 +104,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -67,8 +104,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
func_code = FuncCode((), 0) func_code = FuncCode((), 0)
_default_bindings = {'name_subpath': 'traverse_subpath'} _default_bindings = {'name_subpath': 'traverse_subpath'}
_default_content_fn = os.path.join(package_home(globals()), _default_content_fn = os.path.join(package_home(globals()), 'www', 'default.html')
'www', 'default.html')
manage_options = ( manage_options = (
{'label':'Edit', 'action':'pt_editForm', {'label':'Edit', 'action':'pt_editForm',
...@@ -79,52 +115,44 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -79,52 +115,44 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
+ SimpleItem.manage_options \ + SimpleItem.manage_options \
+ Cacheable.manage_options + Cacheable.manage_options
_properties=({'id':'title', 'type': 'string', 'mode': 'wd'},
_properties=({'id':'title', 'type': 'ustring', 'mode': 'w'},
{'id':'content_type', 'type':'string', 'mode': 'w'}, {'id':'content_type', 'type':'string', 'mode': 'w'},
{'id':'expand', 'type':'boolean', 'mode': 'w'}, {'id':'expand', 'type':'boolean', 'mode': 'w'},
) )
def __init__(self, id, text=None, content_type=None): security = ClassSecurityInfo()
self.id = str(id) security.declareObjectProtected(view)
self.ZBindings_edit(self._default_bindings) security.declareProtected(view, '__call__')
if text is None:
text = open(self._default_content_fn).read()
self.pt_edit(text, content_type)
def _setPropValue(self, id, value): def __init__(self, id, text=None, content_type=None, encoding='utf-8', strict=False):
PropertyManager._setPropValue(self, id, value) self.id = id
self.ZCacheable_invalidate() self.expand = 0
self.strict = strict
self.ZBindings_edit(self._default_bindings)
self.pt_edit(text, content_type, encoding)
security = AccessControl.ClassSecurityInfo() security.declareProtected(change_page_templates, 'pt_edit')
def pt_edit(self, text, content_type, encoding='utf-8'):
security.declareObjectProtected('View') text = text.strip()
security.declareProtected('View', '__call__') if self.strict and not isinstance(text, unicode):
text = unicode(text, encoding)
security.declareProtected('View management screens', self.ZCacheable_invalidate()
'pt_editForm', 'manage_main', 'read', PageTemplate.pt_edit(self, text, content_type)
'ZScriptHTML_tryForm', 'PrincipiaSearchSource',
'document_src', 'source_dot_xml')
security.declareProtected('FTP access', security.declareProtected(change_page_templates, 'pt_editAction')
'manage_FTPstat','manage_FTPget','manage_FTPlist') def pt_editAction(self, REQUEST, title, text, content_type, encoding, expand):
"""Change the title and document."""
pt_editForm = PageTemplateFile('www/ptEdit', globals(), if self.wl_isLocked():
__name__='pt_editForm') raise ResourceLockedError("File is locked via WebDAV")
pt_editForm._owner = None
manage = manage_main = pt_editForm
source_dot_xml = Src() self.expand = expand
self.pt_setTitle(title, encoding)
security.declareProtected('Change Page Templates', self.pt_edit(text, content_type, encoding)
'pt_editAction', 'pt_setTitle', 'pt_edit',
'pt_upload', 'pt_changePrefs')
def pt_editAction(self, REQUEST, title, text, content_type, expand):
"""Change the title and document."""
if self.wl_isLocked():
raise ResourceLockedError, "File is locked via WebDAV"
self.expand=expand
self.pt_setTitle(title)
self.pt_edit(text, content_type)
REQUEST.set('text', self.read()) # May not equal 'text'! REQUEST.set('text', self.read()) # May not equal 'text'!
REQUEST.set('title', self.title) REQUEST.set('title', self.title)
message = "Saved changes." message = "Saved changes."
...@@ -133,36 +161,45 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -133,36 +161,45 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
% '<br>'.join(self._v_warnings)) % '<br>'.join(self._v_warnings))
return self.pt_editForm(manage_tabs_message=message) return self.pt_editForm(manage_tabs_message=message)
def pt_setTitle(self, title):
charset = getattr(self, 'management_page_charset', None) security.declareProtected(change_page_templates, 'pt_setTitle')
if type(title) == types.StringType and charset: def pt_setTitle(self, title, encoding='utf-8'):
try: if self.strict and not isinstance(title, unicode):
title.decode('us-ascii') title = unicode(title, encoding)
title = str(title)
except UnicodeError:
title = unicode(title, charset)
elif type(title) != types.UnicodeType:
title = str(title)
self._setPropValue('title', title) self._setPropValue('title', title)
def pt_upload(self, REQUEST, file='', charset=None):
def _setPropValue(self, id, value):
""" set a property and invalidate the cache """
PropertyManager._setPropValue(self, id, value)
self.ZCacheable_invalidate()
security.declareProtected(change_page_templates, 'pt_upload')
def pt_upload(self, REQUEST, file='', encoding='utf-8'):
"""Replace the document with the text in file.""" """Replace the document with the text in file."""
if self.wl_isLocked(): if self.wl_isLocked():
raise ResourceLockedError, "File is locked via WebDAV" raise ResourceLockedError("File is locked via WebDAV")
if type(file) is not StringType: if isinstance(file, str):
if not file: raise ValueError, 'File not specified' filename = None
file = file.read() text = file
if charset: else:
try: if not file:
unicode(file, 'us-ascii') raise ValueError('File not specified')
file = str(file) filename = file.filename
except UnicodeDecodeError: text = file.read()
file = unicode(file, charset)
self.write(file) content_type = guess_type(filename, text)
message = 'Saved changes.' if not content_type in ('text/html', 'text/xml'):
return self.pt_editForm(manage_tabs_message=message) raise ValueError('Unsupported mimetype: %s' % content_type)
encoding = sniffEncoding(text, encoding)
self.pt_edit(text, content_type, encoding)
return self.pt_editForm(manage_tabs_message='Saved changes')
security.declareProtected(change_page_templates, 'pt_changePrefs')
def pt_changePrefs(self, REQUEST, height=None, width=None, def pt_changePrefs(self, REQUEST, height=None, width=None,
dtpref_cols="100%", dtpref_rows="20"): dtpref_cols="100%", dtpref_rows="20"):
"""Change editing preferences.""" """Change editing preferences."""
...@@ -183,20 +220,20 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -183,20 +220,20 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
setCookie("dtpref_rows", rows, path='/', expires=e) setCookie("dtpref_rows", rows, path='/', expires=e)
setCookie("dtpref_cols", cols, path='/', expires=e) setCookie("dtpref_cols", cols, path='/', expires=e)
REQUEST.other.update({"dtpref_cols":cols, "dtpref_rows":rows}) REQUEST.other.update({"dtpref_cols":cols, "dtpref_rows":rows})
return self.manage_main() return self.pt_editForm()
def ZScriptHTML_tryParams(self): def ZScriptHTML_tryParams(self):
"""Parameters to test the script with.""" """Parameters to test the script with."""
return [] return []
def manage_historyCompare(self, rev1, rev2, REQUEST, # def manage_historyCompare(self, rev1, rev2, REQUEST,
historyComparisonResults=''): # historyComparisonResults=''):
return ZopePageTemplate.inheritedAttribute( # return ZopePageTemplate.inheritedAttribute(
'manage_historyCompare')( # 'manage_historyCompare')(
self, rev1, rev2, REQUEST, # self, rev1, rev2, REQUEST,
historyComparisonResults=html_diff(rev1._text, rev2._text) ) # historyComparisonResults=html_diff(rev1._text, rev2._text) )
def pt_getContext(self): def pt_getContext(self, *args, **kw):
root = self.getPhysicalRoot() root = self.getPhysicalRoot()
context = self._getContext() context = self._getContext()
c = {'template': self, c = {'template': self,
...@@ -207,13 +244,12 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -207,13 +244,12 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
'options': {}, 'options': {},
'root': root, 'root': root,
'request': getattr(root, 'REQUEST', None), 'request': getattr(root, 'REQUEST', None),
'modules': SecureModuleImporter, 'modules': SecureModuleImporter(),
} }
return c return c
def write(self, text): security.declareProtected(view_management_screens, 'read',
self.ZCacheable_invalidate() 'ZScriptHTML_tryForm')
ZopePageTemplate.inheritedAttribute('write')(self, text)
def _exec(self, bound_names, args, kw): def _exec(self, bound_names, args, kw):
"""Call a Page Template""" """Call a Page Template"""
...@@ -228,7 +264,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -228,7 +264,7 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
except AttributeError: except AttributeError:
pass pass
security=getSecurityManager() security = getSecurityManager()
bound_names['user'] = security.getUser() bound_names['user'] = security.getUser()
# Retrieve the value from the cache. # Retrieve the value from the cache.
...@@ -244,8 +280,13 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -244,8 +280,13 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
# Execute the template in a new security context. # Execute the template in a new security context.
security.addContext(self) security.addContext(self)
try: try:
result = self.pt_render(extra_context=bound_names) # XXX: check the parameters for pt_render()! (aj)
result = self.pt_render(self.pt_getContext())
# result = self.pt_render(extra_context=bound_names)
if keyset is not None: if keyset is not None:
# Store the result in the cache. # Store the result in the cache.
self.ZCacheable_set(result, keywords=keyset) self.ZCacheable_set(result, keywords=keyset)
...@@ -253,37 +294,50 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -253,37 +294,50 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
finally: finally:
security.removeContext(self) security.removeContext(self)
security.declareProtected('Change Page Templates', security.declareProtected(change_page_templates,
'PUT', 'manage_FTPput', 'write',
'manage_historyCopy', 'manage_historyCopy',
'manage_beforeHistoryCopy', 'manage_afterHistoryCopy') 'manage_beforeHistoryCopy', 'manage_afterHistoryCopy')
security.declareProtected(change_page_templates, 'PUT')
def PUT(self, REQUEST, RESPONSE): def PUT(self, REQUEST, RESPONSE):
""" Handle HTTP PUT requests """ """ Handle HTTP PUT requests """
self.dav__init(REQUEST, RESPONSE) self.dav__init(REQUEST, RESPONSE)
self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)
self.write(REQUEST.get('BODY', '')) ## XXX:this should be unicode or we must pass an encoding
self.pt_edit(REQUEST.get('BODY', ''))
RESPONSE.setStatus(204) RESPONSE.setStatus(204)
return RESPONSE return RESPONSE
security.declareProtected(change_page_templates, 'manage_FTPput')
manage_FTPput = PUT manage_FTPput = PUT
security.declareProtected(ftp_access, 'manage_FTPstat','manage_FTPlist')
security.declareProtected(ftp_access, 'manage_FTPget')
def manage_FTPget(self): def manage_FTPget(self):
"Get source for FTP download" "Get source for FTP download"
self.REQUEST.RESPONSE.setHeader('Content-Type', self.content_type) self.REQUEST.RESPONSE.setHeader('Content-Type', self.content_type)
return self.read() return self.read()
security.declareProtected(view_management_screens, 'html')
def html(self):
return self.content_type == 'text/html'
security.declareProtected(view_management_screens, 'get_size')
def get_size(self): def get_size(self):
return len(self.read()) return len(self.read())
security.declareProtected(view_management_screens, 'getSize')
getSize = get_size getSize = get_size
security.declareProtected(view_management_screens, 'PrincipiaSearchSource')
def PrincipiaSearchSource(self): def PrincipiaSearchSource(self):
"Support for searching - the document's contents are searched." "Support for searching - the document's contents are searched."
return self.read() return self.read()
security.declareProtected(view_management_screens, 'document_src')
def document_src(self, REQUEST=None, RESPONSE=None): def document_src(self, REQUEST=None, RESPONSE=None):
"""Return expanded document source.""" """Return expanded document source."""
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.setHeader('Content-Type', 'text/plain') RESPONSE.setHeader('Content-Type', 'text/plain')
if REQUEST is not None and REQUEST.get('raw'): if REQUEST is not None and REQUEST.get('raw'):
...@@ -302,10 +356,8 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -302,10 +356,8 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
'title': 'This template has an error'},) 'title': 'This template has an error'},)
return icons return icons
def __setstate__(self, state):
# This is here for backward compatibility. :-(
ZopePageTemplate.inheritedAttribute('__setstate__')(self, state)
security.declareProtected(view, 'pt_source_file')
def pt_source_file(self): def pt_source_file(self):
"""Returns a file name to be compiled into the TAL code.""" """Returns a file name to be compiled into the TAL code."""
try: try:
...@@ -315,53 +367,126 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable, ...@@ -315,53 +367,126 @@ class ZopePageTemplate(Script, PageTemplate, Historical, Cacheable,
# acquisition context, so we don't know where it is. :-( # acquisition context, so we don't know where it is. :-(
return None return None
def wl_isLocked(self):
return 0
security.declareProtected(view, 'strictUnicode')
def strictUnicode(self):
""" Return True if the ZPT enforces the use of unicode,
False otherwise.
"""
return self.strict
def manage_convertUnicode(self, preferred_encodings=preferred_encodings, RESPONSE=None):
""" convert non-unicode templates to unicode """
if not isinstance(self._text, unicode):
for encoding in preferred_encodings:
try:
self._text = unicode(self._text, encoding)
if RESPONSE:
return RESPONSE.redirect(self.absolute_url() + '/pt_editForm?manage_tabs_message=ZPT+successfully+converted')
else:
return
except UnicodeDecodeError:
pass
raise RuntimeError('Pagetemplate could not be converted to unicode')
else:
if RESPONSE:
return RESPONSE.redirect(self.absolute_url() + '/pt_editForm?manage_tabs_message=ZPT+already+converted')
else:
return
security.declareProtected(view_management_screens, 'getSource')
getSource = Src()
source_dot_xml = Src()
InitializeClass(ZopePageTemplate)
setattr(ZopePageTemplate, 'source.xml', ZopePageTemplate.source_dot_xml) setattr(ZopePageTemplate, 'source.xml', ZopePageTemplate.source_dot_xml)
setattr(ZopePageTemplate, 'source.html', ZopePageTemplate.source_dot_xml) setattr(ZopePageTemplate, 'source.html', ZopePageTemplate.source_dot_xml)
# Product registration and Add support
manage_addPageTemplateForm = PageTemplateFile(
'www/ptAdd', globals(), __name__='manage_addPageTemplateForm')
from urllib import quote def _newZPT(id, filename):
""" factory to generate ZPT instances from the file-system
based templates (basically for internal purposes)
"""
zpt = ZopePageTemplate(id, open(filename).read(), 'text/html')
zpt.__name__= id
return zpt
def manage_addPageTemplate(self, id, title=None, text=None, class FSZPT(ZopePageTemplate):
REQUEST=None, submit=None): """ factory to generate ZPT instances from the file-system
"Add a Page Template with optional file content." based templates (basically for internal purposes)
"""
id = str(id) def __init__(self, id, filename):
if REQUEST is None: ZopePageTemplate.__init__(self, id, open(filename).read(), 'text/html')
self._setObject(id, ZopePageTemplate(id, text)) self.__name__= id
ob = getattr(self, id)
if title:
ob.pt_setTitle(title)
return ob
else:
file = REQUEST.form.get('file')
headers = getattr(file, 'headers', None)
if headers is None or not file.filename:
zpt = ZopePageTemplate(id, text) # collector 596
else:
zpt = ZopePageTemplate(id, file, headers.get('content_type'))
self._setObject(id, zpt) InitializeClass(FSZPT)
# collector 596
if title:
ob = getattr(self, id)
ob.pt_setTitle(title)
try: ZopePageTemplate.pt_editForm = FSZPT('pt_editForm', os.path.join(package_home(globals()),'pt', 'ptEdit.pt'))
u = self.DestinationURL() # this is scary, do we need this?
except AttributeError: ZopePageTemplate.manage = ZopePageTemplate.pt_editForm
u = REQUEST['URL1']
manage_addPageTemplateForm= FSZPT('manage_addPageTemplateForm', os.path.join(package_home(globals()), 'pt', 'ptAdd.pt'))
def manage_addPageTemplate(self, id, title='', text='', encoding='utf-8', submit=None, REQUEST=None, RESPONSE=None):
"Add a Page Template with optional file content."
filename = ''
content_type = 'text/html'
if REQUEST and REQUEST.has_key('file'):
file = REQUEST['file']
filename = file.filename
text = file.read()
headers = getattr(file, 'headers', None)
if headers and headers.has_key('content_type'):
content_type = headers['content_type']
else:
content_type = guess_type(filename, text)
encoding = sniffEncoding(text, encoding)
else:
if hasattr(text, 'read'):
filename = getattr(text, 'filename', '')
headers = getattr(text, 'headers', None)
text = text.read()
if headers and headers.has_key('content_type'):
content_type = headers['content_type']
else:
content_type = guess_type(filename, text)
encoding = sniffEncoding(text, encoding)
if not text:
text = open(_default_content_fn).read()
encoding = 'utf-8'
content_type = 'text/html'
zpt = ZopePageTemplate(id, text, content_type, encoding)
zpt.pt_setTitle(title, encoding)
self._setObject(id, zpt)
zpt = getattr(self, id)
if RESPONSE:
if submit == " Add and Edit ": if submit == " Add and Edit ":
u = "%s/%s" % (u, quote(id)) RESPONSE.redirect(zpt.absolute_url() + '/pt_editForm')
REQUEST.RESPONSE.redirect(u+'/manage_main') else:
return '' RESPONSE.redirect(self.absolute_url() + '/manage_main')
else:
return zpt
from Products.PageTemplates import misc_ from Products.PageTemplates import misc_
misc_['exclamation.gif'] = ImageFile('www/exclamation.gif', globals()) misc_['exclamation.gif'] = ImageFile('pt/exclamation.gif', globals())
def initialize(context): def initialize(context):
context.registerClass( context.registerClass(
...@@ -369,7 +494,7 @@ def initialize(context): ...@@ -369,7 +494,7 @@ def initialize(context):
permission='Add Page Templates', permission='Add Page Templates',
constructors=(manage_addPageTemplateForm, constructors=(manage_addPageTemplateForm,
manage_addPageTemplate), manage_addPageTemplate),
icon='www/zpt.gif', icon='pt/zpt.gif',
) )
context.registerHelp() context.registerHelp()
context.registerHelpTitle('Zope Help') context.registerHelpTitle('Zope Help')
......
<html>
<head>
<title tal:content="template/title">The title</title>
</head>
<body>
<h2><span tal:replace="here/title_or_id">content title or id</span>
<span tal:condition="template/title"
tal:replace="template/title">optional template title</span></h2>
This is Page Template <em tal:content="template/id">template id</em>.
</body>
</html>
<h1 tal:replace="structure here/manage_page_header">Header</h1>
<h2 tal:define="form_title string:Add Page Template"
tal:replace="structure here/manage_form_title">Form Title</h2>
<p class="form-help">
Page Templates allow you to use simple HTML or XML attributes to
create dynamic templates. You may choose to upload the template text
from a local file by typing the file name or using the <em>browse</em>
button.
</p>
<form action="manage_addPageTemplate" method="post"
enctype="multipart/form-data">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
File
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="25" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Encoding
</div>
</td>
<td align="left" valign="top">
<input type="text" name="encoding" size="25" value="utf-8" />
<em>(only used for non-XML and non-HTML content)</em>
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
<input class="form-element" type="submit" name="submit"
value=" Add and Edit " />
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure here/manage_page_footer">Footer</h1>
<h1 tal:replace="structure python: context.manage_page_header(management_page_charset='utf-8')">Header</h1>
<h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
tal:replace="structure context/manage_tabs">Tabs</h2>
<tal:block define="global body request/other/text | request/form/text
| context/read" />
<form action="" method="post" tal:attributes="action request/URL1">
<input type="hidden" name=":default_method" value="pt_changePrefs">
<input type="hidden" name="encoding" value="utf-8"/>
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="middle">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="middle">
<input type="text" name="title" size="40"
tal:attributes="value request/title | context/title" />
</td>
<td align="left" valign="middle">
<div class="form-label"> Last Modified </div>
</td>
<td align="left" valign="middle">
<div class="form-text"
tal:content="python:context.bobobase_modification_time().strftime('%Y-%m-%d %I:%M %p')">1/1/2000
</div>
</td>
</tr>
<tr>
<td align="left" valign="middle">
<div class="form-label">
Content-Type
</div>
</td>
<td align="left" valign="middle">
<select name="content_type" size="1" tal:define="ct context/content_type">
<option value="text/html" tal:attributes="SELECTED python: ct == 'text/html'">text/html</option>
<option value="text/xml" tal:attributes="SELECTED python: ct == 'text/xml'">text/xml</option>
</select>
</td>
<td align="left" valign="top" colspan=2>
<a href="source.html" tal:condition="context/html">Browse HTML source</a>
<a href="source.xml" tal:condition="not:context/html">Browse XML source</a>
<br>
<input type="hidden" name="expand:int:default" value="0">
<input type="checkbox" value="1" name="expand:int"
tal:attributes="checked request/expand | context/expand">
Expand macros when editing
</td>
</tr>
<!-- XXX: check if 'None' is a proper argument for 'namespace' -->
<tr tal:define="errors python: context.pt_errors(None)" tal:condition="errors">
<tal:block define="global body python:context.document_src({'raw':1})"/>
<td align="left" valign="middle" class="form-label">Errors</td>
<td align="left" valign="middle" style="background-color: #FFDDDD"
colspan="3">
<pre tal:content="python: '\n'.join(errors)">errors</pre>
</td>
</tr>
<tr tal:define="warnings context/pt_warnings" tal:condition="warnings">
<td align="left" valign="middle" class="form-label">Warnings</td>
<td align="left" valign="middle" style="background-color: #FFEEDD"
colspan="3">
<pre tal:content="python: '\n'.join(warnings)">errors</pre>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4"
tal:define="width request/dtpref_cols | string:100%;
relative_width python:str(width).endswith('%')">
<textarea name="text:text" wrap="off" style="width: 100%;" rows="20"
tal:condition="relative_width"
tal:attributes="style string:width: $width;;;
rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
<textarea name="text:text" wrap="off" rows="20" cols="50"
tal:condition="not:relative_width"
tal:attributes="cols width; rows request/dtpref_rows | default"
tal:content="body">Template Body</textarea>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="4">
<div class="form-element">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit"
name="pt_editAction:method" value="Save Changes">
&nbsp;&nbsp;
<input class="form-element" type="submit" name="height" value="Taller">
<input class="form-element" type="submit" name="height" value="Shorter">
<input class="form-element" type="submit" name="width" value="Wider">
<input class="form-element" type="submit" name="width" value="Narrower">
</div>
</td>
</tr>
</table>
</form>
<p class="form-help">
You can upload the text for <span tal:replace="context/title_and_id" />
using the following form.
Choose an existing HTML or XML file from your local computer by clicking
<em>browse</em>. You can also <a href="document_src">click context</a>
to view or download the current text.
</p>
<form action="pt_upload" method="post"
enctype="multipart/form-data">
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
File &nbsp;
</div>
</td>
<td align="left" valign="top">
<input type="file" name="file" size="40" value="">
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Encoding &nbsp;
</div>
</td>
<td align="left" valign="top" colspan="2">
<input name="encoding" value="utf-8"/>
</td>
<td align="left" valign="top" colspan="1">
<em>(only used for non-XML and non-XHTML content)</em>
</td>
</tr>
<tr>
<td></td>
<td align="left" valign="top">
<div class="form-element">
<em tal:condition="context/wl_isLocked">Locked by WebDAV</em>
<input tal:condition="not:context/wl_isLocked"
class="form-element" type="submit" value="Upload File">
</div>
</td>
</tr>
</table>
</form>
<h1 tal:replace="structure context/manage_page_footer">Footer</h1>
...@@ -12,6 +12,7 @@ import Zope2 ...@@ -12,6 +12,7 @@ import Zope2
import transaction import transaction
from Testing.makerequest import makerequest from Testing.makerequest import makerequest
from Products.PageTemplates.ZopePageTemplate import _default_content_fn
class ZPTRegressions(unittest.TestCase): class ZPTRegressions(unittest.TestCase):
...@@ -34,9 +35,9 @@ class ZPTRegressions(unittest.TestCase): ...@@ -34,9 +35,9 @@ class ZPTRegressions(unittest.TestCase):
def testAddWithoutParams(self): def testAddWithoutParams(self):
pt = self._addPT('pt1') pt = self._addPT('pt1')
default_text = open(pt._default_content_fn).read() default_text = open(_default_content_fn).read()
self.assertEqual(pt.title, '') self.assertEqual(pt.title, '')
self.assertEqual(pt.document_src(), default_text) self.assertEqual(pt.document_src().strip(), default_text.strip())
def testAddWithRequest(self): def testAddWithRequest(self):
"""Test manage_add with file""" """Test manage_add with file"""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment