summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 4456211)
raw | patch | inline | side by side (parent: 4456211)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 9 Sep 2002 00:45:06 +0000 (00:45 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 9 Sep 2002 00:45:06 +0000 (00:45 +0000) |
Simplified the "klass", "item" and "*classname*" variables into "context.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1092 57a73879-2fb5-44c3-a270-3262357dd7e2
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1092 57a73879-2fb5-44c3-a270-3262357dd7e2
13 files changed:
diff --git a/TODO.txt b/TODO.txt
index 91ab4481a266f6ec209ada6e884a30bff4d796d4..014f1eb95d9616970729be4dc0970b7fe8943794 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
in a class
bug: request.url is incorrect in cgi-bin environments
-
+bug: query editing not translated to new templating
done web: Re-enable link backrefs from messages (feature request #568714)
done web: have the page layout (header/footer) be templatable
diff --git a/doc/customizing.txt b/doc/customizing.txt
index 7a1279ca5d7836e2085ce32c93942251a797bff4..6a8b28b4d9853ed389dc5f8e0540fc430721227e 100644 (file)
--- a/doc/customizing.txt
+++ b/doc/customizing.txt
Customising Roundup
===================
-:Version: $Revision: 1.19 $
+:Version: $Revision: 1.20 $
.. This document borrows from the ZopeBook section on ZPT. The original is at:
http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
the access through its main() method. This means that you can do pretty much
anything you want as a web interface to your instance.
+Figuring out what is displayed
+::::::::::::::::::::::::::::::
+
Most customisation of the web view can be done by modifying the templates in
the instance **html** directory. There are several types of files in there:
style.css
a static file that is served up as-is
+How requests are processed
+::::::::::::::::::::::::::
+
The basic processing of a web request proceeds as follows:
1. figure out who we are, defaulting to the "anonymous" user
- NotFound (raised wherever it needs to be)
this exception percolates up to the CGI interface that called the client
+Determining web context
+:::::::::::::::::::::::
+
To determine the "context" of a request, we look at the URL and the special
request variable ``:template``. The URL path after the instance identifier
is examined. Typical URL paths look like:
- only classname suplied: "index"
- full item designator supplied: "item"
-Actions are triggered by using a ``:action`` CGI variable, where the value is
-one of:
+
+Performing actions in web requests
+::::::::::::::::::::::::::::::::::
+
+When a user requests a web page, they may optionally also request for an
+action to take place. As described in `how requests are processed`_, the
+action is performed before the requested page is generated. Actions are
+triggered by using a ``:action`` CGI variable, where the value is one of:
login
Attempt to log a user in.
equivalent to ``item/status/checklist``, assuming that ``checklist`` is
a method.
+Information available to templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following variables are available to templates.
+
+.. taken from roundup.cgi.templating.RoundupPageTemplate docstring
+
+*context*
+ The current context. This is either None, a wrapper around a
+ hyperdb class (an HTMLClass) or a wrapper around a hyperdb item (an
+ HTMLItem).
+*request*
+ Includes information about the current request, including:
+ - the url
+ - the current index information (``filterspec``, ``filter`` args,
+ ``properties``, etc) parsed out of the form.
+ - methods for easy filterspec link generation
+ - *user*, the current user node as an HTMLItem instance
+ - *form*
+ The current CGI form information as a mapping of form argument
+ name to value
+*instance*
+ The current instance
+*db*
+ The current database, through which db.config may be reached.
+
+The context variable
+::::::::::::::::::
+
+The *context* variable is one of three things based on the current context
+(see `determining web context`_ for how we figure this out):
+
+1. if we're looking at a "home" page, then it's None
+2. if we're looking at a specific hyperdb class, it's an HTMLClass instance
+3. if we're looking at a specific hyperdb item, it's an HTMLItem instance
+
+If the context is not None, we can access the properties of the class or item.
+The only real difference between cases 2 and 3 above are:
+
+1. the properties may have a real value behind them, and this will appear if
+ the property is displayed through ``context/property`` or
+ ``context/property/field``.
+2. the context's "id" property will be a false value in the second case, but
+ a real, or true value in the third. Thus we can determine whether we're
+ looking at a real item from the hyperdb by testing "context/id".
+
+
+The request variable
+::::::::::::::::::::
+
+The request variable is packed with information about the current request.
+
+.. taken from roundup.cgi.templating.HTMLRequest docstring
+
+=========== ================================================================
+Variable Holds
+=========== ================================================================
+form the CGI form as a cgi.FieldStorage
+env the CGI environment variables
+url the current URL path for this request
+base the base URL for this instance
+user a HTMLUser instance for this user
+classname the current classname (possibly None)
+template the current template (suffix, also possibly None)
+form the current CGI form variables in a FieldStorage
+**Index page specific variables (indexing arguments)**
+columns dictionary of the columns to display in an index page
+show a convenience access to columns - request/show/colname will
+ be true if the columns should be displayed, false otherwise
+sort index sort column (direction, column name)
+group index grouping property (direction, column name)
+filter properties to filter the index on
+filterspec values to filter the index on
+search_text text to perform a full-text search on for an index
+----------- ----------------------------------------------------------------
+
+
Displaying Properties
~~~~~~~~~~~~~~~~~~~~~
added for clarity)::
/issue?status=unread,in-progress,resolved&
- topic=security,ui&
- :group=+priority&
- :sort=-activity&
- :filters=status,topic&
- :columns=title,status,fixer
+ topic=security,ui&
+ :group=+priority&
+ :sort=-activity&
+ :filters=status,topic&
+ :columns=title,status,fixer
The index view is determined by two parts of the specifier: the layout part and
the filter part. The layout part consists of the query parameters that begin
@@ -958,10 +1050,6 @@ by activity, arranged in descending order. The filter section shows filters for
the "status" and "topic" properties, and the table includes columns for the
"title", "status", and "fixer" properties.
-Associated with each item class is a default layout specifier. The layout
-specifier in the above example is the default layout to be provided with the
-default bug-tracker schema described above in section 4.4.
-
Filtering of indexes
::::::::::::::::::::
diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py
index 58a9cffb3036ad473c85d40d15ec1cde79678148..3dac1330a7154c5e64bae6a45c7ff9c890629a11 100644 (file)
--- a/roundup/cgi/client.py
+++ b/roundup/cgi/client.py
-# $Id: client.py,v 1.20 2002-09-06 22:54:51 richard Exp $
+# $Id: client.py,v 1.21 2002-09-09 00:45:06 richard Exp $
__doc__ = """
WWW request handler (also used in the stand-alone server).
must be supplied or a ValueError will be raised.
'''
required = []
- print form.keys()
if form.has_key(':required'):
value = form[':required']
- print 'required', value
if isinstance(value, type([])):
required = [i.value.strip() for i in value]
else:
index 64f871614e8173f090048b6aec8d09c15a6f7cfc..d8a4f69fcd8e21649c51dd2a6bf035115ebe0686 100644 (file)
Interrogate the client to set up the various template variables to
be available:
- *class*
- The current class of node being displayed as an HTMLClass
- instance.
- *item*
- The current node from the database, if we're viewing a specific
- node, as an HTMLItem instance. If it doesn't exist, then we're
- on a new item page.
- (*classname*)
- this is one of two things:
-
- 1. the *item* is also available under its classname, so a *user*
- node would also be available under the name *user*. This is
- also an HTMLItem instance.
- 2. if there's no *item* then the current class is available
- through this name, thus "user/name" and "user/name/menu" will
- still work - the latter will pull information from the form
- if it can.
- *form*
- The current CGI form information as a mapping of form argument
- name to value
+ *context*
+ this is one of three things:
+ 1. None - we're viewing a "home" page
+ 2. The current class of item being displayed. This is an HTMLClass
+ instance.
+ 3. The current item from the database, if we're viewing a specific
+ item, as an HTMLItem instance.
*request*
Includes information about the current request, including:
- the url
``properties``, etc) parsed out of the form.
- methods for easy filterspec link generation
- *user*, the current user node as an HTMLItem instance
+ - *form*, the current CGI form information as a FieldStorage
*instance*
The current instance
*db*
The current database, through which db.config may be reached.
-
- Maybe also:
-
- *modules*
- python modules made available (XXX: not sure what's actually in
- there tho)
'''
def getContext(self, client, classname, request):
c = {
- 'klass': HTMLClass(client, classname),
'options': {},
'nothing': None,
'request': request,
}
# add in the item if there is one
if client.nodeid:
- c['item'] = HTMLItem(client, classname, client.nodeid)
- c[classname] = c['item']
+ c['context'] = HTMLItem(client, classname, client.nodeid)
else:
- c[classname] = c['klass']
+ c['context'] = HTMLClass(client, classname)
return c
def render(self, client, classname, request, **options):
''' return an HTMLProperty instance
'''
#print 'getitem', (self, item)
+
+ # we don't exist
+ if item == 'id':
+ return None
if item == 'creator':
- return HTMLUser(self.client, 'user', client.userid)
+ # but we will be created by this user...
+ return HTMLUser(self.client, 'user', self.client.userid)
- if not self.props.has_key(item):
- raise KeyError, item
+ # get the property
prop = self.props[item]
# look up the correct HTMLProperty class
#print 'getitem', (self, item)
if item == 'id':
return self.nodeid
- if not self.props.has_key(item):
- raise KeyError, item
+
+ # get the property
prop = self.props[item]
# get the value, handling missing values
diff --git a/roundup/templates/classic/html/_generic.index b/roundup/templates/classic/html/_generic.index
index 298a28292dd9210a65ffea51d83a3d1ce6d5383e..951dafdcd1140ddde491ddba27af0b2da0018a49 100644 (file)
</p>
<form onSubmit="return submit_once()" method="POST">
-<textarea rows="15" cols="60" name="rows" tal:content="klass/csv"></textarea>
+<textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea>
<br>
<input type="hidden" name=":action" value="editCSV">
<input type="submit" value="Edit Items">
index fcbca1f00c65b845181c654e34f067cbdf3c194b..689e207fcbdd7b755908d9bc6d0d2a928d6bdcff 100644 (file)
<!-- dollarId: file.index,v 1.4 2002/01/23 05:10:27 richard Exp dollar-->
-<tr tal:repeat="file class/list">
+<tr tal:repeat="file context/list">
<td tal:condition="display/properties/name">
<a href="" tal:attributes="href string:file${file/id}/${file/name}">dld link</a>
</td>
diff --git a/roundup/templates/classic/html/issue.index b/roundup/templates/classic/html/issue.index
index 74741924d583c0819dd73e4b0016fcfc38a5cf97..a1f41f639eaa0cd66f0102cd387873ef17203fd7 100644 (file)
<td>
<select name=":sort">
<option value="">- nothing -</option>
- <option tal:repeat="col klass/properties"
+ <option tal:repeat="col context/properties"
tal:attributes="value col/name;
selected python:col.name == request.sort[1]"
tal:content="col/name">column</option>
<td>
<select name=":group">
<option value="">- nothing -</option>
- <option tal:repeat="col klass/properties"
+ <option tal:repeat="col context/properties"
tal:attributes="value col/name;
selected python:col.name == request.group[1]"
tal:content="col/name">column</option>
index 7a04bf5f65eda4592621ef97d9be4de11e1de036..70ff043a99f33e9f59c1d503aa82a61ab6838438 100644 (file)
<table border=0 cellspacing=0 cellpadding=2 class="form">
<tr>
<th nowrap>Title</th>
- <td colspan=3 class="form-text" tal:content="structure python:issue.title.field(size=60)">title</td>
+ <td colspan=3 class="form-text" tal:content="structure python:context.title.field(size=60)">title</td>
</tr>
<tr class="form">
<th nowrap>Priority</th>
- <td class="form-text" tal:content="structure issue/priority/menu">priority</td>
+ <td class="form-text" tal:content="structure context/priority/menu">priority</td>
<th nowrap>Status</th>
- <td class="form-text" tal:content="structure issue/status/menu">status</td>
+ <td class="form-text" tal:content="structure context/status/menu">status</td>
</tr>
<tr class="form">
<th nowrap>Superseder</th>
<td>
- <span tal:replace="structure python:issue.superseder.field(showid=1, size=20)" />
+ <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
<span tal:replace="structure python:db.issue.classhelp('id,title', label='list', width=500)" />
- <span tal:condition="issue/superseder">
- <br>View: <span tal:replace="structure python:issue.superseder.link(showid=1)" />
+ <span tal:condition="context/superseder">
+ <br>View: <span tal:replace="structure python:context.superseder.link(showid=1)" />
</span>
</td>
<th nowrap>Nosy List</th>
<td>
- <span tal:replace="structure issue/nosy/field" />
+ <span tal:replace="structure context/nosy/field" />
<span tal:replace="structure python:db.user.classhelp('username,realname,address,phone', label='list', width=500)" />
</td>
</tr>
<tr class="form">
<th nowrap>Assigned To</th>
- <td class="form-text" tal:content="structure issue/assignedto/menu">
+ <td class="form-text" tal:content="structure context/assignedto/menu">
assignedto menu
</td>
<td> </td>
<tr class="form">
<td> </td>
- <td colspan=3 class="form-text" tal:content="structure issue/submit">
+ <td colspan=3 class="form-text" tal:content="structure context/submit">
submit button will go here
</td>
</tr>
</table>
-<span tal:condition="exists:item" tal:content="structure string:Created on <b>${issue/creation}</b> by <b>${issue/creator/username}</b>, last changed <b>${issue/activity}</b>.">activity info</span>
+<span tal:condition="context/id" tal:content="structure string:Created on
+<b>${context/creation}</b> by <b>${context/creator/username}</b>, last
+changed <b>${context/activity}</b>.">activity info</span>
-<tal:block tal:condition="exists:item">
- <table class="messages" tal:condition="issue/messages">
+<tal:block tal:condition="context/id">
+ <table class="messages" tal:condition="context/messages">
<tr><th colspan=2 class="header">Messages</th></tr>
- <tal:block tal:repeat="msg issue/messages/reverse">
+ <tal:block tal:repeat="msg context/messages/reverse">
<tr>
<th tal:content="string:Author: ${msg/author}">author</th>
<th tal:content="string:Date: ${msg/date}">date</th>
</tal:block>
</table>
- <table class="files" tal:condition="issue/files">
+ <table class="files" tal:condition="context/files">
<tr><th colspan="2" class="header">Files</th></tr>
<tr><th>File name</th><th>Uploaded</th></tr>
- <tr tal:repeat="file issue/files">
+ <tr tal:repeat="file context/files">
<td>
<a tal:attributes="href string:file${file/id}/${file/name}"
tal:content="file/name">dld link</a>
<table class="history">
<tr><th colspan="2" class="header">History</th></tr>
- <tr><td colspan="2" tal:content="structure issue/history">history</td></tr>
+ <tr><td colspan="2" tal:content="structure context/history">history</td></tr>
</table>
</tal:block>
index 03fc70b6c3d709851a7c54fea52dce805fb9e34f..f2a834852f6c28beb04a5893b8dbe1b58af0c991 100644 (file)
<table class="messages" tal:condition="request/filter">
<tr><th colspan=2 class="header">Messages</th></tr>
- <tal:block tal:repeat="msg issue/messages/reverse">
+ <tal:block tal:repeat="msg context/list">
<tr>
<th tal:content="string:Author: ${msg/author}">author</th>
<th tal:content="string:Date: ${msg/date}">date</th>
index d1405ed49b44787bd6151b45a2735d0e22839f16..abf69d84c6b5d5642226e91799dc518efb595163 100644 (file)
<tr bgcolor="ffffea">
<td width=1% nowrap align=right><span class="form-label">Author</span></td>
- <td class="form-text" tal:content="msg/author"></td>
+ <td class="form-text" tal:content="context/author"></td>
</tr>
<tr bgcolor="ffffea">
<td width=1% nowrap align=right><span class="form-label">Recipients</span></td>
- <td class="form-text" tal:content="msg/recipients"></td>
+ <td class="form-text" tal:content="context/recipients"></td>
</tr>
<tr bgcolor="ffffea">
<td width=1% nowrap align=right><span class="form-label">Date</span></td>
- <td class="form-text" tal:content="msg/date"></td>
+ <td class="form-text" tal:content="context/date"></td>
</tr>
<tr bgcolor="ffeaff">
<td colspan=2 class="form-text">
- <pre tal:content="msg/content"></pre>
+ <pre tal:content="context/content"></pre>
</td>
</tr>
<property name="files">
<tr class="strong-header"><td colspan=2><b>Files</b></td></tr>
-<tr tal:repeat="file msg/files">
+<tr tal:repeat="file context/files">
<td>
<a tal:attributes="href string:file${file/id}/${file/name}"
tal:content="file/name">dld link</a>
</property>
<tr class="history-header"><td colspan=2><b>History</b></td><tr>
-<tr><td colspan="2" tal:content="structure msg/history">history</td></tr>
+<tr><td colspan="2" tal:content="structure context/history">history</td></tr>
</table>
index 67fbea3b86540c4db9029ac4a060d2eacbf5c482..d553f39d0d6a761dbe6e1c39bb85bd2c66ad0d14 100644 (file)
<th>Email address</th>
<th>Phone number</th>
</tr>
-<tr tal:repeat="u user/list"
- tal:attributes="class python:['row-normal', 'row-alt'][repeat['u'].even()]">
+<tr tal:repeat="user context/list"
+ tal:attributes="class python:['row-normal', 'row-alt'][repeat['user'].even()]">
<td valign="top">
- <a tal:attributes="href string:user${u/id}"
- tal:content="u/username">username</a>
+ <a tal:attributes="href string:user${user/id}"
+ tal:content="user/username">username</a>
</td>
- <td valign="top" tal:content="u/realname">realname</td>
- <td valign="top" tal:content="u/organisation">organisation</td>
- <td valign="top" tal:content="python:u.address.email()">address</td>
- <td valign="top" tal:content="u/phone">phone</td>
+ <td valign="top" tal:content="user/realname">realname</td>
+ <td valign="top" tal:content="user/organisation">organisation</td>
+ <td valign="top" tal:content="python:user.address.email()">address</td>
+ <td valign="top" tal:content="user/phone">phone</td>
</tr>
</table>
index 7e528b86bd22430702c8cf0043ea21f0c39eecba..2968d7886efaa96f7ab76830eebbb50deb78d810 100644 (file)
<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
<tal:block tal:define="
editok python:request.user.hasPermission('Edit') or
- user.id == request.user.id;
+ context.id == request.user.id;
viewok python:request.user.hasPermission('View')">
<span tal:condition="python:not (viewok or editok)">
<table class="form">
<tr>
<th>Name</th>
- <td tal:content="structure user/realname/field">realname</td>
+ <td tal:content="structure context/realname/field">realname</td>
</tr>
<tr>
<th>Login Name</th>
- <td tal:content="structure user/username/field">username</td>
+ <td tal:content="structure context/username/field">username</td>
</tr>
<tr>
<th>Login Password</th>
- <td tal:content="structure user/password/field">password</td>
+ <td tal:content="structure context/password/field">password</td>
</tr>
<tr tal:condition="python:request.user.hasPermission('Web Roles')">
<th>Roles</th>
- <td tal:condition="exists:item"
- tal:content="structure user/roles/field">roles</td>
- <td tal:condition="not:exists:item">
+ <td tal:condition="item/created"
+ tal:content="structure context/roles/field">roles</td>
+ <td tal:condition="not:item/created">
<input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
</td>
</tr>
<tr>
<th>Phone</th>
- <td tal:content="structure user/phone/field">phone</td>
+ <td tal:content="structure context/phone/field">phone</td>
</tr>
<tr>
<th>Organisation</th>
- <td tal:content="structure user/organisation/field">organisation</td>
+ <td tal:content="structure context/organisation/field">organisation</td>
</tr>
<tr>
<th>E-mail address</th>
- <td tal:content="structure user/address/field">address</td>
+ <td tal:content="structure context/address/field">address</td>
</tr>
<tr>
<th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure user/alternate_addresses/multiline">alternate_addresses</td>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
</tr>
<tr>
<td> </td>
- <td tal:content="structure user/submit">submit button here</td>
+ <td tal:content="structure context/submit">submit button here</td>
</tr>
</table>
</form>
-<tal:block tal:condition="exists:item">
- <table class="otherinfo" tal:condition="user/queries">
+<tal:block tal:condition="item/created">
+ <table class="otherinfo" tal:condition="context/queries">
<tr><th class="header">Queries</th></tr>
- <tr tal:repeat="query user/queries">
+ <tr tal:repeat="query context/queries">
<td tal:content="query">query</td>
</tr>
</table>
<table class="otherinfo">
<tr><th class="header">History</th></tr>
<tr>
- <td tal:content="structure user/history">history</td>
+ <td tal:content="structure context/history">history</td>
</tr>
</table>
</tal:block>
<table class="form" tal:condition="python:viewok and not editok">
<tr>
- <th colspan=2 class="header" tal:content="user/realname">realname</th>
+ <th colspan=2 class="header" tal:content="context/realname">realname</th>
</tr>
<tr>
<th>Login Name</th>
- <td tal:content="user/username">username</td>
+ <td tal:content="context/username">username</td>
</tr>
<tr>
<th>Phone</th>
- <td tal:content="user/phone">phone</td>
+ <td tal:content="context/phone">phone</td>
</tr>
<tr>
<th>Organisation</th>
- <td tal:content="user/organisation">organisation</td>
+ <td tal:content="context/organisation">organisation</td>
</tr>
<tr>
<th>E-mail address</th>
- <td tal:content="user/address/email">address</td>
+ <td tal:content="context/address/email">address</td>
</tr>
</table>
diff --git a/roundup/templates/classic/html/user.register b/roundup/templates/classic/html/user.register
index 0b18f8197b85972c3dcf2e2f9657394d417ee230..5033d43cefa157bbb89c63f6e3b6cbe53e86e4b2 100644 (file)
<table class="form">
<tr>
<th>Name</th>
- <td tal:content="structure user/realname/field">realname</td>
+ <td tal:content="structure context/realname/field">realname</td>
</tr>
<tr>
<th>Login Name</th>
- <td tal:content="structure user/username/field">username</td>
+ <td tal:content="structure context/username/field">username</td>
</tr>
<tr>
<th>Login Password</th>
- <td tal:content="structure user/password/field">password</td>
+ <td tal:content="structure context/password/field">password</td>
</tr>
<tr tal:condition="python:request.user.hasPermission('Web Roles')">
<th>Roles</th>
<td tal:condition="exists:item"
- tal:content="structure user/roles/field">roles</td>
+ tal:content="structure context/roles/field">roles</td>
<td tal:condition="not:exists:item">
<input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
</td>
</tr>
<tr>
<th>Phone</th>
- <td tal:content="structure user/phone/field">phone</td>
+ <td tal:content="structure context/phone/field">phone</td>
</tr>
<tr>
<th>Organisation</th>
- <td tal:content="structure user/organisation/field">organisation</td>
+ <td tal:content="structure context/organisation/field">organisation</td>
</tr>
<tr>
<th>E-mail address</th>
- <td tal:content="structure user/address/field">address</td>
+ <td tal:content="structure context/address/field">address</td>
</tr>
<tr>
<th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure user/alternate_addresses/multiline">alternate_addresses</td>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
</tr>
<tr>