Commit f3ab4409 authored by Hanno Schlichting's avatar Hanno Schlichting

Removed the old help system, in favor of the current Sphinx documentation...

Removed the old help system, in favor of the current Sphinx documentation hosted at http://docs.zope.org/zope2/. For backwards compatibility the `registerHelp` and `registerHelpTitle` methods are still available on the ProductContext used during the `initialize` function.
parent c56dd40c
...@@ -33,6 +33,11 @@ Features Added ...@@ -33,6 +33,11 @@ Features Added
Restructuring Restructuring
+++++++++++++ +++++++++++++
- Removed the old help system, in favor of the current Sphinx documentation
hosted at http://docs.zope.org/zope2/. For backwards compatibility the
`registerHelp` and `registerHelpTitle` methods are still available on the
ProductContext used during the `initialize` function.
- Removed various persistent product related code and options. The - Removed various persistent product related code and options. The
`enable-product-installation` `zope.conf` setting is now a no-op. `enable-product-installation` `zope.conf` setting is now a no-op.
......
...@@ -67,12 +67,6 @@ class Product(Base): ...@@ -67,12 +67,6 @@ class Product(Base):
"Return the destination for factory output" "Return the destination for factory output"
return self return self
def getProductHelp(self):
"""Returns the ProductHelp object associated with the Product.
"""
from HelpSys.HelpSys import ProductHelp
return ProductHelp('Help', self.id).__of__(self)
InitializeClass(Product) InitializeClass(Product)
......
...@@ -15,16 +15,10 @@ ...@@ -15,16 +15,10 @@
from logging import getLogger from logging import getLogger
import os import os
import re
import stat
from AccessControl.Permission import registerPermissions from AccessControl.Permission import registerPermissions
from AccessControl.PermissionRole import PermissionRole from AccessControl.PermissionRole import PermissionRole
from App.Common import package_home
from App.ImageFile import ImageFile from App.ImageFile import ImageFile
from DateTime.DateTime import DateTime
from HelpSys import APIHelpTopic
from HelpSys import HelpTopic
from OFS.misc_ import Misc_ from OFS.misc_ import Misc_
from OFS.misc_ import misc_ from OFS.misc_ import misc_
from OFS.ObjectManager import ObjectManager from OFS.ObjectManager import ObjectManager
...@@ -48,8 +42,6 @@ class ProductContext: ...@@ -48,8 +42,6 @@ class ProductContext:
def __init__(self, product, app, package): def __init__(self, product, app, package):
self.__prod = product self.__prod = product
# app is None by default which signals disabled product installation
self.__app = app
self.__pack = package self.__pack = package
def registerClass(self, instance_class=None, meta_type='', def registerClass(self, instance_class=None, meta_type='',
...@@ -223,105 +215,16 @@ class ProductContext: ...@@ -223,105 +215,16 @@ class ProductContext:
setattr(misc_, pid, Misc_(pid, {})) setattr(misc_, pid, Misc_(pid, {}))
getattr(misc_, pid)[name]=icon getattr(misc_, pid)[name]=icon
def getProductHelp(self): def registerHelp(self, directory=None, clear=None, title_re=None):
""" pass
Returns the ProductHelp associated with the current Product.
"""
if self.__app is None:
return self.__prod.getProductHelp()
return self.__prod.__of__(self.__app.Control_Panel.Products).getProductHelp()
def registerHelpTopic(self, id, topic):
"""
Register a Help Topic for a product.
"""
self.getProductHelp()._setObject(id, topic)
def registerHelpTitle(self, title):
"""
Sets the title of the Product's Product Help
"""
h = self.getProductHelp()
if getattr(h, 'title', None) != title:
h.title = title
def registerHelp(self, directory='help', clear=1, def registerHelpTitle(self, title=None):
title_re=re.compile(r'<title>(.+?)</title>', re.I)): pass
"""
Registers Help Topics for all objects in a directory.
Nothing will be done if the files in the directory haven't
changed since the last registerHelp call.
'clear' indicates whether or not to delete all existing
Topics from the Product.
HelpTopics are created for these kind of files def getProductHelp(self):
class DummyHelp(object):
.dtml -- DTMLHelpTopic lastRegistered = None
.html .htm -- TextHelpTopic return DummyHelp()
.stx .txt -- STXHelpTopic
.jpg .png .gif -- ImageHelpTopic
.py -- APIHelpTopic
"""
if not self.__app:
return
help=self.getProductHelp()
path=os.path.join(package_home(self.__pack.__dict__),
directory)
# If help directory does not exist, log a warning and return.
try:
dir_mod_time=DateTime(os.stat(path)[stat.ST_MTIME])
except OSError, (errno, text):
LOG.warn('%s: %s' % (text, path))
return
# test to see if nothing has changed since last registration
if help.lastRegistered is not None and \
help.lastRegistered >= dir_mod_time:
return
help.lastRegistered=DateTime()
if clear:
for id in help.objectIds(['Help Topic','Help Image']):
help._delObject(id)
for file in os.listdir(path):
ext=os.path.splitext(file)[1]
ext=ext.lower()
if ext in ('.dtml',):
contents = open(os.path.join(path,file),'rb').read()
m = title_re.search(contents)
if m:
title = m.group(1)
else:
title = ''
ht=HelpTopic.DTMLTopic(file, '', os.path.join(path,file))
self.registerHelpTopic(file, ht)
elif ext in ('.html', '.htm'):
contents = open(os.path.join(path,file),'rb').read()
m = title_re.search(contents)
if m:
title = m.group(1)
else:
title = ''
ht=HelpTopic.TextTopic(file, title, os.path.join(path,file))
self.registerHelpTopic(file, ht)
elif ext in ('.stx', '.txt'):
title=(open(os.path.join(path,file),'rb').readline()).split(':')[0]
ht=HelpTopic.STXTopic(file, title, os.path.join(path, file))
self.registerHelpTopic(file, ht)
elif ext in ('.jpg', '.gif', '.png'):
ht=HelpTopic.ImageTopic(file, '', os.path.join(path, file))
self.registerHelpTopic(file, ht)
elif ext in ('.py',):
if file[0] == '_': # ignore __init__.py
continue
ht=APIHelpTopic.APIHelpTopic(file, '', os.path.join(path, file))
self.registerHelpTopic(file, ht)
class AttrDict: class AttrDict:
......
...@@ -8,13 +8,7 @@ ...@@ -8,13 +8,7 @@
</td> </td>
<td align="right" valign="top"> <td align="right" valign="top">
<div class="std-text"> <div class="std-text">
<dtml-if expr="help_topic and help_product">
<dtml-if expr="container.HelpSys.helpLink(help_product, help_topic)">
<dtml-var "container.HelpSys.helpLink(help_product, help_topic)">
</dtml-if>
<dtml-else>
&nbsp; &nbsp;
</dtml-if>
</div> </div>
</td> </td>
</tr> </tr>
......
...@@ -126,29 +126,6 @@ ...@@ -126,29 +126,6 @@
</dtml-if wl_isLocked> </dtml-if wl_isLocked>
</div> </div>
</td> </td>
<dtml-if "_.has_key('help_topic') and _.has_key('help_product')">
<dtml-if "HelpSys.helpLink(help_product, help_topic)">
<td align="right" valign="top">
<div class="std-text">
<dtml-var "HelpSys.helpLink(help_product, help_topic)">
</div>
</td>
</dtml-if>
<dtml-else>
<dtml-if manage_options>
<dtml-with "_(option=manage_options[a_])">
<dtml-if "option.has_key('help')">
<dtml-if "HelpSys.helpLink(option['help'][0], option['help'][1])">
<td align="right" valign="top">
<div class="std-text">
<dtml-var "HelpSys.helpLink(option['help'][0], option['help'][1])">
</div>
</td>
</dtml-if>
</dtml-if>
</dtml-with>
</dtml-if>
</dtml-if>
</tr> </tr>
</table> </table>
......
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
""" API documentation help topics.
"""
import types
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from App.special_dtml import DTMLFile
from Persistence import Persistent
from HelpTopic import HelpTopic # XXX relative to avoid cycle
_ignore_objects = {}
class APIHelpTopic(HelpTopic):
""" Provides API documentation.
"""
isAPIHelpTopic=1
funcs=() # for backward compatibility
def __init__(self, id, title, file):
self.id=id
self.title=title
dict={}
execfile(file, dict)
self.doc=dict.get('__doc__','')
self.apis=[]
self.funcs=[]
for k, v in dict.items():
if (not _ignore_objects.has_key(k) or
_ignore_objects[k] is not v):
if type(v)==types.ClassType:
# A class.
self.apis.append(APIDoc(v, 0))
elif (hasattr(v, 'implementedBy')):
# A zope.interface.Interface.
self.apis.append(APIDoc(v, 1))
elif type(v)==types.FunctionType:
# A function
self.funcs.append(MethodDoc(v, 0))
# try to get title from first non-blank line
# of module docstring
if not self.title:
lines=self.doc.split('\n')
while 1:
line=lines[0].strip()
if line:
# get rid of anything after a colon in the line
self.title=line.split(':')[0]
break
lines.pop(0)
if not lines:
break
# otherwise get title from first class name
if not self.title:
self.title=self.apis[0].name
index_html=DTMLFile('dtml/APIHelpView', globals())
def SearchableText(self):
"The full text of the Help Topic, for indexing purposes"
text="%s %s" % (self.title, self.doc)
for api in self.apis + self.funcs:
try: # not all api's provide SearchableText()
text="%s %s" % (text, api.SearchableText())
except AttributeError: pass
return text
class APIDoc(Persistent):
""" Describes an API.
"""
security = ClassSecurityInfo()
security.setDefaultAccess( {'attributes': True, 'constructor': True,
'doc': True, 'extends': True, 'name': True,
'methods': True} )
extends=()
def __init__(self, klass, isInterface=0):
if isInterface:
self._createFromInterface(klass)
else:
self._createFromClass(klass)
def _createFromInterface(self, klass):
# Creates an APIDoc instance given an interface object.
self.name=klass.__name__
self.doc=trim_doc_string(klass.__doc__)
# inheritence information
self.extends=[]
# Get info on methods and attributes, ignore special items
self.attributes=[]
self.methods=[]
for k,v in klass.namesAndDescriptions():
if hasattr(v, 'getSignatureInfo'):
self.methods.append(MethodDoc(v, 1))
else:
self.attributes.append(AttributeDoc(k, v.__doc__))
def _createFromClass(self, klass):
# Creates an APIDoc instance given a python class.
# the class describes the API; it contains
# methods, arguments and doc strings.
#
# The name of the API is deduced from the name
# of the class.
self.name=klass.__name__
self.doc=trim_doc_string(klass.__doc__)
# Get info on methods and attributes, ignore special items
self.attributes=[]
self.methods=[]
for k,v in klass.__dict__.items():
if k not in ('__extends__', '__doc__', '__constructor__'):
if type(v)==types.FunctionType:
self.methods.append(MethodDoc(v, 0))
else:
self.attributes.append(AttributeDoc(k, v))
def SearchableText(self):
"""
The full text of the API, for indexing purposes.
"""
text="%s %s" % (self.name, self.doc)
for attribute in self.attributes:
text="%s %s" % (text, attribute.name)
for method in self.methods:
text="%s %s %s" % (text, method.name, method.doc)
return text
view=DTMLFile('dtml/APIView', globals())
InitializeClass(APIDoc)
class AttributeDoc(Persistent):
""" Describes an attribute of an API.
"""
security = ClassSecurityInfo()
security.setDefaultAccess( {'name': True, 'value': True} )
def __init__(self, name, value):
self.name=name
self.value=value
view=DTMLFile('dtml/attributeView', globals())
InitializeClass(AttributeDoc)
class MethodDoc(Persistent):
""" Describes a method of an API.
required - a sequence of required arguments
optional - a sequence of tuples (name, default value)
varargs - the name of the variable argument or None
kwargs - the name of the kw argument or None
"""
security = ClassSecurityInfo()
security.setDefaultAccess( {'doc': True, 'kwargs': True, 'name': True,
'optional': True, 'required': True,
'varargs': True} )
varargs=None
kwargs=None
def __init__(self, func, isInterface=0):
if isInterface:
self._createFromInterfaceMethod(func)
else:
self._createFromFunc(func)
def _createFromInterfaceMethod(self, func):
self.name = func.__name__
self.doc = trim_doc_string(func.__doc__)
self.required = func.required
opt = []
for p in func.positional[len(func.required):]:
opt.append((p, func.optional[p]))
self.optional = tuple(opt)
if func.varargs:
self.varargs = func.varargs
if func.kwargs:
self.kwargs = func.kwargs
def _createFromFunc(self, func):
if hasattr(func, 'im_func'):
func=func.im_func
self.name=func.__name__
self.doc=trim_doc_string(func.__doc__)
# figure out the method arguments
# mostly stolen from pythondoc
CO_VARARGS = 4
CO_VARKEYWORDS = 8
names = func.func_code.co_varnames
nrargs = func.func_code.co_argcount
if func.func_defaults:
nrdefaults = len(func.func_defaults)
else:
nrdefaults = 0
self.required = names[:nrargs-nrdefaults]
if func.func_defaults:
self.optional = tuple(map(None, names[nrargs-nrdefaults:nrargs],
func.func_defaults))
else:
self.optional = ()
varargs = []
ix = nrargs
if func.func_code.co_flags & CO_VARARGS:
self.varargs=names[ix]
ix = ix+1
if func.func_code.co_flags & CO_VARKEYWORDS:
self.kwargs=names[ix]
view=DTMLFile('dtml/methodView', globals())
InitializeClass(MethodDoc)
def trim_doc_string(text):
"""
Trims a doc string to make it format
correctly with structured text.
"""
text=text.strip()
text=text.replace( '\r\n', '\n')
lines=text.split('\n')
nlines=[lines[0]]
if len(lines) > 1:
min_indent=None
for line in lines[1:]:
if not line:
continue
indent=len(line) - len(line.lstrip())
if indent < min_indent or min_indent is None:
min_indent=indent
for line in lines[1:]:
nlines.append(line[min_indent:])
return '\n'.join(nlines)
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os
from AccessControl.class_init import InitializeClass
from AccessControl.Permissions import access_contents_information
from AccessControl.Permissions import view as View
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Implicit
from App.config import getConfiguration
from App.ImageFile import ImageFile
from App.special_dtml import DTMLFile
from App.special_dtml import HTML
from ComputedAttribute import ComputedAttribute
from OFS.DTMLDocument import DTMLDocument
from OFS.PropertyManager import PropertyManager
from OFS.SimpleItem import Item
from Persistence import Persistent
class HelpTopicBase:
"Mix-in Help Topic support class"
_properties=(
{'id':'title', 'type':'string', 'mode':'w'},
{'id':'categories', 'type':'multiple selection',
'select_variable':'categories_values', 'mode':'w'},
{'id':'permissions', 'type':'multiple selection',
'select_variable':'permissions_values', 'mode':'w'},
)
# default values
categories=('Content Manager Information',)
permissions=('View',)
def _permissions_values(self):
perms=[]
for m in self.permission_settings():
perms.append(m['name'])
return perms
permissions_values=ComputedAttribute(_permissions_values, 1)
categories_values=(
'Content Manager Information',
'DTML Programmer Information',
'Python Programmer Information',
)
def helpValues(self, REQUEST=None):
return ()
def authorized(self, sm):
"Is a given user authorized to view this Help Topic?"
if not self.permissions:
return True
return any( sm.checkPermission(p, self) for p in self.permissions )
# Indexable methods
# -----------------
def SearchableText(self):
"The full text of the Help Topic, for indexing purposes"
raise NotImplementedError
def url(self):
"URL for indexing purposes"
return '/'.join(self.getPhysicalPath())
# Private indexing methods
# ------------------------
def manage_afterAdd(self, item, container):
self.index_object()
def manage_afterClone(self, item):
self.index_object()
def manage_beforeDelete(self, item, container):
self.unindex_object()
def _setPropValue(self, id, value):
setattr(self,id,value)
self.reindex_object()
def index_object(self, prefix=''):
self.get_catalog().catalog_object(self, prefix + self.url())
def unindex_object(self, prefix=''):
self.get_catalog().uncatalog_object(prefix + self.url())
def reindex_object(self):
self.unindex_object()
self.index_object()
def get_catalog(self):
return self.catalog
class HelpTopic(Implicit, HelpTopicBase, Item, PropertyManager, Persistent):
"""
Abstract base class for Help Topics
"""
meta_type='Help Topic'
icon='p_/HelpTopic_icon'
_v_last_read = 0
security = ClassSecurityInfo()
manage_options=(
{'label':'Properties', 'action':'manage_propertiesForm'},
{'label':'View', 'action':'index_html'},
)
security.declareProtected(View, 'SearchableText')
security.declareProtected(View, 'url')
security.declareProtected(access_contents_information, 'helpValues')
def _set_last_read(self, filepath):
try: mtime = os.stat(filepath)[8]
except: mtime = 0
self._v_last_read = mtime
def _check_for_update(self):
if getConfiguration().debug_mode:
try: mtime=os.stat(self.file)[8]
except: mtime=0
if mtime != self._v_last_read:
fileob = open(self.file)
self.obj = fileob.read()
fileob.close()
self._v_last_read=mtime
self.reindex_object()
security.declareProtected(View, 'index_html')
def index_html(self, REQUEST, RESPONSE):
"View the Help Topic"
raise NotImplementedError
InitializeClass(HelpTopic)
class DTMLDocumentTopic(HelpTopicBase, DTMLDocument):
"""
A user addable Help Topic based on DTML Document.
"""
meta_type='Help Topic'
icon='p_/HelpTopic_icon'
def munge(self,*args, **kw):
apply(DTMLDocument.munge, (self,) + args, kw)
self.reindex_object()
def SearchableText(self):
return '%s %s' % (self.title, self.read())
default_topic_content="""\
<html>
<head><title><dtml-var title_or_id></title>
</head>
<body bgcolor="#FFFFFF">
<h2><dtml-var title></h2>
<p>This is the <dtml-var id> Help Topic.</p>
</body>
</html>
"""
class DTMLTopic(HelpTopic):
"""
A basic Help Topic. Holds a HTMLFile object.
"""
def __init__(self, id, title, file, permissions=None, categories=None):
self.id=id
self.title=title
file,ext=os.path.splitext(file)
prefix,file=os.path.split(file)
self.index_html=DTMLFile(file,prefix)
if permissions is not None:
self.permissions=permissions
if categories is not None:
self.categories=categories
def SearchableText(self):
"The full text of the Help Topic, for indexing purposes"
return '%s %s' % (self.title, self.index_html.read())
class TextTopic(HelpTopic):
"""
A basic Help Topic. Holds a text file.
"""
index_html = None
def __init__(self, id, title, file, permissions=None, categories=None):
self.id=id
self.title=title
self.file = file
self.obj=open(file).read()
self._set_last_read(file)
if permissions is not None:
self.permissions=permissions
if categories is not None:
self.categories=categories
def __call__(self, REQUEST=None):
"View the Help Topic"
self._check_for_update()
return self.obj
def SearchableText(self):
"The full text of the Help Topic, for indexing purposes"
return '%s %s' % (self.title, self.obj)
class STXTopic(TextTopic):
"""
A structured-text topic. Holds a HTMLFile object.
"""
index_html = None
def __call__(self, REQUEST=None):
""" View the STX Help Topic """
self._check_for_update()
return self.htmlfile(self, REQUEST)
htmlfile = HTML("""\
<html>
<head><title><dtml-var title_or_id></title>
</head>
<body bgcolor="#FFFFFF">
<dtml-var obj fmt="structured-text">
</body>
</html>""")
class ReSTTopic(TextTopic):
"""
A reStructuredText [1]_ topic. Similar to STXTopic, it uses a
simle DTML construct to render its contents - this time using the
*reStructuredText* language.
.. [1] reStructuredText
(http://docutils.sourceforge.net/rst.html)
"""
index_html = None
def __call__(self, REQUEST=None):
""" Renders the ReST Help Topic """
self._check_for_update()
return self.htmlfile(self, REQUEST)
htmlfile = HTML("""\
<html>
<head><title><dtml-var title_or_id></title>
</head>
<body bgcolor="#FFFFFF">
<dtml-var obj fmt="restructured-text">
</body>
</html>""")
class ImageTopic(HelpTopic):
"""
A image Help Topic. Holds an ImageFile object.
"""
meta_type='Help Image'
def __init__(self, id, title, file, categories=None, permissions=None):
self.id=id
self.title=title
self.file = file
self.obj=open(file).read()
self._set_last_read(file)
dir, file=os.path.split(file)
self.image=ImageFile(file, dir)
if permissions is not None:
self.permissions=permissions
if categories is not None:
self.categories=categories
def index_html(self, REQUEST, RESPONSE):
"View the Help Topic"
self._check_for_update()
return self.image.index_html(REQUEST, RESPONSE)
def SearchableText(self):
"The full text of the Help Topic, for indexing purposes"
return ''
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Object Reference implementation"""
import sys
from urllib import quote
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from App.special_dtml import DTMLFile
from HelpSys.HelpUtil import classobject
from HelpSys.HelpUtil import HelpBase
from HelpSys.HelpUtil import is_class
from HelpSys.HelpUtil import is_module
class ObjectItem(HelpBase, classobject):
""" """
security = ClassSecurityInfo()
security.declareObjectPublic()
hs_main=DTMLFile('dtml/objectitem', globals())
hs_cicon='HelpSys/hs_dnode'
hs_eicon='HelpSys/hs_dnode'
def hs_id(self):
return self._obj_.meta_type
def hs_url(self):
return quote(self._obj_.meta_type)
hs_title=hs_id
def __getattr__(self, name):
if name in ('isDocTemp', '__call__'):
raise AttributeError, name
return getattr(self.__dict__['_obj_'], name)
def get_method_list(self):
rdict=classobject.get_method_dict(self)
perms=self.__ac_permissions__
mdict={}
mlist=[]
for p in self.__ac_permissions__:
pname=p[0]
fnames=p[1]
for fname in fnames:
if rdict.has_key(fname):
fn=rdict[fname]
fn.permission=pname
mdict[fname]=fn
keys=mdict.keys()
keys.sort()
for key in keys:
fn=mdict[key]
if not hasattr(fn._obj_, '__doc__'):
continue
doc=fn._obj_.__doc__
if hasattr(fn._obj_, '__class__') and \
fn._obj_.__class__.__doc__ is doc:
continue
mlist.append(mdict[key])
del rdict
del mdict
return mlist
security.declarePublic('hs_objectvalues')
def hs_objectvalues(self):
return []
InitializeClass(ObjectItem)
class ObjectRef(HelpBase):
""" """
security = ClassSecurityInfo()
security.declareObjectPublic()
__names__=None
hs_main=DTMLFile('dtml/objectref', globals())
hs_cicon='HelpSys/hs_cbook'
hs_eicon='HelpSys/hs_obook'
hs_id ='ObjectRef'
hs_title='Object Reference'
hs_url =hs_id
def hs_deferred__init__(self):
# This is necessary because we want to wait until all
# products have been installed (imported).
dict={}
for k, v in sys.modules.items():
if v is not None and k != '__builtins__':
dict=self.hs_search_mod(v, dict)
keys=dict.keys()
keys.sort()
__traceback_info__=(`dict`,)
for key in keys:
setattr(self, key, dict[key])
self.__names__=keys
def hs_search_mod(self, mod, dict):
# Root through a module for things that look like
# createable object classes.
hidden=('Control Panel', 'simple item',
'Broken Because Product is Gone')
for k, v in mod.__dict__.items():
if is_class(v) and hasattr(v, 'meta_type') and \
hasattr(v, '__ac_permissions__'):
if callable(v.meta_type):
meta_type=v.meta_type()
else:
meta_type=v.meta_type
if (meta_type is not None) and (meta_type not in hidden):
dict[meta_type]=ObjectItem(k, v)
if is_module(v) and hasattr(v, '__path__'):
dict=self.hs_search_mod(v, dict)
return dict
security.declarePublic('hs_objectvalues')
def hs_objectvalues(self):
if self.__names__ is None:
self.hs_deferred__init__()
items=[]
for id in self.__names__:
items.append(getattr(self, id))
return items
def __getitem__(self, key):
return self.__dict__[key].__of__(self)
InitializeClass(ObjectRef)
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
# backward compatibility
import HelpSys
import sys
sys.modules['HelpSys.HelpSystem']=HelpSys
<dtml-var standard_html_header>
<h1>API Documentation</h1>
<dtml-if "_.len(apis) > 1 or (apis and funcs)">
<h3>Classes</h3>
<dl><dd>
<h2 class="api">
<dtml-in apis>
<a href="#&dtml.url_quote-name;">&dtml-name;</a>
<dtml-unless sequence-end> , </dtml-unless>
</dtml-in>
</h2>
</dd></dl>
</dtml-if>
<dtml-if "_.len(funcs) > 1 or (apis and funcs)">
<h3>Functions</h3>
<dl><dd>
<h2 class="api">
<dtml-in funcs>
<a href="#&dtml.url_quote-name;">&dtml-name;</a>
<dtml-unless sequence-end> , </dtml-unless>
</dtml-in>
</h2>
</dd></dl>
</dtml-if>
<dtml-if doc>
<dtml-var doc fmt="structured-text">
<hr noshade>
</dtml-if>
<dtml-in apis>
<dtml-if expr="_['sequence-start'] and funcs">
<h2>Classes</h2>
</dtml-if>
<dtml-var view>
<dtml-unless expr="_['sequence-end'] and not funcs">
<hr noshade>
</dtml-unless>
</dtml-in>
<dtml-in funcs>
<dtml-if expr="_['sequence-start'] and apis">
<h2>Functions</h2>
</dtml-if>
<dtml-var view>
<dtml-unless sequence-end>
<hr noshade>
</dtml-unless>
</dtml-in>
<dtml-var standard_html_footer>
<a name="&dtml-name;"></a>
<h2 class="api">class
&dtml-name;<dtml-if extends>
(<dtml-in extends>
<a href="/Control_Panel/Products/&dtml-sequence-item;">&dtml-sequence-key;</a><dtml-unless sequence-end>, </dtml-unless>
</dtml-in>)
</dtml-if>
</h2>
<dl>
<dd>
<dtml-var doc fmt="structured-text">
</dd>
</dl>
<dtml-if constructor>
<hr>
<h3>Product Constructor</h3>
<dtml-with constructor>
<dtml-var view>
</dtml-with>
</dtml-if>
<dtml-if "attributes or methods">
<hr>
</dtml-if>
<dtml-in attributes>
<dtml-var view>
</dtml-in>
<dtml-if methods>
<h3>Methods</h3>
<dtml-in methods>
<dtml-var view>
</dtml-in>
</dtml-if>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Add Help Topic</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<h2>Add Help Topic</h2>
<form action="addTopic" method="post">
<table>
<tr valign="top">
<th>Id</th>
<td><input type="text" name="id"></td>
</tr>
<tr valign="top">
<th>Title</th>
<td><input type="text" name="title"></td>
</tr>
<tr valign="top">
<td colspan="2"><input type="submit" value="Add"></td>
</tr>
</table>
</form>
</body>
</html>
<a name="&dtml-name;"></a>
<h2 class="attribute">&dtml-name; = &dtml-value;
</h2>
<div align="right">
<SCRIPT LANGUAGE="JavaScript">
<!--
function openHelpWindow(url) {
helpWindow = window.open(url,"zope_help","width=600,height=500,menubar=yes,toolbar=yes,scrollbars=yes,resizable=yes");
helpWindow.focus();
return false;
}
//-->
</SCRIPT>
<font face="Verdana, Arial, Helvetica" size="1">
<FORM ACTION="&dtml-absolute_url;" METHOD="get" target="zope_help"
onSubmit="return openHelpWindow('&dtml-absolute_url;?help_url=&dtml.url_quote_plus-helpURL;');">
<input type="hidden" name="help_url" value="&dtml-helpURL;">
<input type="submit" name="submit" value=" Help ">
</FORM>
</font>
</div>
<HTML>
<HEAD>
<TITLE>Zope Help System</TITLE>
</HEAD>
<FRAMESET COLS="200,*">
<FRAME SRC="menu" NAME="help_menu"
MARGINWIDTH="2" MARGINHEIGHT="2" SCROLLING="auto">
<FRAME
<dtml-if "_.has_key('help_url')">
SRC="&dtml.url_quote-help_url;"
<dtml-else>
SRC="main"
</dtml-if>
NAME="help_main" MARGINWIDTH="2" MARGINHEIGHT="0" SCROLLING="auto">
</FRAMESET>
<NOFRAMES>
Management interfaces require the use of a <B>frames-capable</B> web browser.
</NOFRAMES>
</HTML>
\ No newline at end of file
&dtml-BASEPATH1;/Control_Panel/Products/&dtml-product;/Help/&dtml-topic;
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>Z Object Publishing Environment Help</title>
</head>
<frameset cols="180,*">
<frame src="&dtml-BASEPATH1;/HelpSys/hs_menu" name="hs_tframe"
marginwidth="2" marginheight="2" scrolling="auto">
<frame src="&dtml-BASEPATH1;/HelpSys/hs_main" NAME="hs_cframe"
marginwidth="2" marginheight="2" scrolling="auto">
</frameset>
<noframes>
This item requires the use of a <em>frames-capable</em> web browser.
</noframes>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>
Z Object Publishing Environment Help
</title>
</head>
<body bgcolor="#ffffff" link="#000099" vlink="#555555">
<h2>Z Object Publishing Environment Help</h2>
<p>
The Z online help system provides links to in-depth product guides,
programming references and other resources.
</p>
<h3>General Documentation</h3>
<p>
General documentation for the use and management of built-in and
add-on products, as well as an extensive DTML manual are available
on the Zope website at
<a href="http://www.zope.org" target="_top">http://www.zope.org</a>.
</p>
<p>The <a href="http://www.zope.org/Documentation/Guides" target="_top">Zope Guides</a> are a great place to start learning Zope.
<ul>
<li><a href="http://www.zope.org/Documentation/Guides/ZCMG">Zope Content Manager's Guide</a></li>
<li><a href="http://www.zope.org/Documentation/Guides/DTML">Z Document Template User's Guide</a></li>
</ul>
</p>
<h3>Programming References</h3>
<p>
There is currently an online object reference that documents the
services provided by high-level objects such as Documents
and Folders. Other references will be added soon.
</p>
<ul>
<li> <a href="&dtml-BASE1;/HelpSys/ObjectRef/hs_main">
Object Reference
</a>
</ul>
<h3>Other Resources</h3>
<p>
One of the best resources available is the
<a href="http://www.zope.org/mailman/listinfo/zope" target="_top">Zope mailing list</a>.
You can subscribe to the mailing list by sending an
email to <a href="mailto:zope-request@zope.org">zope-request@zope.org</a>
and including the word &quot;subscribe&quot; in the subject line.
</p>
<p>
There is also a <a href="http://zdp.zope.org/" target="_top">Zope documentation project</a> working on a Zope FAQ
</p>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>Z Object Publishing Environment Help</title>
</head>
<body bgcolor="#ffffff" link="#000099" vlink="#555555">
<table cellspacing="0">
<tr>
<td valign="top" nowrap>
<a href="hs_main" target="hs_cframe">
<img src="&dtml-BASEPATH1;/&dtml-hs_eicon;" border="0"
alt="Z Online Help"></a>
<strong>
<a href="hs_main" target="hs_cframe">
Z Online Help
</a>
</strong>
</td>
</tr>
</table>
<dtml-tree id=hs_id url=hs_url branches=hs_objectvalues nowrap=1>
<a href="&dtml.-tree-item-url;/hs_main" target="hs_cframe">
<dtml-if tree-item-expanded>
<img src="&dtml-BASEPATH1;/&dtml-hs_eicon;" border="0" alt="click to view this item"></a>
<dtml-else>
<img src="&dtml-BASEPATH1;/&dtml-hs_cicon;" border="0" alt="click to view this item"></a>
</dtml-if>
<a href="&dtml.-tree-item-url;/hs_main" target="hs_cframe">
&dtml-hs_title;
</a>
</dtml-tree>
</body>
</html>
<dtml-var standard_html_header>
<dtml-call "REQUEST.set('MANAGE_TABS_NO_BANNER',1)">
<dtml-var manage_tabs>
<dtml-tree sort=id>
<dtml-if "meta_type =='Help Topic'">
<a href="&dtml-absolute_url;" target="help_main">&dtml-title_or_id;</a>
<dtml-else>
&dtml-title;
</dtml-if>
</dtml-tree>
<dtml-var standard_html_footer>
<html>
<head>
<title>&dtml-title;</title>
</head>
<body bgcolor="#FFFFFF">
<a name="&dtml-name;"></a>
<h2 class="method">&dtml-name;(<dtml-in required>&dtml-sequence-item;<dtml-if sequence-end>
<dtml-if optional>, </dtml-if>
<dtml-else>,
</dtml-if>
</dtml-in>
<dtml-in optional>
&dtml-sequence-key;=&dtml-sequence-item;<dtml-unless sequence-end>, </dtml-unless>
</dtml-in>
<dtml-if varargs>, *&dtml-varargs;</dtml-if>
<dtml-if kwargs>, **&dtml-kwargs;</dtml-if>):
</h2>
<dl><dd>
<dtml-var doc fmt="structured-text">
</dd></dl>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>
Object Reference
</title>
</head>
<body bgcolor="#ffffff" link="#000099" vlink="#555555">
<a name="top">
<h2><a href="../hs_main">Object Reference</a></h2>
<h3><dtml-if icon><img src="&dtml-BASEPATH1;/&dtml-icon;" height="16" width="16" alt=""></dtml-if> &dtml-meta_type;</h3>
<code>
<dtml-var get_docstring_html>
</code>
<h3>&dtml-meta_type; methods</h3>
<dtml-call "REQUEST.set('cached_method_list', get_method_list())">
<dtml-call "REQUEST.set('row_max', _.len(cached_method_list)/2)">
<dtml-if "_.len(cached_method_list) % 2">
<dtml-call "REQUEST.set('row_max', row_max+1)">
</dtml-if>
<table width="100%" border="0">
<tr>
<td align="left" valign="top">
<code>
<dtml-in "cached_method_list[:row_max]">
<a href="#&dtml.url_quote-get_name;">&dtml-get_name;</a><br>
</dtml-in>
</code>
</td>
<td align="left" valign="top">
<code>
<dtml-in "cached_method_list[row_max:]">
<a href="#&dtml.url_quote-get_name;">&dtml-get_name;</a><br>
</dtml-in>
</code>
</td>
</tr>
</table>
<dl>
<dtml-in cached_method_list>
<dt><code>
<a name="&dtml-get_name;">
<strong>&dtml-get_signature;</strong>
</code>
</dt>
<dd><code>
<dtml-if permission>
<strong>Permission:</strong> &dtml-permission;<br><br>
</dtml-if>
<dtml-if get_docstring_html>
<dtml-var get_docstring_html>
<dtml-else>
<p>No documentation for this method</p>
</dtml-if>
<a href="#top"><img src="&dtml-BASEPATH1;/HelpSys/hs_uarrow" height="9" width="9" border="0" valign="bottom" alt=""> top</a><br><br>
</code>
</dd>
</dtml-in>
</dl>
<p>
<a href="../hs_main">
<img src="&dtml-BASEPATH1;/HelpSys/hs_larrow" height="9" width="9" border="0" valign="bottom" alt=""> Back to Object Reference</a>
</p>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html lang="en">
<head>
<title>
Object Reference
</title>
</head>
<body bgcolor="#ffffff" link="#000099" vlink="#555555">
<h2>Object Reference</h2>
<p>
The object reference documents the interfaces of
objects which are built in to the system or have
been installed as add-on products. This reference
focuses on those object services useful in
<em>DTML scripting</em>.
</p>
<ul>
<dtml-in hs_objectvalues>
<dtml-with sequence-item>
<li> <a href="&dtml-BASEPATH1/HelpSys/ObjectRef/&dtml.url_quote-meta_type;/hs_main">&dtml-meta_type;</a>
</dtml-with>
</li>
</dtml-in>
</ul>
<p>
<a href="../hs_main">
<img src="&dtml-BASEPATH1;/HelpSys/hs_larrow" height="9" width="9" border="0" valign="bottom" alt=""> Back to Help</a>
</p>
</body>
</html>
<dtml-var standard_html_header>
<dtml-call "REQUEST.set('MANAGE_TABS_NO_BANNER',1)">
<dtml-call "REQUEST.set('management_view', 'Search')">
<dtml-var manage_tabs>
<p>Help topics matching <b>&dtml-SearchableText;</b>:</p>
<p>
<dtml-in "searchResults(REQUEST)">
<a href="&dtml-BASEPATH1;&dtml-url;" target="help_main">&dtml-title_or_id;</a><br>
<dtml-else>
<em>No matches.</em>
</dtml-in>
</p>
<dtml-var standard_html_footer>
<dtml-var standard_html_header>
<dtml-call "REQUEST.set('MANAGE_TABS_NO_BANNER',1)">
<dtml-var manage_tabs>
<p>
<form action="results" method="GET">
Search terms
<input type="text" name="SearchableText" size="16">
<input type="submit" value=" Search ">
</form>
</p>
<dtml-var standard_html_footer>
<html>
<head>
<title>&dtml-title;</title>
<style type="text/css">
.instructions{
background: #FFFFAA;
border-width: thin;
border-style: solid;
padding: 10pt;
}
.explanation{
border-width: thin;
border-style: solid;
padding: 10pt;
}
.api{
font-size: 14pt;
font-family : "Courier New", Courier, monospace;
}
.attribute, .method{
font-size: 12pt;
font-family : "Courier New", Courier, monospace;
}
</style>
</head>
<body bgcolor="#FFFFFF">
...@@ -27,7 +27,6 @@ from App.ApplicationManager import ApplicationManager ...@@ -27,7 +27,6 @@ from App.ApplicationManager import ApplicationManager
from App.config import getConfiguration from App.config import getConfiguration
from App import FactoryDispatcher from App import FactoryDispatcher
from DateTime import DateTime from DateTime import DateTime
from HelpSys.HelpSys import HelpSys
from OFS.metaconfigure import get_packages_to_initialize from OFS.metaconfigure import get_packages_to_initialize
from OFS.metaconfigure import package_initialized from OFS.metaconfigure import package_initialized
from OFS.userfolder import UserFolder from OFS.userfolder import UserFolder
...@@ -65,10 +64,6 @@ class Application(ApplicationDefaultPermissions, ...@@ -65,10 +64,6 @@ class Application(ApplicationDefaultPermissions,
web__form__method = 'GET' web__form__method = 'GET'
isTopLevelPrincipiaApplicationObject = 1 isTopLevelPrincipiaApplicationObject = 1
# Create the help system object
HelpSys = HelpSys('HelpSys')
manage_options=(( manage_options=((
Folder.Folder.manage_options[0], Folder.Folder.manage_options[0],
Folder.Folder.manage_options[1], Folder.Folder.manage_options[1],
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
<five:deprecatedManageAddDelete <five:deprecatedManageAddDelete
class="OFS.userfolder.BasicUserFolder"/> class="OFS.userfolder.BasicUserFolder"/>
<five:deprecatedManageAddDelete
class="HelpSys.HelpTopic.HelpTopicBase"/>
<five:deprecatedManageAddDelete <five:deprecatedManageAddDelete
class="OFS.Cache.CacheManager"/> class="OFS.Cache.CacheManager"/>
......
...@@ -841,8 +841,6 @@ class IApplication(IFolder, IRoot): ...@@ -841,8 +841,6 @@ class IApplication(IFolder, IRoot):
title=u"Is top level Principa application object", title=u"Is top level Principa application object",
) )
HelpSys = Attribute("Help system")
p_ = Attribute(""" """) p_ = Attribute(""" """)
misc_ = Attribute("Misc.") misc_ = Attribute("Misc.")
......
...@@ -73,11 +73,6 @@ class p_: ...@@ -73,11 +73,6 @@ class p_:
Properties_icon = ImageFile('www/Properties_icon.gif', ofs_dir) Properties_icon = ImageFile('www/Properties_icon.gif', ofs_dir)
Propertysheets_icon = ImageFile('www/Properties_icon.gif', ofs_dir) Propertysheets_icon = ImageFile('www/Properties_icon.gif', ofs_dir)
import HelpSys
helpsys_dir = dirname(HelpSys.__file__)
ProductHelp_icon=ImageFile('images/productHelp.gif', helpsys_dir)
HelpTopic_icon=ImageFile('images/helpTopic.gif', helpsys_dir)
InitializeClass(p_) InitializeClass(p_)
......
...@@ -501,6 +501,3 @@ def initialize(context): ...@@ -501,6 +501,3 @@ def initialize(context):
manage_addPageTemplate), manage_addPageTemplate),
icon='www/zpt.gif', icon='www/zpt.gif',
) )
context.registerHelp()
context.registerHelpTitle('Zope Help')
Edit View: Edit A Page Template
Description
This view allows you to edit the template's text, upload new
text, or change the content type and title of the template.
Template Text
The text in a template must be well-formed HTML if the content
type is 'text/html'. Otherwise, it must be well-formed XML.
Either way, it may include "TAL":tal.stx or "METAL":metal.stx
markup containing "TALES":tales.stx expressions.
Controls
'Title' -- Allows you to specify the Zope title of the template.
'Content-Type' -- Allows you to specify the content-type that
will be given to renderings of this template. Also, if the
content type is 'text/html' (the default) then the template is
assumed to contain HTML, not XML. This affects both parsing
and rendering of the template, and can be overridden by giving
the template an 'is_html' property. In HTML mode you don't
need to explicitly declare 'tal' and 'metal' XML namespaces. In
XML mode you must explicitly declare 'tal' and 'metal' XML
namespaces, and Zope assumes that your template contains
well-formed XML.
'Expand macros when editing' -- Allows you to turn the expansion
of METAL macros on or off. This only affects viewing of the
source code, not rendering.
Buttons and Other Form Elements
'Save Changes' -- saves changes you make to the body, title, or
content type.
'Taller'/'Shorter'/'Wider'/'Narrower' -- make the body textarea
taller, shorter, wider, or narrower.
'File' -- upload a file into this template.
File Upload Details
Files uploaded into a template must be valid HTML or XML text.
"""
ZTUtils: Page Template Utilities
The classes in this module are available from Page Templates.
"""
class Batch:
"""
Batch - a section of a large sequence.
You can use batches to break up large sequences (such as search
results) over several pages.
Batches provide Page Templates with similar functions as those
built-in to '<dtml-in>'.
You can access elements of a batch just as you access elements of
a list. For example::
>>> b=Batch(range(100), 10)
>>> b[5]
4
>>> b[10]
IndexError: list index out of range
Batches have these public attributes:
start -- The first element number (counting from 1).
first -- The first element index (counting from 0). Note that this
is that same as start - 1.
end -- The last element number (counting from 1).
orphan -- The desired minimum batch size. This controls how
sequences are split into batches. If a batch smaller than the
orphan size would occur, then no split is performed, and a batch
larger than the batch size results.
overlap -- The number of elements that overlap between batches.
length -- The actual length of the batch. Note that this can be
different than size due to orphan settings.
size -- The desired size. Note that this can be different than the
actual length of the batch due to orphan settings.
previous -- The previous batch or None if this is the first batch.
next -- The next batch or None if this is the last batch.
"""
def __init__(self, sequence, size, start=0, end=0,
orphan=0, overlap=0):
"""
Creates a new batch given a sequence and a desired batch
size.
sequence -- The full sequence.
size -- The desired batch size.
start -- The index of the start of the batch (counting from 0).
end -- The index of the end of the batch (counting from 0).
orphan -- The desired minimum batch size. This controls how
sequences are split into batches. If a batch smaller than the
orphan size would occur, then no split is performed, and a
batch larger than the batch size results.
overlap -- The number of elements that overlap between
batches.
"""
define-macro: Define a macro
Syntax
'metal:define-macro' syntax::
argument ::= Name
Description
The 'metal:define-macro' statement defines a macro. The macro is
named by the statement expression, and is defined as the element
and its sub-tree.
In Zope, a macro definition is available as a sub-object of a
template's 'macros' object. For example, to access a macro named
'header' in a template named 'master.html', you could use the path
expression 'master.html/macros/header'.
Examples
Simple macro definition::
<p metal:define-macro="copyright">
Copyright 2001, <em>Foobar</em> Inc.
</p>
See Also
"metal:use-macro":metal-use-macro.stx
"metal:define-slot":metal-define-slot.stx
define-slot: Define a macro customization point
Syntax
'metal:define-slot' syntax::
argument ::= Name
Description
The 'metal:define-slot' statement defines a macro customization
point or *slot*. When a macro is used, its slots can be replaced,
in order to customize the macro. Slot definitions provide default
content for the slot. You will get the default slot contents if
you decide not to customize the macro when using it.
The 'metal:define-slot' statement must be used inside a
'metal:define-macro' statement.
Slot names must be unique within a macro.
Examples
Simple macro with slot::
<p metal:define-macro="hello">
Hello <b metal:define-slot="name">World</b>
</p>
This example defines a macro with one slot named 'name'. When you
use this macro you can customize the 'b' element by filling the
'name' slot.
See Also
"metal:fill-slot":metal-fill-slot.stx
fill-slot: Customize a macro
Syntax
'metal:fill-slot' syntax::
argument ::= Name
Description
The 'metal:fill-slot' statement customizes a macro by replacing a
*slot* in the macro with the statement element (and its content).
The 'metal:fill-slot' statement must be used inside a
'metal:use-macro' statement.
Slot names must be unique within a macro.
If the named slot does not exist within the macro, the slot
contents will be silently dropped.
Examples
Given this macro::
<p metal:define-macro="hello">
Hello <b metal:define-slot="name">World</b>
</p>
You can fill the 'name' slot like so::
<p metal:use-macro="container/master.html/macros/hello">
Hello <b metal:fill-slot="name">Kevin Bacon</b>
</p>
See Also
"metal:define-slot":metal-define-slot.stx
use-macro: Use a macro
Syntax
'metal:use-macro' syntax::
argument ::= expression
Description
The 'metal:use-macro' statement replaces the statement element
with a macro. The statement expression describes a macro
definition.
In Zope the expression will generally be a path expression
referring to a macro defined in another template. See
"metal:define-macro" for more information.
The effect of expanding a macro is to graft a subtree from another
document (or from elsewhere in the current document) in place of
the statement element, replacing the existing sub-tree. Parts of
the original subtree may remain, grafted onto the new subtree, if
the macro has *slots*. See
"metal:define-slot":metal-define-slot.stx for more information. If
the macro body uses any macros, they are expanded first.
When a macro is expanded, its 'metal:define-macro' attribute is
replaced with the 'metal:use-macro' attribute from the statement
element. This makes the root of the expanded macro a valid
'use-macro' statement element.
Examples
Basic macro usage::
<p metal:use-macro="container/other.html/macros/header">
header macro from defined in other.html template
</p>
This example refers to the 'header' macro defined in the
'other.html' template which is in the same folder as the current
template. When the macro is expanded, the 'p' element and its
contents will be replaced by the macro. Note: there will still be
a 'metal:use-macro' attribute on the replacement element.
See Also
"metal:define-macro":metal-define-macro.stx
"metal:fill-slot":metal-fill-slot.stx
METAL Overview
The *Macro Expansion Template Attribute Language* (METAL) standard
is a facility for HTML/XML macro preprocessing. It can be used in
conjunction with or independently of "TAL":tal.stx and
"TALES":tales.stx.
Macros provide a way to define a chunk of presentation in one
template, and share it in others, so that changes to the macro are
immediately reflected in all of the places that share it.
Additionally, macros are always fully expanded, even in a template's
source text, so that the template appears very similar to its final
rendering.
METAL Namespace
The METAL namespace URI and recommended alias are currently
defined as::
xmlns:metal="http://xml.zope.org/namespaces/metal"
Just like the TAL namespace URI, this URI is not attached to a web
page; it's just a unique identifier.
Zope does not require an XML namespace declaration when creating
templates with a content-type of 'text/html'. However, it does
require an XML namespace declaration for all other content-types.
METAL Statements
METAL defines a number of statements:
* "metal:define-macro":metal-define-macro.stx - Define a macro.
* "metal:use-macro":metal-use-macro.stx - Use a macro.
* "metal:define-slot":metal-define-slot.stx - Define a macro
customization point.
* "metal:fill-slot":metal-fill-slot.stx - Customize a macro.
Although METAL does not define the syntax of expression
non-terminals, leaving that up to the implementation, a canonical
expression syntax for use in METAL arguments is described in
"TALES Specification":tales.stx.
See Also
"TAL Overview":tal.stx
"TALES Overview":tales.stx
"metal:define-macro":metal-define-macro.stx
"metal:use-macro":metal-use-macro.stx
"metal:define-slot":metal-define-slot.stx
"metal:fill-slot":metal-fill-slot.stx
attributes: Replace element attributes
Syntax
'tal:attributes' syntax::
argument ::= attribute_statement [';' attribute_statement]*
attribute_statement ::= attribute_name expression
attribute_name ::= [namespace ':'] Name
namespace ::= Name
*Note: If you want to include a semi-colon (;) in an 'expression',
it must be escaped by doubling it (;;).*
Description
The 'tal:attributes' statement replaces the value of an attribute
(or creates an attribute) with a dynamic value. You can qualify an
attribute name with a namespace prefix, for example 'html:table', if
you are generating an XML document with multiple namespaces. The
value of each expression is converted to a string, if necessary.
If the expression associated with an attribute assignment evaluates
to *nothing*, then that attribute is deleted from the statement
element. If the expression evaluates to *default*, then that
attribute is left unchanged. Each attribute assignment is
independent, so attributes may be assigned in the same statement in
which some attributes are deleted and others are left alone.
If you use 'tal:attributes' on an element with an active
'tal:replace' command, the 'tal:attributes' statement is ignored.
If you use 'tal:attributes' on an element with a 'tal:repeat'
statement, the replacement is made on each repetition of the
element, and the replacement expression is evaluated fresh for each
repetition.
Examples
Replacing a link::
<a href="/sample/link.html"
tal:attributes="href here/sub/absolute_url">
Replacing two attributes::
<textarea rows="80" cols="20"
tal:attributes="rows request/rows;cols request/cols">
condition: Conditionally insert or remove an element
Syntax
'tal:condition' syntax::
argument ::= expression
Description
The 'tal:condition' statement includes the statement element in the
template only if the condition is met, and omits it otherwise. If
its expression evaluates to a *true* value, then normal processing
of the element continues, otherwise the statement element is
immediately removed from the template. For these purposes, the
value *nothing* is false, and *default* has the same effect as
returning a true value.
*Note: Zope considers missing variables, None, zero, empty strings,
and empty sequences false; all other values are true.*
Examples
Test a variable before inserting it (the first example tests for
existence and truth, while the second only tests for existence)::
<p tal:condition="request/message | nothing"
tal:content="request/message">message goes here</p>
<p tal:condition="exists:request/message"
tal:content="request/message">message goes here</p>
Test for alternate conditions::
<div tal:repeat="item python:range(10)">
<p tal:condition="repeat/item/even">Even</p>
<p tal:condition="repeat/item/odd">Odd</p>
</div>
content: Replace the content of an element
Syntax
'tal:content' syntax::
argument ::= (['text'] | 'structure') expression
Description
Rather than replacing an entire element, you can insert text or
structure in place of its children with the 'tal:content'
statement. The statement argument is exactly like that of
'tal:replace', and is interpreted in the same fashion. If the
expression evaluates to *nothing*, the statement element is left
childless. If the expression evaluates to *default*, then the
element's contents are unchanged.
*Note: The default replacement behavior is 'text'.*
Examples
Inserting the user name::
<p tal:content="user/getUserName">Fred Farkas</p>
Inserting HTML/XML::
<p tal:content="structure here/getStory">marked <b>up</b>
content goes here.</p>
See Also
"'tal:replace'":tal-replace.stx
define: Define variables
Syntax
'tal:define' syntax::
argument ::= define_scope [';' define_scope]*
define_scope ::= (['local'] | 'global') define_var
define_var ::= variable_name expression
variable_name ::= Name
*Note: If you want to include a semi-colon (;) in an 'expression',
it must be escaped by doubling it (;;).*
Description
The 'tal:define' statement defines variables. You can define two
different kinds of TAL variables: local and global. When you
define a local variable in a statement element, you can only use
that variable in that element and the elements it contains. If
you redefine a local variable in a contained element, the new
definition hides the outer element's definition within the inner
element. When you define a global variables, you can use it in
any element processed after the defining element. If you redefine
a global variable, you replace its definition for the rest of the
template.
*Note: local variables are the default*
If the expression associated with a variable evaluates to
*nothing*, then that variable has the value *nothing*, and may be
used as such in further expressions. Likewise, if the expression
evaluates to *default*, then the variable has the value *default*,
and may be used as such in further expressions.
Examples
Defining a global variable::
tal:define="global company_name string:Zope Corp, Inc."
Defining two variables, where the second depends on the first::
tal:define="mytitle template/title; tlen python:len(mytitle)"
omit-tag: Remove an element, leaving its contents
Syntax
'tal:omit-tag' syntax::
argument ::= [ expression ]
Description
The 'tal:omit-tag' statement leaves the contents of a tag in place
while omitting the surrounding start and end tag.
If its expression evaluates to a *false* value, then normal
processing of the element continues and the tag is not omitted.
If the expression evaluates to a *true* value, or there is no
expression, the statement tag is replaced with its contents.
Zope treats empty strings, empty sequences, zero, None, *nothing*,
and *default* at false. All other values are considered true.
Examples
Unconditionally omitting a tag::
<div tal:omit-tag="" comment="This tag will be removed">
<i>...but this text will remain.</i>
</div>
Conditionally omitting a tag::
<b tal:omit-tag="not:bold">I may be bold.</b>
The above example will omit the 'b' tag if the variable 'bold' is
false.
Creating ten paragraph tags, with no enclosing tag::
<span tal:repeat="n python:range(10)"
tal:omit-tag="">
<p tal:content="n">1</p>
</span>
on-error: Handle errors
Syntax
'tal:on-error' syntax::
argument ::= (['text'] | 'structure') expression
Description
The 'tal:on-error' statement provides error handling for your
template. When a TAL statement produces an error, the TAL
interpreter searches for a 'tal:on-error' statement on the same
element, then on the enclosing element, and so forth. The first
'tal:on-error' found is invoked. It is treated as a 'tal:content'
statement.
A local variable 'error' is set. This variable has these
attributes:
'type' -- the exception type
'value' -- the exception instance
'traceback' -- the traceback object
The simplest sort of 'tal:on-error' statement has a literal error
string or *nothing* for an expression. A more complex handler may
call a script that examines the error and either emits error text
or raises an exception to propagate the error outwards.
Examples
Simple error message::
<b tal:on-error="string: Username is not defined!"
tal:content="here/getUsername">Ishmael</b>
Removing elements with errors::
<b tal:on-error="nothing"
tal:content="here/getUsername">Ishmael</b>
Calling an error-handling script::
<div tal:on-error="structure here/errorScript">
...
</div>
Here's what the error-handling script might look like::
## Script (Python) "errHandler"
##bind namespace=_
##
error=_['error']
if error.type==ZeroDivisionError:
return "<p>Can't divide by zero.</p>"
else
return """<p>An error ocurred.</p>
<p>Error type: %s</p>
<p>Error value: %s</p>""" % (error.type,
error.value)
See Also
"Python Tutorial: Errors and
Exceptions":http://www.python.org/doc/current/tut/node10.html
"Python Built-in
Exceptions":http://www.python.org/doc/current/lib/module-exceptions.html
repeat: Repeat an element
Syntax
'tal:repeat' syntax::
argument ::= variable_name expression
variable_name ::= Name
Description
The 'tal:repeat' statement replicates a sub-tree of your document
once for each item in a sequence. The expression should evaluate
to a sequence. If the sequence is empty, then the statement
element is deleted, otherwise it is repeated for each value in the
sequence. If the expression is *default*, then the element is
left unchanged, and no new variables are defined.
The 'variable_name' is used to define a local variable and a
repeat variable. For each repetition, the local variable is set to
the current sequence element, and the repeat variable is set to an
iteration object.
Repeat Variables
You use repeat variables to access information about the current
repetition (such as the repeat index). The repeat variable has
the same name as the local variable, but is only accessible
through the built-in variable named 'repeat'.
The following information is available from the repeat variable:
o *index* - repetition number, starting from zero.
o *number* - repetition number, starting from one.
o *even* - true for even-indexed repetitions (0, 2, 4, ...).
o *odd* - true for odd-indexed repetitions (1, 3, 5, ...).
o *start* - true for the starting repetition (index 0).
o *end* - true for the ending, or final, repetition.
o *first* - true for the first item in a group - see note below
o *last* - true for the last item in a group - see note below
o *length* - length of the sequence, which will be the total number
of repetitions.
o *letter* - repetition number as a lower-case letter: "a" -
"z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz",
and so forth.
o *Letter* - upper-case version of *letter*.
o *roman* - repetition number as a lower-case roman numeral:
"i", "ii", "iii", "iv", "v", etc.
o *Roman* - upper-case version of *roman*.
You can access the contents of the repeat variable using path
expressions or Python expressions. In path expressions, you write
a three-part path consisting of the name 'repeat', the statement
variable's name, and the name of the information you want, for
example, 'repeat/item/start'. In Python expressions, you use
normal dictionary notation to get the repeat variable, then
attribute access to get the information, for example,
"python:repeat['item'].start".
Note that 'first' and 'last' are intended for use with sorted
sequences. They try to divide the sequence into group of items
with the same value. If you provide a path, then the value
obtained by following that path from a sequence item is used for
grouping, otherwise the value of the item is used. You can
provide the path by passing it as a parameter, as in
"python:repeat['item'].first('color')", or by appending it to the
path from the repeat variable, as in "repeat/item/first/color".
Examples
Iterating over a sequence of strings::
<p tal:repeat="txt python:'one', 'two', 'three'">
<span tal:replace="txt" />
</p>
Inserting a sequence of table rows, and using the repeat variable
to number the rows::
<table>
<tr tal:repeat="item here/cart">
<td tal:content="repeat/item/number">1</td>
<td tal:content="item/description">Widget</td>
<td tal:content="item/price">$1.50</td>
</tr>
</table>
Nested repeats::
<table border="1">
<tr tal:repeat="row python:range(10)">
<td tal:repeat="column python:range(10)">
<span tal:define="x repeat/row/number;
y repeat/column/number;
z python:x*y"
tal:replace="string:$x * $y = $z">1 * 1 = 1</span>
</td>
</tr>
</table>
Insert objects. Seperates groups of objects by meta-type by
drawing a rule between them::
<div tal:repeat="object objects">
<h2 tal:condition="repeat/object/first/meta_type"
tal:content="object/meta_type">Meta Type</h2>
<p tal:content="object/getId">Object ID</p>
<hr tal:condition="repeat/object/last/meta_type" />
</div>
Note, the objects in the above example should already be sorted by
meta-type.
replace: Replace an element
Syntax
'tal:replace' syntax::
argument ::= (['text'] | 'structure') expression
Description
The 'tal:replace' statement replaces an element with dynamic
content. It replaces the statement element with either text or a
structure (unescaped markup). The body of the statement is an
expression with an optional type prefix. The value of the
expression is converted into an escaped string if you prefix the
expression with 'text' or omit the prefix, and is inserted
unchanged if you prefix it with 'structure'. Escaping consists of
converting "&amp;" to "&amp;amp;", "&lt;" to "&amp;lt;", and
"&gt;" to "&amp;gt;".
If the value is *nothing*, then the element is simply removed. If
the value is *default*, then the element is left unchanged.
Examples
The two ways to insert the title of a template::
<span tal:replace="template/title">Title</span>
<span tal:replace="text template/title">Title</span>
Inserting HTML/XML::
<div tal:replace="structure table" />
Inserting nothing::
<div tal:replace="nothing">This element is a comment.</div>
See Also
"'tal:content'":tal-content.stx
TAL Overview
The *Template Attribute Language* (TAL) standard is an attribute
language used to create dynamic templates. It allows elements of a
document to be replaced, repeated, or omitted.
The statements of TAL are XML attributes from the TAL namespace.
These attributes can be applied to an XML or HTML document in order
to make it act as a template.
A **TAL statement** has a name (the attribute name) and a body (the
attribute value). For example, an 'content' statement might look
like 'tal:content="string:Hello"'. The element on which a statement
is defined is its **statement element**. Most TAL statements
require expressions, but the syntax and semantics of these
expressions are not part of TAL. TALES is recommended for this
purpose.
TAL Namespace
The TAL namespace URI and recommended alias are currently defined
as::
xmlns:tal="http://xml.zope.org/namespaces/tal"
This is not a URL, but merely a unique identifier. Do not expect
a browser to resolve it successfully.
Zope does not require an XML namespace declaration when creating
templates with a content-type of 'text/html'. However, it does
require an XML namespace declaration for all other content-types.
TAL Statements
These are the tal statements:
- "tal:attributes":tal-attributes.stx - dynamically change
element attributes.
- "tal:define":tal-define.stx - define variables.
- "tal:condition":tal-condition.stx - test conditions.
- "tal:content":tal-content.stx - replace the content of an
element.
- "tal:omit-tag":tal-omit-tag.stx - remove an element, leaving
the content of the element.
- "tal:on-error":tal-on-error.stx - handle errors.
- "tal:repeat":tal-repeat.stx - repeat an element.
- "tal:replace":tal-replace.stx - replace the content of an
element and remove the element leaving the content.
Expressions used in statements may return values of any type,
although most statements will only accept strings, or will convert
values into a string representation. The expression language must
define a value named *nothing* that is not a string. In
particular, this value is useful for deleting elements or
attributes.
Order of Operations
When there is only one TAL statement per element, the order in
which they are executed is simple. Starting with the root
element, each element's statements are executed, then each of its
child elements is visited, in order, to do the same.
Any combination of statements may appear on the same elements,
except that the 'content' and 'replace' statements may not appear
together.
When an element has multiple statements, they are executed in this
order:
1. 'define'
2. 'condition'
3. 'repeat'
4. 'content' or 'replace'
5. 'attributes'
6. 'omit-tag'
Since the 'on-error' statement is only invoked when an error occurs,
it does not appear in the list.
The reasoning behind this ordering goes like this: You often want
to set up variables for use in other statements, so 'define' comes
first. The very next thing to do is decide whether this element
will be included at all, so 'condition' is next; since the
condition may depend on variables you just set, it comes after
'define'. It is valuable be able to replace various parts of an
element with different values on each iteration of a repeat, so
'repeat' is next. It makes no sense to replace attributes and
then throw them away, so 'attributes' is last. The remaining
statements clash, because they each replace or edit the statement
element.
See Also
"TALES Overview":tales.stx
"METAL Overview":metal.stx
"tal:attributes":tal-attributes.stx
"tal:define":tal-define.stx
"tal:condition":tal-condition.stx
"tal:content":tal-content.stx
"tal:omit-tag":tal-omit-tag.stx
"tal:on-error":tal-on-error.stx
"tal:repeat":tal-repeat.stx
"tal:replace":tal-replace.stx
TALES Exists expressions
Syntax
Exists expression syntax::
exists_expressions ::= 'exists:' path_expression
Description
Exists expressions test for the existence of paths. An exists
expression returns true when the path expressions following it
expression returns a value. It is false when the path expression
cannot locate an object.
Examples
Testing for the existence of a form variable::
<p tal:condition="not:exists:request/form/number">
Please enter a number between 0 and 5
</p>
Note that in this case you can't use the expression,
'not:request/form/number', since that expression will be true if
the 'number' variable exists and is zero.
\ No newline at end of file
TALES Nocall expressions
Syntax
Nocall expression syntax::
nocall_expression ::= 'nocall:' path_expression
Description
Nocall expressions avoid rendering the results of a path
expression.
An ordinary path expression tries to render the object that it
fetches. This means that if the object is a function, Script,
Method, or some other kind of executable thing, then expression
will evaluate to the result of calling the object. This is
usually what you want, but not always. For example, if you want
to put a DTML Document into a variable so that you can refer to
its properties, you can't use a normal path expression because it
will render the Document into a string.
Examples
Using nocall to get the properties of a document::
<span tal:define="doc nocall:here/aDoc"
tal:content="string:${doc/getId}: ${doc/title}">
Id: Title</span>
Using nocall expressions on a functions::
<p tal:define="join nocall:modules/string/join">
This example defines a variable 'join' which is bound to the
'string.join' function.
TALES Not expressions
Syntax
Not expression syntax::
not_expression ::= 'not:' expression
Description
Not expression evaluate the expression string (recursively) as a
full expression, and returns the boolean negation of its value. If
the expression supplied does not evaluate to a boolean value,
*not* will issue a warning and *coerce* the expression's value
into a boolean type based on the following rules:
1. the number 0 is *false*
2. numbers > 0 are *true*
3. an empty string or other sequence is *false*
4. a non-empty string or other sequence is *true*
5. a *non-value* (e.g. void, None, Nil, NULL, etc) is *false*
6. all other values are implementation-dependent.
If no expression string is supplied, an error should be generated.
Zope considers all objects not specifically listed above as
*false* (including negative numbers) to be *true*.
Examples
Testing a sequence::
<p tal:condition="not:here/objectIds">
There are no contained objects.
</p>
TALES Path expressions
Syntax
Path expression syntax::
PathExpr ::= Path [ '|' Path ]*
Path ::= variable [ '/' URL_Segment ]*
variable ::= Name
Description
A path expression consists of one or more *paths* separated by
vertical bars (|). A path consists of one or more non-empty
strings separated by slashes. The first string must be a variable
name (built-in variable or a user defined variable), and the
remaining strings, the *path segments*, may contain letters,
digits, spaces, and the punctuation characters underscore, dash,
period, comma, and tilde.
For example::
request/cookies/oatmeal
nothing
here/some-file 2001_02.html.tar.gz/foo
root/to/branch | default
request/name | string:Anonymous Coward
When a path expression is evaluated, Zope attempts to traverse the
path, from left to right, until it succeeds or runs out of paths
segments. To traverse a path, it first fetches the object stored
in the variable. For each path segment, it traverses from the
current object to the subobject named by the path
segment. Subobjects are located according to standard Zope
traversal rules (via getattr, getitem, or traversal hooks).
Once a path has been successfully traversed, the resulting object
is the value of the expression. If it is a callable object, such
as a method or template, it is called.
If a traversal step fails, evaluation immediately proceeds to the next
path. If there are no further paths, an error results.
The expression in a series of paths seperated by vertical bars can
be any TALES expression. For example, 'request/name |
string:Anonymous Coward'. This is useful chiefly for providing
default values such as strings and numbers which are not
expressable as path expressions.
If no path is given the result is *nothing*.
Since every path must start with a variable name, you need a set
of starting variables that you can use to find other objects and
values. See the "TALES overview":tales.stx for a list of
built-in variables. Since variable names are looked up first in
locals, then in globals, then in this list, these names act just
like built-ins in Python; They are always available, but they can
be shadowed by a global or local variable declaration. You can
always access the built-in names explicitly by prefixing them with
*CONTEXTS*. (e.g. CONTEXTS/root, CONTEXTS/nothing, etc).
Examples
Inserting a cookie variable or a property::
<span tal:replace="request/cookies/pref | here/pref">
preference
</span>
Inserting the user name::
<p tal:content="user/getUserName">
User name
</p>
TALES Python expressions
Syntax
Python expression syntax::
Any valid Python language expression
Description
Python expressions evaluate Python code in a security-restricted
environment. Python expressions offer the same facilities as those
available in Python-based Scripts and DTML variable expressions.
Security Restrictions
Python expressions are subject to the same security restrictions
as Python-based scripts. These restrictions include:
access limits -- Python expressions are subject to Zope
permission and role security restrictions. In addition,
expressions cannot access objects whose names begin with
underscore.
write limits -- Python expressions cannot change attributes of
Zope objects.
Despite these limits malicious Python expressions can cause
problems. See The Zope Book for more information.
Built-in Functions
Python expressions have the same built-ins as Python-based
Scripts with a few additions.
These standard Python built-ins are available: 'None', 'abs',
'apply', 'callable', 'chr', 'cmp', 'complex', 'delattr',
'divmod', 'filter', 'float', 'getattr', 'hash', 'hex', 'int',
'isinstance', 'issubclass', 'list', 'len', 'long', 'map', 'max',
'min', 'oct', 'ord', 'repr', 'round', 'setattr', 'str', 'tuple'.
The 'range' and 'pow' functions are available and work the same
way they do in standard Python; however, they are limited to
keep them from generating very large numbers and sequences. This
limitation helps protect against denial of service attacks.
Finally, these functions are available in Python expressions,
but not in Python-based scripts:
'path(string)' -- Evaluate a TALES "path":tales-path.stx
expression.
'string(string)' -- Evaluate a TALES "string":tales-string.stx
expression.
'exists(string)' -- Evaluates a TALES "exists":tales-exists.stx
expression.
'nocall(string)' -- Evaluates a TALES "nocall":tales-nocall.stx
expression.
Python Modules
A number of Python modules are available by default. You can
make more modules available. You can access modules either via
path expressions (for example 'modules/string/join') or in
Python with the 'modules' mapping object (for example
'modules["string"].join'). Here are the default modules:
'string' -- The standard "Python string
module":http://www.python.org/doc/current/lib/module-string.html. Note:
most of the functions in the module are also available as
methods on string objects.
'random' -- The standard "Python random
module":http://www.python.org/doc/current/lib/module-random.html.
'math' -- The standard "Python math
module":http://www.python.org/doc/current/lib/module-math.html.
Examples
Using a module usage (pick a random choice from a list)::
<span tal:replace="python:modules['random'].choice(['one',
'two', 'three', 'four', 'five'])">
a random number between one and five
</span>
String processing (capitalize the user name)::
<p tal:content="python:user.getUserName().capitalize()">
User Name
</p>
Basic math (convert an image size to megabytes)::
<p tal:content="python:image.getSize() / 1048576.0">
12.2323
</p>
String formatting (format a float to two decimal places)::
<p tal:content="python:'%0.2f' % size">
13.56
</p>
TALES String expressions
Syntax
String expression syntax::
string_expression ::= ( plain_string | [ varsub ] )*
varsub ::= ( '$' Path ) | ( '${' Path '}' )
plain_string ::= ( '$$' | non_dollar )*
non_dollar ::= any character except '$'
Description
String expressions interpret the expression string as text. If no
expression string is supplied the resulting string is *empty*. The
string can contain variable substitutions of the form '$name' or
'${path}', where 'name' is a variable name, and 'path' is a
"path expression":tales-path.stx.
The escaped string value of the path expression is inserted into
the string. To prevent a '$' from being interpreted this way, it
must be escaped as '$$'.
Examples
Basic string formatting::
<span tal:replace="string:$this and $that">
Spam and Eggs
</span>
Using paths::
<p tal:content="total: ${request/form/total}">
total: 12
</p>
Including a dollar sign::
<p tal:content="cost: $$$cost">
cost: $42.00
</p>
TALES Overview
The *Template Attribute Language Expression Syntax* (TALES) standard
describes expressions that supply "TAL":tal.stx and
"METAL":metal.stx with data. TALES is *one* possible expression
syntax for these languages, but they are not bound to this
definition. Similarly, TALES could be used in a context having
nothing to do with TAL or METAL.
TALES expressions are described below with any delimiter or quote
markup from higher language layers removed. Here is the basic
definition of TALES syntax::
Expression ::= [type_prefix ':'] String
type_prefix ::= Name
Here are some simple examples::
a/b/c
path:a/b/c
nothing
path:nothing
python: 1 + 2
string:Hello, ${user/getUserName}
The optional *type prefix* determines the semantics and syntax of
the *expression string* that follows it. A given implementation of
TALES can define any number of expression types, with whatever
syntax you like. It also determines which expression type is
indicated by omitting the prefix.
If you do not specify a prefix, Zope assumes that the expression is
a *path* expression.
TALES Expression Types
These are the TALES expression types supported by Zope:
* "path":tales-path.stx expressions - locate a value by its path.
* "exists":tales-exists.stx expressions - test whether a path is valid.
* "nocall":tales-nocall.stx expressions - locate an object by its path.
* "not":tales-not.stx expressions - negate an expression
* "string":tales-string.stx expressions - format a string
* "python":tales-python.stx expressions - execute a Python
expression
Built-in Names
These are the names that always available to TALES expressions in Zope:
- *nothing* - special value used by to represent
a *non-value* (e.g. void, None, Nil, NULL).
- *default* - special value used to specify that
existing text should not be replaced. See the documentation for
individual TAL statements for details on how they interpret
*default*.
- *options* - the *keyword* arguments passed to the template. These
are generally available when a template is called from Methods
and Scripts, rather than from the web.
- *repeat* - the 'repeat' variables; see the
"tal:repeat":tal-repeat.stx documentation.
- *attrs* - a dictionary containing the initial values of the
attributes of the current statement tag.
- *CONTEXTS* - the list of standard names (this list). This can be
used to access a built-in variable that has been hidden by a local
or global variable with the same name.
- *root* - the system's top-most object: the Zope root folder.
- *here* - the object to which the template is being applied.
- *container* - The folder in which the template is located.
- *template* - the template itself.
- *request* - the publishing request object.
- *user* - the authenticated user object.
- *modules* - a collection through which Python modules and
packages can be accessed. Only modules which are approved by
the Zope security policy can be accessed.
Note the names 'root', 'here', 'container', 'template', 'request',
'user', and 'modules' are optional names supported by Zope, but
are not required by the TALES standard.
See Also
"TAL Overview":tal.stx
"METAL Overview":metal.stx
"exists":tales-exists.stx expressions
"nocall":tales-nocall.stx expressions
"not":tales-not.stx expressions
"string":tales-string.stx expressions
"path":tales-path.stx expressions
"python":tales-python.stx expressions
...@@ -36,9 +36,6 @@ def initialize(context): ...@@ -36,9 +36,6 @@ def initialize(context):
SessionDataManager.constructSessionDataManager) SessionDataManager.constructSessionDataManager)
) )
context.registerHelp()
context.registerHelpTitle("Zope Help")
# do module security declarations so folks can use some of the # do module security declarations so folks can use some of the
# module-level stuff in PythonScripts # module-level stuff in PythonScripts
# #
......
Browser Id Manager - Add
A browser id manager is an object which identifies visitors
to your site, even if they don't log in. Browser id managers
are part of the Zope sessioning machinery.
Form options available are:
Id -- you cannot choose an 'id' for your browser id manager.
It must always be "browser_id_manager". Additionally, you cannot
rename a browser id manager. This is required in the current
implementation so that session data managers can find browser
id managers via Zope acquisition. This may be changed in a
later release.
Title -- the browser id manager title.
Browser Id Name -- the cookie name and/or form variable
name used for this browser id manager instance. This will be the
name looked up in the 'cookies' or 'form' REQUEST namespaces
when the browser id manager attempts to find a cookie or form
variable with a browser id in it.
Look for Browser Id In -- choose any of 'Forms and Query Strings',
'URLs', or 'Cookies'. The browser id name/value will be looked
for within these places.
Automatically Encode Zope-Generated URLs With A Browser Id -- if
this is selected, URLs generated by Zope (such as URLs which come
as a result of calling an object's 'absolute_url' method) will be
encoded with a browser name and browser id as the first two
elements of the URL path.
Cookie path -- this is the 'path' element which should be sent
in the session token cookie. For more information, see the
Netscape Cookie specification at
http://home.netscape.com/newsref/std/cookie_spec.html.
Cookie domain -- this is the "domain" element which should be
sent in the browser id cookie. For more information, see
the Netscape Cookie specification at
http://home.netscape.com/newsref/std/cookie_spec.html.
Leaving this form element blank results in no domain element
in the cookie. If you change the cookie domain here, the
value you enter must have at least two dots (as per the cookie
spec).
Cookie lifetime in days -- browser id cookies sent to browsers
will last this many days on a remote system before expiring if
this value is set. If this value is 0, cookies will persist
on client browsers for only as long as the browser is open.
Only send cookie over https -- if this flag is set, only send
cookies to remote browsers if they're communicating with us
over https. The browser id cookie sent under this
circumstance will also have the 'secure' flag set in it, which
the remote browser should interpret as a request to refrain
from sending the cookie back to the server over an insecure
(non-https) connection. NOTE: In the case you wish to share
browser id cookies between https and non-https connections
from the same browser, do not set this flag.
After reviewing and changing these options, click the "Add"
button to instantiate a browser id manager.
You can manage a browser id manager by visiting it in the
management interface.
Instantiating Multiple Browser Id Managers (Optional)
If you've got special needs, you may want to instantiate more than
one browser id manager. In its default configuration, Zope will not
allow you to create a browser id manager if one is installed in the
root or in a place where the new browser id manager can acquire the
original browser id manager via its containment path (for
programmers: the session id manager's class' Zope __replaceable__
property is set to UNIQUE). This means, practically, that if you
wish to have multiple browser id managers, you need to carefully
delete the root browser id manager, then you need to place
additional browser id managers in the most deeply-nested containers
first, working your way out towards the root, finally replacing
the root browser id manager if desired.
See Also
- "Session API":SessionInterfaces.py
Browser Id Manager - Change
Form options available are:
Title -- the browser id manager title.
Browser id name -- the cookie or forms variable name
used for this browser id manager instance. This will be the
name looked up in the namespaces specified by "Look for browser
id name in" (below).
Look for Browser Id In -- choose any of 'Forms and Query Strings',
'URLs', or 'Cookies'. The browser id name/value will be looked
for within these places.
Automatically Encode Zope-Generated URLs With A Browser Id -- if
this is selected, URLs generated by Zope (such as URLs which come
as a result of calling an object's 'absolute_url' method) will be
encoded with a browser name and browser id as the first two
elements of the URL path.
Cookie path -- this is the 'path' element which should be sent
in the session token cookie. For more information, see the
Netscape Cookie specification at
http://home.netscape.com/newsref/std/cookie_spec.html.
Cookie domain -- this is the "domain" element which should be
sent in the browser id cookie. For more information, see
the Netscape Cookie specification at
http://home.netscape.com/newsref/std/cookie_spec.html.
Leaving this form element blank results in no domain element
in the cookie. If you change the cookie domain here, the
value you enter must have at least two dots (as per the cookie
spec).
Cookie lifetime in days -- browser id cookies sent to browsers
will last this many days on a remote system before expiring if
this value is set. If this value is 0, cookies will persist
on client browsers for only as long as the browser is open.
Only send cookie over https -- if this flag is set, only send
cookies to remote browsers if they're communicating with us
over https. The browser id cookie sent under this
circumstance will also have the 'secure' flag set in it, which
the remote browser should interpret as a request to refrain
from sending the cookie back to the server over an insecure
(non-https) connection. NOTE: In the case you wish to share
browser id cookies between https and non-https connections
from the same browser, do not set this flag.
After reviewing and changing these options, click the "Change"
button to change the browser id manager.
See Also
- "Session API":SessionInterfaces.py
Session Data Manager - Add
A Zope Session Data Manager is responsible for maintaining a
relationship between session data objects and Zope browser ids.
It is part of the Zope sessioning machinery. Programmers will
sometimes interact with a session data manager in order to obtain
information about session data.
You can place a session data manager in any Zope container,as
long as a browser id manager object can be acquired from that
container. The session data manager will use the first acquired
object named "browser_id_manager" as a browser id manager.
Choose "Session Data Manager" within the container you wish to
house the session data manager from the "Add" dropdown box in
the Zope management interface.
The session data manager add form displays these options:
id -- choose an id for the session data manager
title -- choose a title for the session data manager
transient object container path --
the path in Zope to a transient object container which will
store the actual session data. This path is
/temp_folder/transient_container in a default Zope installation.
place SESSION in REQUEST as --
If set, the REQUEST variable will be populated with the session
object, stored as the given name (default is 'SESSION')
After reviewing and changing these options, click the "Add"
button to instantiate a session data manager.
You can manage a session data manager by visiting it in the
management interface. You may change all options available
during the add process by doing this.
See Also
- "Session API":SessionInterfaces.py
Session Data Manager - Change
The session data manager add form displays these options:
title -- choose a title for the session data manager
transient object container path --
the path in Zope to a transient object container which will
store the actual session data. This path is
/temp_folder/transient_container in a default Zope installation.
place SESSION in REQUEST as --
If set, the REQUEST variable will be populated with the session
object, stored as the given name (default is 'SESSION')
After reviewing and changing these options, click the "Change"
button to change the session data manager.
See Also
- "Session API":SessionInterfaces.py
...@@ -18,5 +18,3 @@ def initialize(context): ...@@ -18,5 +18,3 @@ def initialize(context):
permission='Add Virtual Host Monsters', permission='Add Virtual Host Monsters',
constructors=VirtualHostMonster.constructors, constructors=VirtualHostMonster.constructors,
icon='www/VirtualHostMonster.gif') icon='www/VirtualHostMonster.gif')
context.registerHelp()
SiteRoot - Edit: Edit SiteRoot parameters
Description
This view displays the SiteRoot parameters and allows you to
change them.
Information
'Title' -- The optional title.
'Base' -- Replacement for base of URLs. If you do not want to replace this
portion of URLs, leave it blank.
'Path' -- Replacement for the URL path to the SiteRoot's container. If you
do not want to replace this portion of URLs, leave it blank.
Controls
'Change' -- Changes the parameters.
...@@ -31,6 +31,3 @@ def initialize(context): ...@@ -31,6 +31,3 @@ def initialize(context):
TemporaryFolder.constructTemporaryFolder), TemporaryFolder.constructTemporaryFolder),
visibility=0 # dont show this in the add list for 2.7+ (use dbtab) visibility=0 # dont show this in the add list for 2.7+ (use dbtab)
) )
context.registerHelp()
context.registerHelpTitle('Zope Help')
Temporary Folders
Overview
Temporary Folders are Folders which store their contents
"in-memory", in much the same way as a RAM disk. The contents
of a Temporary Folder are lost upon shutdown.
Creating
By default, Zope will create a Temporary Folder named "temp_folder" in
the root of every Zope installation. This Temporary Folder will
be used by the Zope Sessions machinery, but it may be used for
other purposes as well.
You may create additional Temporary Folders. Creating a Temporary
Folder is fairly straightfoward; they are created in the same way
as a "regular" Folder through the Zope management interface:
- Specify an id (a name) for the folder
- Specify an optional title for the folder
Usage
Once created, a Temporary Folder acts just like regular Folder
object with the exception that the items which it contains will be
lost upon Zope shutdown and restart.
Since Temporary Folders use RAM to store data, it is advised to
add items to a Temporary Folder sparingly. The capacity of a
Temporary Folder is limited by available RAM.
Interaction with ZEO
Temporary Folders exist local to the Zope server. Thus, each
server in a ZEO cluster would have their own private copy of data
in a Temporary Folder. Only temporary data that should be local
to a specific Zope instance should go into a Temporary Folder.
Items which need to be shared between Zope servers in a ZEO
cluster should not be placed in Temporary Folders.
...@@ -29,5 +29,3 @@ def initialize(context): ...@@ -29,5 +29,3 @@ def initialize(context):
constructors=(Transience.constructTransientObjectContainerForm, constructors=(Transience.constructTransientObjectContainerForm,
Transience.constructTransientObjectContainer) Transience.constructTransientObjectContainer)
) )
context.registerHelp()
context.registerHelpTitle('Zope Help')
TransientObjectContainer - Add
Transient Object Containers
A Transient Object Container contains objects which expire after
a user-settable period of time. Items placed into transient object
must have string keys, but may have any type of value.
Common Usages
A Transient Object Container is used by Session Data Managers to store
session data.
To create a Transient Object Container, specify the following:
- **Id**
The Zope id of the Transient Object Container.
- **Title**
*Optional*
The title of the object.
- **Data object timeout (in minutes)**
The minimum number of minutes that objects in the container will
persist for. Objects in the container are passively deleted, so
they may not be deleted exactly after this number of minutes elapses.
A setting of "0" indicates that objects should not expire.
- **Timeout resolution (in seconds)**
Defines what the "resolution" of item timeout is. Setting this
higher allows the transience machinery to do fewer "writes" at
the expense of causing items to time out later than the "Data
object timeout value" by a factor of (at most) this many
seconds. This number must divide evenly into the number of
timeout seconds ("Data object timeout value" * 60) and cannot
be set higher than the timeout value in seconds.
- **Maximum number of subobjects **
The maximum number of subobjects that this container may
simultaneously hold. Since transient objects normally hold
session data, this number is this is the effective limit for
the number of simultaneous sessions.
If the value is "0", the number of objects addable to the container
will be not be artificially limited.
Note: This setting is useful to prevent accidental or deliberate denial
of service due to RAM shortage if the transient object container is
instantiated in a storage which is backed solely by RAM, such
as a Temporary Folder.
- **Script to call when objects are added**
*Optional*
The physical path of of a Zope script which will receive notifications
when objects are added to the Transient Object Container.
Ex: '/path/to/add/script'.
For more information, see "Add and Delete Scripts" below.
- **Script to call when objects are deleted**
*Optional*
The physical path of a Zope script which will receive notifications
when objects are deleted from the Transient Object Container, either
explicitly or through timeout-related expiration.
Ex: '/path/to/delete/script'
For more information, see "Add and Delete Scripts" below.
Add and Delete Scripts
Add and Delete scripts are Zope scripts which are called,
respectively, when an object is added or removed from a
Transient Object Container. An add or delete script is specified
by naming it by its full Zope object path with slash separators,
e.g. "/path/to/method".
Add and delete scripts are called with two arguments. The first
argument is the item being added or removed from the container;
the second argument is the Transient Object Container itself.
The container will be acquisition wrapped, allowing the
it to be used as a context to reference other Zope objects.
See Also
- "Transience API":TransienceInterfaces.py
TransientObjectContainer - Manage
Transient Object Containers
A Transient Object Container contains objects which expire after
a user-settable period of time. Items placed into transient object
must have string keys, but may have any type of value.
Common Usages
A Transient Object Container is used by Session Data Mangers to store
session data.
Editing Form
- **Id**
The Zope id of the Transient Object Container.
- **Title**
*Optional*
The title of the object.
- **Data object timeout (in minutes)**
The minimum number of minutes that objects in the container will
persist for. Objects in the container are passively deleted, so
they may not be deleted exactly after this number of minutes elapses.
If you change the timeout value, all objects in the transient
container will be flushed.
If the timeout value is "0", objects will not time out.
- **Timeout resolution (in seconds)**
Defines what the "resolution" of item timeout is. Setting this
higher allows the transience machinery to do fewer "writes" at
the expense of causing items to time out later than the "Data
object timeout value" by a factor of (at most) this many
seconds. This number must divide evenly into the number of
timeout seconds ("Data object timeout value" * 60) and cannot
be set higher than the timeout value in seconds.
- **Maximum number of subobjects **
The maximum number of subobjects that this container may
simultaneously hold. Since transient objects normally hold
session data, this number is this is the effective limit for
the number of simultaneous sessions.
If the value is "0", the number of objects addable to the container
will be not be artificially limited.
This setting is useful to prevent accidental or deliberate denial
of service due to RAM shortage if the transient object container is
instantiated in a storage which is backed solely by RAM, such
as a Temporary Folder.
- **Script to call when objects are added**
*Optional*
The physical path of of a Zope script which will receive notifications
when objects are added to the Transient Object Container.
Ex: '/path/to/add/script'.
For more information, see "Add and Delete Scripts" below.
- **Script to call when objects are deleted**
*Optional*
The physical path of a Zope script which will receive notifications
when objects are deleted from the Transient Object Container, either
explicitly or through timeout-related expiration.
Ex: '/path/to/delete/script'
For more information, see "Add and Delete Scripts" below.
Add and Delete Scripts
Add and Delete scripts are Zope scripts which are called,
respectively, when an object is added or removed from a
Transient Object Container. An add or delete script is specified
by naming it by its full Zope object path with slash separators,
e.g. "/path/to/method".
Add and delete scripts are called with two arguments. The first
argument is the item being added or removed from the container;
the second argument is the Transient Object Container itself.
The container will be acquisition wrapped, allowing the
it to be used as a context to reference other Zope objects.
An example of an External Method used as a delete script::
def deleteScript(item, container):
from logging import getLogger
LOG = getLogger('test')
LOG.info('id: %s' % item.getId())
See Also
- "Transience API":TransienceInterfaces.py
##########################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##########################################################################
"""
Transient Objects
"""
class TransientObjectContainer:
"""
TransientObjectContainers hold transient objects, most often,
session data.
You will rarely have to script a transient object
container. You'll almost always deal with a TransientObject
itself which you'll usually get as 'REQUEST.SESSION'.
"""
def getId(self):
"""
Returns a meaningful unique id for the object.
Permission -- Always available
"""
def get(self, k, default=None):
"""
Return value associated with key k. If value associated with k does
not exist, return default.
Permission -- 'Access Transient Objects'
"""
def has_key(self, k):
"""
Return true if container has value associated with key k, else
return false.
Permission -- 'Access Transient Objects'
"""
def new(self, k):
"""
Creates a new subobject of the type supported by this container
with key "k" and returns it.
If an object already exists in the container with key "k", a
KeyError is raised.
"k" must be a string, else a TypeError is raised.
If the container is 'full', a MaxTransientObjectsExceeded will
be raised.
Permission -- 'Create Transient Objects'
"""
def new_or_existing(self, k):
"""
If an object already exists in the container with key "k", it
is returned.
Otherwiser, create a new subobject of the type supported by this
container with key "k" and return it.
"k" must be a string, else a TypeError is raised.
If the container is 'full', a MaxTransientObjectsExceeded exception
be raised.
Permission -- 'Create Transient Objects'
"""
def setTimeoutMinutes(self, timeout_mins, period=20):
"""
Set the number of minutes of inactivity allowable for subobjects
before they expire (timeout_mins) as well as the 'timeout resolution'
in seconds (period). 'timeout_mins' * 60 must be evenly divisible
by the period. Period must be less than 'timeout_mins' * 60.
Permission -- 'Manage Transient Object Container'
"""
def getTimeoutMinutes(self):
"""
Return the number of minutes allowed for subobject inactivity
before expiration.
Permission -- 'View management screens'
"""
def getPeriodSeconds(self):
"""
Return the 'timeout resolution' in seconds.
Permission -- 'View management screens'
"""
def getAddNotificationTarget(self):
"""
Returns the current 'after add' function, or None.
Permission -- 'View management screens'
"""
def setAddNotificationTarget(self, f):
"""
Cause the 'after add' function to be 'f'.
If 'f' is not callable and is a string, treat it as a Zope path to
a callable function.
'after add' functions need accept a single argument: 'item', which
is the item being added to the container.
Permission -- 'Manage Transient Object Container'
"""
def getDelNotificationTarget(self):
"""
Returns the current 'before destruction' function, or None.
Permission -- 'View management screens'
"""
def setDelNotificationTarget(self, f):
"""
Cause the 'before destruction' function to be 'f'.
If 'f' is not callable and is a string, treat it as a Zope path to
a callable function.
'before destruction' functions need accept a single argument: 'item',
which is the item being destroyed.
Permission -- 'Manage Transient Object Container'
"""
class TransientObject:
"""
A transient object is a temporary object contained in a transient
object container.
Most of the time you'll simply treat a transient object as a
dictionary. You can use Python sub-item notation::
SESSION['foo']=1
foo=SESSION['foo']
del SESSION['foo']
When using a transient object from Python-based Scripts or DTML
you can use the 'get', 'set', and 'delete' methods instead.
Methods of transient objects are not protected by security
assertions.
It's necessary to reassign mutuable sub-items when you change
them. For example::
l=SESSION['myList']
l.append('spam')
SESSION['myList']=l
This is necessary in order to save your changes. Note that this caveat
is true even for mutable subitems which inherit from the
Persistence.Persistent class.
"""
def getId(self):
"""
Returns a meaningful unique id for the object.
Permission -- Always available
"""
def getContainerKey(self):
"""
Returns the key under which the object is "filed" in its container.
getContainerKey will often return a differnt value than the value
returned by getId.
Permission -- Always available
"""
def invalidate(self):
"""
Invalidate (expire) the transient object.
Causes the transient object container's "before destruct" method
related to this object to be called as a side effect.
Permission -- Always available
"""
def getLastAccessed(self):
"""
Return the time the transient object was last accessed in
integer seconds-since-the-epoch form.
Permission -- Always available
"""
def setLastAccessed(self):
"""
Cause the last accessed time to be set to now.
Permission -- Always available
"""
def getCreated(self):
"""
Return the time the transient object was created in integer
seconds-since-the-epoch form.
Permission -- Always available
"""
def keys(self):
"""
Return sequence of key elements.
Permission -- Always available
"""
def values(self):
"""
Return sequence of value elements.
Permission -- Always available
"""
def items(self):
"""
Return sequence of (key, value) elements.
Permission -- Always available
"""
def get(self, k, default='marker'):
"""
Return value associated with key k. If k does not exist and default
is not marker, return default, else raise KeyError.
Permission -- Always available
"""
def has_key(self, k):
"""
Return true if item referenced by key k exists.
Permission -- Always available
"""
def clear(self):
"""
Remove all key/value pairs.
Permission -- Always available
"""
def update(self, d):
"""
Merge dictionary d into ourselves.
Permission -- Always available
"""
def set(self, k, v):
"""
Call __setitem__ with key k, value v.
Permission -- Always available
"""
def delete(self, k):
"""
Call __delitem__ with key k.
Permission -- Always available
"""
class MaxTransientObjectsExceeded:
"""
An exception importable from the Products.Transience.Transience module
which is raised when an attempt is made to add an item to a
TransientObjectContainer that is 'full'.
This exception may be caught in PythonScripts through a normal import.
A successful import of the exception can be achieved via::
from Products.Transience import MaxTransientObjectsExceeded
"""
...@@ -119,14 +119,6 @@ def _apply_patches(): ...@@ -119,14 +119,6 @@ def _apply_patches():
def null_initialize(app): pass def null_initialize(app): pass
OFS.Application.initialize = null_initialize OFS.Application.initialize = null_initialize
# Avoid expensive help registration
def null_register_topic(self,id,topic): pass
App.ProductContext.ProductContext.registerHelpTopic = null_register_topic
def null_register_title(self,title): pass
App.ProductContext.ProductContext.registerHelpTitle = null_register_title
def null_register_help(self,directory='',clear=1,title_re=None): pass
App.ProductContext.ProductContext.registerHelp = null_register_help
# Avoid loading any ZCML # Avoid loading any ZCML
from Zope2.App import startup as zopeapp_startup from Zope2.App import startup as zopeapp_startup
def null_load_zcml(): pass def null_load_zcml(): pass
......
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