[Checkins]
SVN: Sandbox/darrylcousins/tfws.website/src/tfws/website/
Progressing with the site demo
Darryl Cousins
darryl at darrylcousins.net.nz
Mon Jul 23 01:06:33 EDT 2007
Log message for revision 78286:
Progressing with the site demo
Changed:
U Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt
A Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py
U Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py
A Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/formatter.py
U Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/index.pt
A Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/table_sorted_header.pt
A Sandbox/darrylcousins/tfws.website/src/tfws/website/catalog.py
U Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml
U Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py
A Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/ascending.gif
A Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/buttonBG.gif
A Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/decending.gif
U Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py
U Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt
U Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css
-=-
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/BROWSER.txt 2007-07-23 05:06:32 UTC (rev 78286)
@@ -16,6 +16,7 @@
Traceback (most recent call last):
...
HTTPError: HTTP Error 401: Unauthorized
+ >>> user.handleErrors = False
Using our authenticated browser instance we can add a website.
@@ -28,8 +29,15 @@
>>> browser.getControl('Email').value = u'darry.cousins at tfws.org.nz'
>>> browser.getControl('Add').click()
-We can now access the new site with our user.
+The new site is now included in the table of sites available.
- >>> user.handleErrors = False
- >>> browser.open("http://localhost/treefern")
- >>> print browser.contents
+ >>> browser.open("http://localhost/")
+ >>> testing.printElement(browser, "//table/tbody/tr[1]/td/a/text()",
+ ... multiple=True, serialize=False )
+ treefern
+ Grok/Mars/Z3C Demo Site
+
+We can edit the new site.
+
+ >>> #print browser.contents
+ >>> browser.getLink('Grok/Mars/Z3C Demo Site').click()
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -0,0 +1,13 @@
+import zope.interface
+
+from z3c.breadcrumb.browser import Breadcrumbs as Breadcrumbs_
+from z3c.breadcrumb.interfaces import IBreadcrumbs
+
+import grok
+
+class Breadcrumbs(grok.MultiAdapter, Breadcrumbs_):
+ """Breadcrumbs implementation using IBreadcrumb adapters."""
+ grok.name('breadcrumbs')
+ grok.context(zope.interface.Interface)
+ grok.provides(IBreadcrumbs)
+
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/breadcrumb.py
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/browser.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -1,33 +1,96 @@
from zope.traversing.browser import absoluteURL
from zope.app.folder.interfaces import IRootFolder
+from zope.dublincore.interfaces import IZopeDublinCore
+from zope.traversing import api
+from z3c.form import form, field
+
+from zc.table import column
+from zc.table import table
+
import grok
import mars.layer
import mars.view
import mars.template
+from tfws.website import interfaces
+from tfws.website.browser import formatter
from tfws.website.layer import IWebsiteLayer
+from tfws.website.i18n import MessageFactory as _
mars.layer.layer(IWebsiteLayer)
grok.define_permission('tfws.ManageSites')
+class CheckboxColumn(column.Column):
+
+ def renderCell(self, item, formatter):
+ widget = (u'<input type="checkbox" '
+ u'name="selected:list" value="%s">')
+ return widget %api.getName(item)
+
+
+def getCreatedDate(item, formatter):
+ formatter = formatter.request.locale.dates.getFormatter('date', 'short')
+ return formatter.format(IZopeDublinCore(item).created)
+
+
+def getModifiedDate(item, formatter):
+ formatter = formatter.request.locale.dates.getFormatter('date', 'short')
+ return formatter.format(IZopeDublinCore(item).modified)
+
+
+def link(view='index', title=''):
+ def anchor(value, item, formatter):
+ url = absoluteURL(item, formatter.request) + '/' + view
+ return u'<a href="%s" title="%s">%s</a>' %(url, title, value)
+ return anchor
+
+
class Index(mars.view.PageletView):
grok.context(IRootFolder)
grok.require('tfws.ManageSites')
- @property
+ columns = (
+ CheckboxColumn(_('Sel')),
+ column.GetterColumn(_('Id'),
+ lambda item, f: api.getName(item), link('index', _('View'))),
+ column.GetterColumn(_('Title'),
+ lambda item, f: item.title, link('edit', _('Edit'))),
+ column.GetterColumn(_('Created On'), getCreatedDate),
+ column.GetterColumn(_('Modified On'), getModifiedDate),
+ )
+
+ status = None
+
def sites(self):
- for site in self.context:
- print site
+ return [obj
+ for obj in self.context.values()
+ if interfaces.IWebSite.providedBy(obj)]
- @property
- def addurl(self):
- url = absoluteURL(self.context, self.request)
- return url + '/add'
+ def table(self):
+ formatter = table.AlternatingRowFormatter(
+ self.context, self.request, self.sites(), columns=self.columns)
+ formatter.widths=[25, 50, 300, 100, 100]
+ formatter.cssClasses['table'] = 'list'
+ return formatter()
+ def update(self):
+ if 'ADD' in self.request:
+ self.request.response.redirect('add')
+ if 'DELETE' in self.request:
+ if self.request.get('confirm_delete') != 'yes':
+ self.status = _('You did not confirm the deletion correctly.')
+ return
+ if 'selected' in self.request:
+ for id in self.request['selected']:
+ del self.context[id]
+ self.status = _('Sites were successfully deleted.')
+ else:
+ self.status = _('No sites were selected.')
+
class IndexTemplate(mars.template.TemplateFactory):
"""layout template for `home`"""
grok.context(Index)
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/formatter.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/formatter.py (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/formatter.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+#
+##############################################################################
+"""List Formatter Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from xml.sax.saxutils import quoteattr
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.session.interfaces import ISession
+from zc.table import table, column, interfaces
+
+
+class ListFormatter(table.SortingFormatterMixin, table.AlternatingRowFormatter):
+ """Provides a width for each column."""
+
+ sortedHeaderTemplate = ViewPageTemplateFile('table_sorted_header.pt')
+
+ sortKey = 'formdemo.table.sort-on'
+ widths = None
+ columnCSS = None
+
+ def __init__(self, *args, **kw):
+ # Figure out sorting situation
+ kw['ignore_request'] = True
+ request = args[1]
+ prefix = kw.get('prefix')
+ session = ISession(request)[self.sortKey]
+ if 'sort-on' in request:
+ name = request['sort-on']
+ if prefix and name.startswith(prefix):
+ name = name[len(prefix):]
+ oldName, oldReverse = session.get(prefix, (None, None))
+ if oldName == name:
+ session[prefix] = (name, not oldReverse)
+ else:
+ session[prefix] = (name, False)
+ # Now get the sort-on data from the session
+ if prefix in session:
+ kw['sort_on'] = [session[prefix]]
+
+ super(ListFormatter, self).__init__(*args, **kw)
+ self.columnCSS = {}
+
+ self.sortOn = (None, None)
+ if 'sort_on' in kw:
+ for name, reverse in kw['sort_on']:
+ self.columnCSS[name] = 'sorted-on'
+ self.sortOn = kw['sort_on'][0]
+
+ def getHeader(self, column):
+ contents = column.renderHeader(self)
+ if (interfaces.ISortableColumn.providedBy(column)):
+ contents = self._wrapInSortUI(contents, column)
+ return contents
+
+ def _wrapInSortUI(self, header, column):
+ name = column.name
+ if self.prefix:
+ name = self.prefix + name
+ isSortedOn = self.sortOn[0] == column.name
+ isAscending = self.sortOn[0] == column.name and not self.sortOn[1]
+ isDecending = self.sortOn[0] == column.name and self.sortOn[1]
+ return self.sortedHeaderTemplate(
+ header=header, name=name, isSortedOn=isSortedOn,
+ isAscending=isAscending, isDecending=isDecending)
+
+ def renderContents(self):
+ """Avoid to render empty table (tr) rows."""
+ rows = self.renderRows()
+ if not rows:
+ return ' <thead%s>\n%s </thead>\n' % (
+ self._getCSSClass('thead'), self.renderHeaderRow())
+ else:
+ return ' <thead%s>\n%s </thead>\n <tbody>\n%s </tbody>\n' % (
+ self._getCSSClass('thead'), self.renderHeaderRow(),
+ rows)
+
+ def renderHeader(self, column):
+ width = ''
+ if self.widths:
+ idx = list(self.visible_columns).index(column)
+ width = ' width="%i"' %self.widths[idx]
+ klass = self.cssClasses.get('tr', '')
+ if column.name in self.columnCSS:
+ klass += klass and ' ' or '' + self.columnCSS[column.name]
+ return ' <th%s class=%s>\n %s\n </th>\n' % (
+ width, quoteattr(klass), self.getHeader(column))
+
+
+ def renderCell(self, item, column):
+ klass = self.cssClasses.get('tr', '')
+ if column.name in self.columnCSS:
+ klass += klass and ' ' or '' + self.columnCSS[column.name]
+ return ' <td class=%s>\n %s\n </td>\n' % (
+ quoteattr(klass), self.getCell(item, column))
+
+ def renderExtra(self):
+ """Avoid use of resourcelibrary in original class."""
+ return ''
+
+
+class SelectedItemFormatter(ListFormatter):
+
+ selectedItem = None
+
+ def renderRow(self, item):
+ self.row += 1
+ klass = self.cssClasses.get('tr', '')
+ if klass:
+ klass += ' '
+ if item == self.selectedItem:
+ klass += 'selected'
+ else:
+ klass += self.row_classes[self.row % 2]
+
+ return ' <tr class=%s>\n%s </tr>\n' % (
+ quoteattr(klass), self.renderCells(item))
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/formatter.py
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/index.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/index.pt 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/index.pt 2007-07-23 05:06:32 UTC (rev 78286)
@@ -1,11 +1,38 @@
<h1>Tree Fern Web Site Demos</h1>
+<div class="message"
+ tal:condition="view/status"
+ tal:content="view/status"
+ i18n:translate="">
+ Something happened.
+</div>
-<p>
-<a tal:attributes="href view/addurl" title="Add website">Add website</a>
-</p>
-<ul>
- <li tal:repeat="site view/sites">
- <a tal:attributes="href site/url;title site/description|site/title"
- tal:content="site/title">Site</a>
- </li>
-</ul>
+<form action="" method="post"
+ tal:attributes="action request/URL">
+
+ <tal:block
+ condition="view/sites"
+ replace="structure view/table" />
+
+ <div
+ tal:condition="not: view/sites"
+ i18n:translate="">
+ There are no sites.
+ </div>
+
+ <div id="actionsView">
+ <span class="actionButtons">
+ <input type="submit" class="button" name="ADD" value="Add"
+ i18n:attributes="value" />
+ <tal:block condition="view/sites">
+ <input type="submit" class="button" name="DELETE" value="Delete"
+ i18n:attributes="value" />
+ <input type="text" id="confirm_delete" name="confirm_delete"
+ size="5" />
+ <label for="confirm_delete" i18n:translate="">
+ (Type "yes" to delete.)
+ </label>
+ </tal:block>
+ </span>
+ </div>
+
+</form>
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/table_sorted_header.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/table_sorted_header.pt (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/browser/table_sorted_header.pt 2007-07-23 05:06:32 UTC (rev 78286)
@@ -0,0 +1,19 @@
+<html tal:omit-tag="">
+ <a href=""
+ tal:attributes="href string:${request/URL}?sort-on=${options/name}"
+ tal:content="options/header" />
+ <span tal:condition="options/isSortedOn">
+
+ </span>
+ <img src="" width="7" height="4" style="vertical-align: middle"
+ alt="sort ascending"
+ tal:condition="options/isAscending"
+ tal:attributes="src
+ context/++resource++images/ascending.gif" />
+ <img src="" width="7" height="4" style="vertical-align: middle"
+ alt="sort ascending"
+ tal:condition="options/isDecending"
+ tal:attributes="src
+ context/++resource++images/decending.gif" />
+</html>
+
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/catalog.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/catalog.py (rev 0)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/catalog.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -0,0 +1,38 @@
+import zope.interface
+from zope.index.text import textindex
+from zope.dublincore.interfaces import IZopeDublinCore
+from zope.app.catalog.text import ITextIndex
+from zope.app.container import contained
+
+from zc.catalog import catalogindex
+
+from tfws.website import interfaces
+
+class TextIndex(textindex.TextIndex, contained.Contained):
+
+ # not really true but needed by query.Text
+ zope.interface.implements(ITextIndex)
+
+ def index_doc(self, docid, obj):
+ text = ''
+ if interfaces.IContent.providedBy(obj):
+ text += obj.title + ' '
+ text += obj.description + ' '
+ text += obj.keyword + ' '
+ text += obj.body
+ return super(TextIndex, self).index_doc(docid, text)
+
+ def __repr__(self):
+ return '<%s for IFeed>' %self.__class__.__name__
+
+
+def setup_catalog(catalog):
+ """Configure catalog for the site."""
+
+ # Feed text index
+ catalog['text'] = TextIndex()
+
+ # Dublin Core Indices
+ catalog['creator'] = catalogindex.SetIndex('creators', IZopeDublinCore)
+ catalog['created'] = catalogindex.DateTimeValueIndex(
+ 'created', IZopeDublinCore)
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/catalog.py
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/configure.zcml 2007-07-23 05:06:32 UTC (rev 78286)
@@ -7,6 +7,7 @@
<!-- extra package includes, check grok configure first -->
<include package="zope.contentprovider" />
+ <include package="zope.app.session" />
<include package="zope.viewlet" file="meta.zcml" />
@@ -17,6 +18,7 @@
<include package="z3c.zrtresource" file="meta.zcml" />
<include package="zc.resourcelibrary" file="meta.zcml" />
+ <include package="z3c.breadcrumb" />
<include package="z3c.form" />
<include package="z3c.formui" />
<include package="z3c.layer.pagelet" />
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/site.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -24,7 +24,7 @@
from z3c.authentication.simple.principal import PrincipalBase
from z3c.configurator import configurator
-from z3c.form import form, field, button
+from z3c.form import form, field, button, group
from z3c.formui import layout
import grok
@@ -36,6 +36,7 @@
from tfws.website import interfaces
from tfws.website import authentication
+from tfws.website.catalog import setup_catalog
from tfws.website.layer import IWebsiteLayer
from tfws.website.i18n import MessageFactory as _
@@ -44,6 +45,8 @@
class WebSite(grok.Application, grok.Container):
"""Mars/Grok/Z3C demo website"""
zope.interface.implements(interfaces.IWebSite)
+ grok.local_utility(IntIds, IIntIds) # needed for the catalog
+ grok.local_utility(Catalog, ICatalog, setup=setup_catalog)
title = FieldProperty(interfaces.IWebSite['title'])
description = FieldProperty(interfaces.IWebSite['description'])
@@ -66,12 +69,24 @@
grok.context(Index)
grok.template('templates/index.pt')
-class Edit(mars.form.FormView, layout.FormLayoutSupport, form.EditForm):
+class InitialManagerGroup(group.Group):
+ label = u'Initial Manager Account'
+ fields = field.Fields(interfaces.IWebSiteMember, prefix="member").select(
+ 'member.login', 'member.password', 'member.firstName',
+ 'member.lastName', 'member.email')
+
+class SiteMetaDataGroup(group.Group):
+ label = u'Site Metadata'
+ fields = field.Fields(interfaces.IWebSite).select('title',
+ 'description', 'keyword')
+
+class Edit(mars.form.FormView, layout.FormLayoutSupport,
+ group.GroupForm, form.EditForm):
"""Edit form for site"""
grok.name('edit')
form.extends(form.EditForm)
label = u'Tree Fern Web Site Edit Form'
- fields = field.Fields(interfaces.IWebSite).omit('__parent__')
+ groups = (SiteMetaDataGroup,)
@button.buttonAndHandler(u'Apply and View', name='applyView')
def handleApplyView(self, action):
@@ -80,27 +95,34 @@
url = absoluteURL(self.context, self.request)
self.request.response.redirect(url)
-class Add(mars.form.FormView, layout.AddFormLayoutSupport, form.AddForm):
+
+class Add(mars.form.FormView, layout.AddFormLayoutSupport,
+ group.GroupForm, form.AddForm):
""" Add form for tfws.website."""
grok.name('add')
grok.context(IRootFolder)
- grok.local_utility(IntIds, IIntIds) # needed for the catalog
- grok.local_utility(Catalog, ICatalog, setup=setup_catalog)
label = _('Add a Tree Fern WebSite')
contentName = None
data = None
- fields = field.Fields(zope.schema.TextLine(
- __name__='__name__',
- title=_(u"name"),
- required=True))
+ fields = field.Fields(zope.schema.TextLine(__name__='__name__',
+ title=_(u"name"), required=True))
- fields += field.Fields(interfaces.IWebSite).select('title')
- fields += field.Fields(interfaces.IWebSiteMember, prefix="member").select(
- 'member.login', 'member.password', 'member.firstName',
- 'member.lastName', 'member.email')
+ groups = (SiteMetaDataGroup, InitialManagerGroup)
+ @button.buttonAndHandler(_('Add'), name='add')
+ def handleAdd(self, action):
+ data, errors = self.extractData()
+ if errors:
+ self.status = self.formErrorsMessage
+ return
+ obj = self.create(data)
+ zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(obj))
+ result = self.add(obj)
+ if result is not None:
+ self._finishedAdd = True
+
def create(self, data):
self.data = data
# get form data
@@ -115,14 +137,14 @@
# Add the site
if self.context.get(self.contentName) is not None:
self.status = _('Site with name already exist.')
- self._finished_add = False
+ self._finishedAdd = False
return None
self.context[self.contentName] = obj
# Configure the new site
configurator.configure(obj, data)
- self._finished_add = True
+ self._finishedAdd = True
return obj
def nextURL(self):
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/ascending.gif
===================================================================
(Binary files differ)
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/ascending.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/buttonBG.gif
===================================================================
(Binary files differ)
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/buttonBG.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/decending.gif
===================================================================
(Binary files differ)
Property changes on: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/images/decending.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/skin.py 2007-07-23 05:06:32 UTC (rev 78286)
@@ -1,6 +1,10 @@
+import zope.component
import zope.interface
from zope.viewlet.viewlet import CSSViewlet
from zope.publisher.interfaces.browser import IBrowserPage
+from zope.publisher.interfaces.http import IHTTPRequest
+from zope.traversing.browser import absoluteURL
+from zope.app.component import hooks
import z3c.formui
@@ -25,6 +29,11 @@
grok.context(IBrowserPage)
grok.template('template.pt')
+class NavigationManager(mars.viewlet.ViewletManager):
+ """navigation column viewletmanager"""
+ grok.name('INavigationColumn')
+ grok.context(zope.interface.Interface)
+
class CSSManager(mars.viewlet.ViewletManager):
"""css viewletmanager"""
zope.interface.implements(z3c.formui.interfaces.ICSS)
@@ -52,3 +61,20 @@
"""image resource directory (++resource++images)"""
mars.resource.directory('images')
+class ISiteURL(zope.interface.Interface):
+ pass
+
+class SiteURL(grok.MultiAdapter):
+ """Provides siteURL to all context"""
+ grok.name('siteURL')
+ grok.context(zope.interface.Interface)
+ zope.interface.implements(ISiteURL)
+ zope.component.adapts(zope.interface.Interface, IHTTPRequest)
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return absoluteURL(hooks.getSite(), self.request)
+
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/template.pt 2007-07-23 05:06:32 UTC (rev 78286)
@@ -6,20 +6,49 @@
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="pragma" content="no-cache" />
-<script type="text/javascript"
- tal:define="contexturl context/@@absolute_url;
- viewurl request/URL"
- tal:content="string:
- var contextURL = '${contexturl}';
- var viewURL = '${viewurl}';">
-</script>
<script tal:replace="structure provider:IJavaScript"> </script>
<style tal:replace="structure provider:ICSS">
</style>
</head>
-<body>
-<div id="content">
- <tal:block replace="structure provider:pagelet" />
+<body tal:define="siteURL context/@@siteURL">
+<div id="layoutWrapper">
+ <div id="layoutContainer">
+ <div id="headerContainer">
+ <div id="topLine">
+ </div>
+ </div>
+ <div id="breadCrumbContainer">
+ <b i18n:translate="">You are here:</b>
+ <tal:block tal:repeat="crumb context/@@breadcrumbs/crumbs">
+ <a href=""
+ tal:content="string:${crumb/name}"
+ tal:attributes="href string:${crumb/url}"
+ >item</a>
+ <tal:block condition="not:repeat/crumb/end">></tal:block>
+ </tal:block>
+ </div>
+ <div id="mainContainer">
+ <div id="naviContainer">
+ <tal:block replace="structure provider:INavigationColumn">
+ tools
+ </tal:block>
+ </div>
+ <div id="contentContainer">
+ <div id="content">
+ <tal:block replace="structure provider:pagelet">
+ content
+ </tal:block>
+ </div>
+ </div>
+ <div class="clear" />
+ <div id="footerContainer">
+ <div class="footer">
+ © Tree Fern Web Services ----
+ <a href="http://www.tfws.org.nz/mars" target="_blank">Mars Website</a>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
</body>
</html>
Modified: Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css
===================================================================
--- Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css 2007-07-23 04:21:03 UTC (rev 78285)
+++ Sandbox/darrylcousins/tfws.website/src/tfws/website/skin/website.css 2007-07-23 05:06:32 UTC (rev 78286)
@@ -1,86 +1,344 @@
/* zrt-replace: "./images" tal"string:${context/++resource++images}" */
-
body {
- font: 11px Verdana, Helvetica, Arial, sans-serif;
+ font-family: Verdana, sans-serif;
+ font-size: 100%;
margin: 0px;
padding: 0px;
}
/* [ html ]---------------------------------------------------------------- */
+img {
+ border: none;
+}
+
+a:link {
+ color: #3257C2;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #3257C2;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #214285;
+}
+
+h1 {
+ font-size: 150%;
+ color: #3257C2;
+ font-weight: normal;
+}
+
+h2 {
+ font-size: 125%;
+ color: #3257C2;
+ font-weight: normal;
+}
+
+h3 {
+ font-size: 100%;
+ color: #3257C2;
+ font-weight: normal;
+}
+
+h4 {
+ font-size: 85%;
+ color: #3257C2;
+}
+
+h5 {
+ font-size: 75%;
+ color: #3257C2;
+}
+
+
+h6 {
+ font-size: 75%;
+ color: #3257C2;
+}
+
+
+
+/* [ forms ]---------------------------------------------------------------- */
+
form {
margin: 0px;
padding: 0px;
}
-img {
- border: 0;
+fieldset {
+ margin-top: 15px;
+ padding: 10px 15px 5px 15px;
+ -moz-border-radius: 7px;
}
-a {
- color: #D91813;
- text-decoration: none;
+fieldset legend {
+ color: #5E4A32;
+ font-variant: small-caps;
+ font-weight: bold;
+ font-size: 110%;
+ padding: 2px 4px;
+ -moz-border-radius: 3px;
}
-a:link {
- color: #D91813;
- text-decoration: none;
+/* [ layout ]---------------------------------------------------------------- */
+
+div#layoutWrapper {
+ font-size: 80%;
+ text-align: center;
}
-a:visited {
- color: #A68E8E;
- text-decoration: none;
+div#layoutContainer {
+ width: 941px;
+ text-align: left;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 0px;
}
-a:hover {
- color: #8C100D;
+
+/* [ header ]-------------------------------------------------------------- */
+
+div#headerContainer {
+ width: 941px;
+ text-align: left;
+ position: relative;
+ margin: 0px;
+ padding: 0px;
+ background-color: #E1E1E1;
}
-fieldset {
+#topLine {
+ height: 5px;
+ background-color: #3257C2;
+}
+
+img#logo {
+ position: absolute;
+ top: 40px;
+ left: 10px;
+ padding: 0px 0px 20px 10px;
+}
+
+div#user {
+ top: 10px;
+ right: 10px;
+ position: absolute;
+ color: white;
+ padding: 0px 10px 0px 0px;
+}
+
+div#user a {
+ font-size: 80%;
+}
+
+/*---[ main ]-----------------------------------------------------------------*/
+
+div#mainContainer {
+ padding: 10px 0px 10px 0px;
+}
+
+/*---[ navigation ]-----------------------------------------------------------*/
+
+#naviContainer {
+ width: 140px;
+ float: left;
+ background-color: white;
+ padding: 25px 20px 0px 0px;
+}
+
+#naviContainer a {
+ color: #000000;
+}
+
+div.naviBox {
padding: 5px;
+ margin: 0px;
+ background-color: #F2F2F2;
+/* background: url("./img/naviBG.jpg") repeat-y left top;*/
}
+div.naviBox .naviBoxHeader {
+ height: 40px;
+ line-height: 40px;
+ color: #3257C2;
+ vertical-align: top;
+}
-h1, h2, h3, h4, h5, h6 {
- color: Black;
- clear: left;
- font: 100% bold Verdana, Helvetica, Arial, sans-serif;
- margin: 0;
- padding-top: 0.5em;
+div.naviBox .naviBoxHeader img {
+ vertical-align: middle;
+ padding: 5px 10px 5px 0px;
}
-h1 {
- font-size: 160%;
+
+div.naviBox .naviBoxBody {
+ font-size: 90%;
+ color: #000000;
}
-h2 {
- font-size: 140%;
+
+div.naviBox .naviBoxBody div {
+ padding-bottom: 5px;
}
-h3 {
- height: 20px;
- font-size: 120%;
- background-color: #DDDCD0;
- padding: 2px 0px 0px 5px;
+div.boxSpacer {
+ height: 10px;
}
-h4 {
- color: #777777;
- font-size: 100%;
+div.naviBox #searchForm input {
+ vertical-align: middle;
+}
+
+
+/* [ breadcrumbs ]----------------------------------------------------------- */
+
+div#breadCrumbContainer {
+ height: 24px;
+ line-height: 24px;
+ color: #666666;
+ font-size: 11px;
+ padding-left: 20px;
+}
+
+#breadCrumbContainer a {
+ color: #002B8B;
font-weight: bold;
+ text-decoration: none;
}
-h5 {
- font-size: 90%;
+#breadCrumbContainer a:hover {
+ font-weight: bold;
+ text-decoration: underline;
}
-h6 {
- font-size: 80%;
+#breadCrumbContainer a.selected {
+ font-weight: bold;
}
-/* ---[ website layout tags ]--------------------------------------------------- */
+/*---[ content ]-------------------------------------------------------------*/
+#contentContainer {
+ float: left;
+ width: 670px;
+ margin: 0;
+ padding: 10px 10px 0px 20px;
+}
#content {
- padding: 20px;
+ padding: 15px 0px 0px 0px;
}
+
+#content div.headline {
+ font-size: 175%;
+ color: #214285;
+ padding: 0px;
+}
+
+#content div.body {
+ padding-top: 10px;
+}
+
+/*---[ tool ]----------------------------------------------------------------*/
+
+.button, .button-field {
+ cursor: pointer;
+ border: outset 1px #ccc;
+ background: #999999;
+ color: #666666;
+ font-weight: bold;
+ padding: 1px 2px;
+ background: url(./images/buttonBG.gif) repeat-x left top;
+}
+
+.clear {
+ height: 1px;
+ clear: both;
+ margin: 0px;
+ padding: 0px;
+}
+
+/*---[ footer ]--------------------------------------------------------------*/
+
+#footerContainer {
+ padding-top: 20px;
+ text-align: center;
+}
+
+#footerContainer .footer {
+ width: 900px;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 10px;
+ color: #999999;
+ padding-top: 20px;
+}
+
+#footerContainer a {
+ color: #999999;
+}
+
+/*---[ table ]---------------------------------------------------------------*/
+
+table.list {
+ margin: 1em 0;
+ padding: 0;
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.list tr {
+ border-bottom: 1px solid #ffffff;
+}
+
+table.list tr.even {
+ background-color: #E6E1D9;
+}
+
+table.list tr.even td.sorted-on {
+ background-color: #D5CCBD;
+}
+
+table.list tr.odd {
+ background-color: #F2F0EC;
+}
+
+table.list tr.odd td.sorted-on {
+ background-color: #DFD9CE;
+}
+
+table.list tr.selected {
+ background-color: #BCAE98;
+}
+
+table.list tr.selected td.sorted-on {
+ background-color: #AE9E84;
+}
+
+table.list th {
+ background-color: #E6E1D9;
+ border-color: #ffffff;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ padding: 3px 4px;
+ text-align: left;
+}
+
+table.list th.sorted-on {
+ background-color: #D5CCBD;
+}
+
+table.list td {
+ vertical-align: top;
+ padding: 3px 4px;
+}
+
+table.list .centered {
+ text-align: center;
+}
+
+table.list .right {
+ text-align: right;
+}
+
More information about the Checkins
mailing list