[Checkins] SVN: z3c.formdemo/trunk/src/z3c/formdemo/ - Moved some
generally useful table stuff to formdemo browser package.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Thu Jun 21 22:20:21 EDT 2007
Log message for revision 76933:
- Moved some generally useful table stuff to formdemo browser package.
- Developed a new and pretty complex demo.
Changed:
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/__init__.py
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/address.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.css
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addresses.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/browser.py
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/configure.zcml
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.py
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.py
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/email.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/emails.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/form-macros.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/interfaces.py
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phone.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phones.pt
A z3c.formdemo/trunk/src/z3c/formdemo/addressbook/text-shadow.js
A z3c.formdemo/trunk/src/z3c/formdemo/browser/formatter.py
U z3c.formdemo/trunk/src/z3c/formdemo/browser/index.pt
A z3c.formdemo/trunk/src/z3c/formdemo/browser/table_sorted_header.pt
U z3c.formdemo/trunk/src/z3c/formdemo/configure.zcml
D z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/formatter.py
U z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/spreadsheet.py
D z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/table_sorted_header.pt
-=-
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/__init__.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/__init__.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/__init__.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1 @@
+# Make a package.
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/address.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/address.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/address.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,20 @@
+<div metal:use-macro="macro:form-header" />
+
+<div class="row">
+ <div class="inline" tal:define="widget view/widgets/street">
+ <div metal:use-macro="macro:widget-noerror-row" />
+ </div>
+</div>
+<div class="row">
+ <div class="inline" tal:define="widget view/widgets/city">
+ <div metal:use-macro="macro:widget-noerror-row" />
+ </div>
+ <div class="inline" tal:define="widget view/widgets/state">
+ <div metal:use-macro="macro:widget-noerror-row" />
+ </div>
+ <div class="inline" tal:define="widget view/widgets/zip">
+ <div metal:use-macro="macro:widget-noerror-row" />
+ </div>
+</div>
+
+<div metal:use-macro="macro:form-buttons" />
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/address.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.css
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.css (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.css 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,211 @@
+h1 {
+ background-color: #619FDF;
+ border: 1px solid #3B81C8;
+ color: white;
+ padding: 5px 7px 2px 7px;
+ font-weight: bold;
+ margin-bottom: 20px;
+ -moz-border-radius: 3px;
+}
+
+h1 span {
+ text-shadow: 1px 1px 1px black;
+}
+
+h2 {
+ border-top: 2px solid #3B81C8;
+ border-bottom: 2px solid #3B81C8;
+ color: #3B81C8;
+ font-weight: bold;
+ padding: 0;
+ margin: 10px 0px 5px 0px;
+}
+
+h2 span {
+ font-size: 95%;
+ font-weight: normal;
+ text-shadow: 1px 1px 1px #285989;
+}
+
+input, select, textarea {
+ background-color: #FFFFA0;
+}
+
+input[type=submit] {
+ background-color: #619FDF;
+ border: 2px solid #3B81C8;
+ color: white;
+ font-weight: bold;
+ -moz-border-radius: 3px;
+}
+
+span.dateselect .year {
+ width: 6em;
+}
+
+span.dateselect .month {
+ width: 4em;
+}
+
+span.dateselect .day {
+ width: 4em;
+}
+
+hr.separator {
+ height: 2px;
+ color: #3B81C8;
+ background-color: #3B81C8;
+ margin-top: 15px;
+ border: 0;
+}
+
+div.status {
+ color: red;
+}
+
+div#layout {
+ clear: both;
+}
+
+div#contact-table {
+ float: left;
+ margin-right: 20px;
+}
+
+div#contact-form {
+ float: right;
+ border: 2px solid #3B81C8;
+ -moz-border-radius: 3px;
+ padding: 10px;
+ width: 400px;
+}
+
+div.section-content {
+ margin: 0px 10px;
+}
+
+table.contact-list {
+ border-collapse: collapse;
+}
+
+table.contact-list th {
+ background-color: #619FDF;
+ border-top: 1px solid #3B81C8;
+ border-bottom: 1px solid #3B81C8;
+ padding: 3px 5px;
+ text-align: left;
+ color: white;
+}
+
+table.contact-list th a {
+ color: white;
+}
+
+table.contact-list th a:visited {
+ color: white;
+}
+
+table.contact-list th a:hover {
+ color: white;
+}
+
+table.contact-list td {
+ padding: 2px 5px;
+ border-bottom: 1px solid #DBE1E6;
+}
+
+table.contact-list tr.even {
+ background-color: #EDF4F9;
+}
+
+table.contact-list tr.selected {
+ background-color: #FFFFA0;
+}
+
+table.contact-list a {
+ color: black;
+}
+
+table.contact-list a:visited {
+ color: black;
+}
+
+table.contact-list a:hover {
+ color: black;
+}
+
+div#addresses {
+ margin-top: 10px;
+}
+
+div#add-address {
+ margin-top: 10px;
+}
+
+select#form-widgets-addressName {
+ width: 150px;
+}
+
+fieldset.address {
+ background-color: #EDF4F9;
+ border: 1px solid #DBE1E6;
+ margin-top: 7px;
+}
+
+fieldset.address legend {
+ color: #3B81C8;
+}
+
+fieldset.address div.buttons {
+ margin: 0;
+ padding: 0;
+}
+
+div.inline, div.inline div {
+ display: inline;
+}
+
+input.city {
+ width: 12em;
+}
+
+input.state {
+ width: 2em;
+}
+
+input.zip {
+ width: 5em;
+}
+
+
+/* ----[ Phone Styles ]----------------------------------------------------- */
+
+div#phones {
+ margin-top: 20px;
+}
+
+input.countryCode {
+ width: 2em;
+}
+
+input.areaCode {
+ width: 3em;
+}
+
+input.number {
+ width: 9em;
+}
+
+input.extension {
+ width: 6em;
+}
+
+/* ----[ E-Mail Styles ]---------------------------------------------------- */
+
+div#emails {
+ margin-top: 20px;
+}
+
+input.email {
+ width: 20em;
+}
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.css
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,8 @@
+<h1><span>Address Book Demo</span></h1>
+
+<div id="layout">
+ <div id="contact-table"
+ tal:content="structure view/table" />
+ <div id="contact-form"
+ tal:content="structure view/form/render" />
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addressbook.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addresses.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addresses.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addresses.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,24 @@
+<fieldset class="address" tal:repeat="form view/addressForms">
+ <legend tal:content="form/title">Name</legend>
+ <div tal:content="structure form/render" />
+</fieldset>
+<div id="add-address">
+ <div class="status"
+ tal:define="status view/status"
+ tal:condition="status">
+ <div class="summary"
+ tal:content="view/status">
+ Form status summary
+ </div>
+ </div>
+ <div>
+ <span class="widget"
+ tal:content="structure view/widgets/addressName/render">
+ <input type="text" size="24" value="" />
+ </span>
+ <span class="buttons">
+ <input tal:repeat="action view/actions/values"
+ tal:replace="structure action/render" />
+ </span>
+ </div>
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/addresses.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/browser.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/browser.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/browser.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,415 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Address Book Views
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.component
+import zope.location
+from zope.app.container import btree
+from zope.app.session.interfaces import ISession
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.publisher import browser
+from zope.traversing.browser import absoluteURL
+from zope.viewlet.viewlet import CSSViewlet, JavaScriptViewlet
+from z3c.template.interfaces import ILayoutTemplate
+from zc.table import column
+from zc.table.interfaces import ISortableColumn
+
+from z3c.form import form, field, button, subform
+from z3c.formdemo.browser import formatter
+from z3c.formdemo.addressbook import interfaces, contact, dateselect
+
+SESSION_KEY = 'z3c.formdemo.addressbook'
+
+AddressBookCSSViewlet = CSSViewlet('addressbook.css')
+TextShadowViewlet = JavaScriptViewlet('text-shadow.js')
+
+
+class AddressForm(subform.EditSubForm, form.EditForm):
+
+ form.extends(subform.EditSubForm)
+ fields = field.Fields(interfaces.IAddress)
+ name = None
+ deleted = False
+
+ # In this application, we do not want this message
+ noChangesMessage = None
+
+ def updateWidgets(self):
+ super(AddressForm, self).updateWidgets()
+ for name, widget in self.widgets.items():
+ widget.css += ' ' + name
+
+ @property
+ def title(self):
+ return interfaces.AddressNamesVocabulary.getTerm(self.name).title
+
+ @button.handler(form.AddForm.buttons['add'])
+ def handleAdd(self, action):
+ self.handleApply(self, action)
+
+ @button.buttonAndHandler(u'Delete')
+ def handleDelete(self, action):
+ addresses = self.getContent().__parent__
+ del addresses[self.name]
+ self.deleted = True
+
+
+class AddressesForm(form.AddForm):
+ """Form to manage addresses."""
+ # Select the field that specifies the address name.
+ fields = field.Fields(interfaces.IContact['addresses'].key_type)
+ parentForm = None
+
+ def create(self, data):
+ address = contact.Address()
+ address.__name__ = data['addressName']
+ return address
+
+ def add(self, object):
+ addressbook = self.getContent()
+ # Make sure that an address cannot be added twice.
+ if object.__name__ in addressbook:
+ self.status = u'Address already provided for contact.'
+ return None
+ addressbook[object.__name__] = object
+ return object
+
+ def getContent(self):
+ # Get the address container from the contact
+ if interfaces.IContact.providedBy(self.context):
+ return self.context.addresses
+ # We are in the process of adding a contact, so store the addresses
+ # container in a session variable.
+ session = ISession(self.request)[SESSION_KEY]
+ if 'addresses' not in session:
+ session['addresses'] = btree.BTreeContainer()
+ return session['addresses']
+
+ def update(self):
+ # Make sure that we have a unique prefix.
+ self.prefix = self.parentForm.prefix + 'addresses.'
+ super(AddressesForm, self).update()
+ # For each address, create an address form.
+ self.addressForms = []
+ for name, address in self.getContent().items():
+ form = AddressForm(address, self.request, self.parentForm)
+ form.name = name
+ # The prefix is created at runtime to guarantee uniqueness
+ form.prefix = self.prefix + name + '.'
+ form.update()
+ # Updating the address can also mean its deletion. If deleted, it
+ # is not added to the list.
+ if not form.deleted:
+ self.addressForms.append(form)
+
+ def render(self):
+ # Boilerplate when workign with view templates.
+ template = zope.component.getMultiAdapter(
+ (self, self.request), IPageTemplate)
+ return template(self)
+
+
+class PhoneForm(subform.EditSubForm):
+ form.extends(subform.EditSubForm)
+ fields = field.Fields(interfaces.IPhone)
+ attrName = None
+ error = None
+ mode = 'input'
+
+ def updateWidgets(self):
+ super(PhoneForm, self).updateWidgets()
+ for name, widget in self.widgets.items():
+ widget.css += ' ' + name
+
+ def getContent(self):
+ # Get the phone attribute from the contact
+ if interfaces.IContact.providedBy(self.context):
+ return getattr(self.context, self.attrName)
+ # We are in the process of adding a contact, so store the phone
+ # in a session variable.
+ session = ISession(self.request)[SESSION_KEY]
+ if self.attrName not in session:
+ session[self.attrName] = contact.Phone()
+ return session[self.attrName]
+
+ @button.handler(form.AddForm.buttons['add'])
+ def handleAdd(self, action):
+ self.handleApply(self, action)
+
+ @property
+ def id(self):
+ return (self.prefix + 'widgets.countryCode').replace('.', '-')
+
+ @property
+ def label(self):
+ return interfaces.IContact[self.attrName].title
+
+ @property
+ def required(self):
+ return interfaces.IContact[self.attrName].required
+
+
+class PhonesForm(browser.BrowserPage):
+ parentForm = None
+
+ def update(self):
+ self.prefix = self.parentForm.prefix + 'phones.'
+ self.forms = []
+ for name in ('homePhone', 'workPhone', 'cellPhone'):
+ form = PhoneForm(self.context, self.request, self.parentForm)
+ form.prefix = self.prefix + name + '.'
+ form.attrName = name
+ form.update()
+ self.forms.append(form)
+
+ def render(self):
+ template = zope.component.getMultiAdapter(
+ (self, self.request), IPageTemplate)
+ return template(self)
+
+
+class EMailForm(subform.EditSubForm, form.EditForm):
+ form.extends(subform.EditSubForm)
+ fields = field.Fields(interfaces.IEMail['fullAddress'])
+ index = None
+ deleted = False
+
+ # In this application, we do not want this message
+ noChangesMessage = None
+
+ def updateWidgets(self):
+ super(EMailForm, self).updateWidgets()
+ for name, widget in self.widgets.items():
+ widget.css += ' email'
+
+ @button.handler(form.AddForm.buttons['add'])
+ def handleAdd(self, action):
+ self.handleApply(self, action)
+
+ @button.buttonAndHandler(u'Delete')
+ def handleDelete(self, action):
+ emails = self.getContent().__parent__
+ del emails[self.index]
+ self.deleted = True
+
+
+class EMailsForm(form.AddForm):
+ fields = field.Fields(interfaces.IEMail['fullAddress'])
+ parentForm = None
+
+ def updateWidgets(self):
+ super(EMailsForm, self).updateWidgets()
+ for name, widget in self.widgets.items():
+ widget.css += ' email'
+
+ def create(self, data):
+ address = contact.EMail(**data)
+ return address
+
+ def add(self, object):
+ self.getContent().append(object)
+ zope.location.locate(object, self.getContent())
+ self.widgets.ignoreRequest = True
+ self.widgets.update()
+ return object
+
+ def getContent(self):
+ # Get the address container from the contact
+ if interfaces.IContact.providedBy(self.context):
+ return self.context.emails
+ # We are in the process of adding a contact, so store the email list
+ # in a session variable.
+ session = ISession(self.request)[SESSION_KEY]
+ if 'emails' not in session:
+ session['emails'] = contact.EMails()
+ return session['emails']
+
+ def update(self):
+ self.prefix = self.parentForm.prefix + 'emails.'
+ super(EMailsForm, self).update()
+ self.emailForms = []
+ for index, email in enumerate(self.getContent()):
+ form = EMailForm(email, self.request, self.parentForm)
+ form.index = index
+ form.prefix = self.prefix + str(index) + '.'
+ form.update()
+ if not form.deleted:
+ self.emailForms.append(form)
+
+ def render(self):
+ template = zope.component.getMultiAdapter(
+ (self, self.request), IPageTemplate)
+ return template(self)
+
+
+class ContactAddForm(form.AddForm):
+ fields = field.Fields(interfaces.IContact).select(
+ 'firstName', 'lastName', 'birthday')
+ fields['birthday'].widgetFactory = dateselect.DateSelectFieldWidget
+ prefix = 'contact.add.'
+
+ def update(self):
+ self.updateWidgets()
+ self.updateActions()
+
+ self.addressesForm = AddressesForm(self.context, self.request)
+ self.addressesForm.parentForm = self
+ self.addressesForm.update()
+
+ self.phonesForm = PhonesForm(self.context, self.request)
+ self.phonesForm.parentForm = self
+ self.phonesForm.update()
+
+ self.emailsForm = EMailsForm(self.context, self.request)
+ self.emailsForm.parentForm = self
+ self.emailsForm.update()
+
+ self.actions.execute()
+
+
+ def create(self, data):
+ newContact = contact.Contact(**data)
+
+ newContact.addresses = self.addressesForm.getContent()
+ zope.location.locate(newContact.addresses, newContact, 'addresses')
+ del ISession(self.request)[SESSION_KEY]['addresses']
+
+ for phoneForm in self.phonesForm.forms:
+ phone = phoneForm.getContent()
+ zope.location.locate(phone, newContact, phoneForm.attrName)
+ setattr(newContact, phoneForm.attrName, phone)
+ del ISession(self.request)[SESSION_KEY][phoneForm.attrName]
+
+ newContact.emails = self.emailsForm.getContent()
+ zope.location.locate(newContact.emails, newContact, 'emails')
+ del ISession(self.request)[SESSION_KEY]['emails']
+
+ return newContact
+
+
+ def add(self, object):
+ count = 0
+ while 'contact-%i' %count in self.context:
+ count += 1;
+ self._name = 'contact-%i' %count
+ self.context[self._name] = object
+ return object
+
+
+ def nextURL(self):
+ return self.request.getURL()
+
+AddContactLabel = button.StaticButtonActionAttribute(
+ u'Add Contact', button=form.AddForm.buttons['add'], form=ContactAddForm)
+
+
+class ContactEditForm(form.EditForm):
+ form.extends(form.EditForm)
+ fields = field.Fields(interfaces.IContact).select(
+ 'firstName', 'lastName', 'birthday')
+ fields['birthday'].widgetFactory = dateselect.DateSelectFieldWidget
+ prefix = 'contact.edit.'
+
+ # In this application, we do not want this message
+ noChangesMessage = None
+
+ @button.buttonAndHandler(u'Delete')
+ def handleDelete(self, action):
+ # Delete the contact from the address book
+ contact = self.getContent()
+ addressbook = contact.__parent__
+ del addressbook[contact.__name__]
+ # Reset the selected item
+ ISession(self.request)[SESSION_KEY]['selectedContact'] = None
+
+ @button.buttonAndHandler(u'Done')
+ def handleDone(self, action):
+ # Reset the selected item
+ ISession(self.request)[SESSION_KEY]['selectedContact'] = None
+
+ def update(self):
+ super(ContactEditForm, self).update()
+ self.addressesForm = AddressesForm(self.context, self.request)
+ self.addressesForm.parentForm = self
+ self.addressesForm.update()
+
+ self.phonesForm = PhonesForm(self.context, self.request)
+ self.phonesForm.parentForm = self
+ self.phonesForm.update()
+
+ self.emailsForm = EMailsForm(self.context, self.request)
+ self.emailsForm.parentForm = self
+ self.emailsForm.update()
+
+
+class SelectContactColumn(column.GetterColumn):
+ zope.interface.implements(ISortableColumn)
+
+ def renderCell(self, item, formatter):
+ value = super(SelectContactColumn, self).renderCell(item, formatter)
+ return '<a href="%s?selectContact=%s">%s</a>' %(
+ formatter.request.getURL(), item.__name__, value)
+
+
+class AddressBook(browser.BrowserPage):
+
+ columns = (
+ SelectContactColumn(
+ u'Last Name', lambda i, f: i.lastName, name='lastName'),
+ SelectContactColumn(
+ u'First Name', lambda i, f: i.firstName, name='firstName'),
+ )
+
+ @apply
+ def selectedContact():
+ def get(self):
+ session = ISession(self.request)[SESSION_KEY]
+ return session.get('selectedContact')
+ def set(self, value):
+ session = ISession(self.request)[SESSION_KEY]
+ session['selectedContact'] = value
+ return property(get, set)
+
+ def update(self):
+ # Select a new contact
+ if 'selectContact' in self.request:
+ self.selectedContact = self.context[self.request['selectContact']]
+ # Setup the form
+ if self.selectedContact:
+ self.form = ContactEditForm(self.selectedContact, self.request)
+ self.form.update()
+ if not self.selectedContact:
+ self.form = ContactAddForm(self.context, self.request)
+ self.form.update()
+ # Setup the table
+ rows = [content for content in self.context.values()
+ if interfaces.IContact.providedBy(content)]
+
+ self.table = formatter.SelectedItemFormatter(
+ self.context, self.request, rows,
+ prefix = SESSION_KEY + '.', columns=self.columns,
+ sort_on=[('lastName', False)])
+ self.table.sortKey = 'z3c.formdemo.addressbook.sort-on'
+ self.table.cssClasses['table'] = 'contact-list'
+ self.table.widths = (150, 150)
+ self.table.selectedItem = self.selectedContact
+
+ def __call__(self):
+ self.update()
+ layout = zope.component.getMultiAdapter((self, self.request),
+ ILayoutTemplate)
+ return layout(self)
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/browser.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/configure.zcml
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/configure.zcml (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/configure.zcml 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,152 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="z3c.formdemo">
+
+ <!-- Content Security Declarations -->
+
+ <class class=".contact.Address">
+ <allow interface=".interfaces.IAddress" />
+ <require permission="zope.Public"
+ set_schema=".interfaces.IAddress" />
+ </class>
+
+ <class class=".contact.EMail">
+ <allow interface=".interfaces.IEMail" />
+ <require permission="zope.Public"
+ set_schema=".interfaces.IEMail" />
+ </class>
+
+ <class class=".contact.Phone">
+ <allow interface=".interfaces.IPhone" />
+ <require permission="zope.Public"
+ set_schema=".interfaces.IPhone" />
+ </class>
+
+ <class class=".contact.Contact">
+ <allow interface=".interfaces.IContact" />
+ <require permission="zope.Public"
+ set_schema=".interfaces.IContact" />
+ </class>
+
+ <!-- Supporting resources -->
+
+ <browser:zrt-resource
+ name="addressbook.css"
+ file="addressbook.css"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <browser:viewlet
+ name="addressbook.css"
+ view=".browser.AddressBook"
+ manager="z3c.formdemo.skin.ICSS"
+ class=".browser.AddressBookCSSViewlet"
+ permission="zope.Public"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ weight="1000"
+ />
+
+ <browser:zrt-resource
+ name="text-shadow.js"
+ file="text-shadow.js"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <browser:viewlet
+ name="text-shadow.js"
+ view=".browser.AddressBook"
+ manager="z3c.formdemo.skin.IJavaScript"
+ class=".browser.TextShadowViewlet"
+ permission="zope.Public"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:macro
+ name="widget-noerror-row"
+ macro="widget-noerror-row"
+ template="form-macros.pt"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <!-- Date-Select Widget -->
+
+ <adapter factory=".dateselect.DateSelectDataConverter" />
+
+ <z3c:widgetTemplate
+ mode="input"
+ widget=".dateselect.DateSelectWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="dateselect.pt"
+ />
+
+ <!-- Address book view -->
+
+ <z3c:pagelet
+ name="addressbook.html"
+ for="zope.app.container.interfaces.IContainer"
+ class=".browser.AddressBook"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ permission="zope.Public"
+ />
+
+ <z3c:template
+ template="addressbook.pt"
+ for=".browser.AddressBook"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <adapter
+ factory=".browser.AddContactLabel"
+ name="title" />
+
+ <z3c:template
+ template="contact.pt"
+ for=".browser.ContactAddForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="contact.pt"
+ for=".browser.ContactEditForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="addresses.pt"
+ for=".browser.AddressesForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="address.pt"
+ for=".browser.AddressForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="phones.pt"
+ for=".browser.PhonesForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="phone.pt"
+ for=".browser.PhoneForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="emails.pt"
+ for=".browser.EMailsForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+ <z3c:template
+ template="email.pt"
+ for=".browser.EMailForm"
+ layer="z3c.formdemo.layer.IDemoBrowserLayer"
+ />
+
+</configure>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,20 @@
+<div metal:use-macro="macro:form">
+ <metal:block fill-slot="above-buttons">
+ <div id="addresses">
+ <h2><span>Addresses</span></h2>
+ <div class="section-content"
+ tal:content="structure view/addressesForm/render" />
+ </div>
+ <div id="phones">
+ <h2><span>Phone Numbers</span></h2>
+ <div class="section-content"
+ tal:content="structure view/phonesForm/render" />
+ </div>
+ <div id="emails">
+ <h2><span>E-Mail Addresses</span></h2>
+ <div class="section-content"
+ tal:content="structure view/emailsForm/render" />
+ </div>
+ <hr class="separator" />
+ </metal:block>
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,92 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Address Book Views
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import persistent
+import zope.interface
+import zope.location
+from zope.app.container import contained
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.formdemo.addressbook import interfaces
+
+
+class Address(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IAddress)
+
+ street = FieldProperty(interfaces.IAddress['street'])
+ city = FieldProperty(interfaces.IAddress['city'])
+ state = FieldProperty(interfaces.IAddress['state'])
+ zip = FieldProperty(interfaces.IAddress['zip'])
+
+ def __init__(self, **data):
+ for name, value in data.items():
+ setattr(self, name, value)
+
+
+class EMails(zope.location.Location, list):
+ pass
+
+class EMail(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IEMail)
+
+ user = FieldProperty(interfaces.IEMail['user'])
+ host = FieldProperty(interfaces.IEMail['host'])
+
+ def __init__(self, **data):
+ for name, value in data.items():
+ setattr(self, name, value)
+
+ @apply
+ def fullAddress():
+ def get(self):
+ return self.user + u'@' + self.host
+ def set(self, value):
+ self.user, self.host = value.split('@')
+ return property(get, set)
+
+
+class Phone(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IPhone)
+
+ countryCode = FieldProperty(interfaces.IPhone['countryCode'])
+ areaCode = FieldProperty(interfaces.IPhone['areaCode'])
+ number = FieldProperty(interfaces.IPhone['number'])
+ extension = FieldProperty(interfaces.IPhone['extension'])
+
+ def __init__(self, **data):
+ for name, value in data.items():
+ setattr(self, name, value)
+
+
+class Contact(contained.Contained, persistent.Persistent):
+ zope.interface.implements(interfaces.IContact)
+
+ firstName = FieldProperty(interfaces.IContact['firstName'])
+ lastName = FieldProperty(interfaces.IContact['lastName'])
+ birthday = FieldProperty(interfaces.IContact['birthday'])
+
+ addresses = None
+ emails = None
+ homePhone = None
+ cellPhone = None
+ workPhone = None
+
+ def __init__(self, **data):
+ # Save all values
+ for name, value in data.items():
+ setattr(self, name, value)
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/contact.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,5 @@
+<span class="dateselect">
+ <div tal:replace="structure view/month/render" /> /
+ <div tal:replace="structure view/day/render" /> /
+ <div tal:replace="structure view/year/render" />
+</span>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,88 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Date Selection
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import datetime
+import zope.component
+import zope.interface
+import zope.schema
+from zope.schema import vocabulary
+from z3c.form import interfaces, widget
+from z3c.form.browser import select
+
+
+class DateSelectWidget(widget.Widget):
+
+ selects = ( ('year', range(1920, 2011), 0),
+ ('month', range(1, 13), 1),
+ ('day', range(1, 32), 2) )
+
+ def update(self):
+ for (name, options, loc) in self.selects:
+ selectWidget = select.SelectWidget(self.request)
+ selectWidget.terms = vocabulary.SimpleVocabulary.fromValues(options)
+ selectWidget.required = True
+ selectWidget.name = self.name + '.' + name
+ selectWidget.id = selectWidget.name.replace('.', '-')
+ selectWidget.css = name
+ setattr(self, name, selectWidget)
+
+ super(DateSelectWidget, self).update()
+
+ for (name, options, loc) in self.selects:
+ selectWidget = getattr(self, name)
+ if self.value and not selectWidget.value:
+ selectWidget.value = (self.value[loc],)
+ selectWidget.update()
+
+
+ def extract(self, default=interfaces.NOVALUE):
+ """See z3c.form.interfaces.IWidget."""
+ value = (self.year.extract(default),
+ self.month.extract(default),
+ self.day.extract(default))
+ if default in value:
+ return default
+ return value
+
+
+ at zope.component.adapter(zope.schema.interfaces.IDate, interfaces.IFormLayer)
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def DateSelectFieldWidget(field, request):
+ """IFieldWidget factory for DateSelectWidget."""
+ return widget.FieldWidget(field, DateSelectWidget(request))
+
+
+class DateSelectDataConverter(object):
+ zope.component.adapts(zope.schema.interfaces.IDate, DateSelectWidget)
+ zope.interface.implements(interfaces.IDataConverter)
+
+ def __init__(self, field, widget):
+ self.field = field
+ self.widget = widget
+
+ def toWidgetValue(self, value):
+ """See interfaces.IDataConverter"""
+ if value is self.field.missing_value:
+ return None
+ return (str(value.year), str(value.month), str(value.day))
+
+ def toFieldValue(self, value):
+ """See interfaces.IDataConverter"""
+ if value == None:
+ return self.field.missing_value
+ return datetime.date(*[int(part[0]) for part in value])
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/dateselect.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/email.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/email.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/email.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,5 @@
+<div>
+ <div metal:use-macro="macro:form-header" />
+ <div tal:replace="structure view/widgets/fullAddress/render" />
+ <div tal:replace="structure view/actions/delete/render" />
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/email.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/emails.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/emails.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/emails.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,23 @@
+<div class="row"
+ tal:repeat="form view/emailForms"
+ tal:content="structure form/render" />
+<div id="add-email">
+ <div class="status"
+ tal:define="status view/status"
+ tal:condition="status">
+ <div class="summary"
+ tal:content="view/status">
+ Form status summary
+ </div>
+ </div>
+ <div>
+ <span class="widget"
+ tal:content="structure view/widgets/fullAddress/render">
+ <input type="text" size="24" value="" />
+ </span>
+ <span class="buttons">
+ <input tal:repeat="action view/actions/values"
+ tal:replace="structure action/render" />
+ </span>
+ </div>
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/emails.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/form-macros.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/form-macros.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/form-macros.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,14 @@
+<metal:block define-macro="widget-noerror-row">
+<div class="noerror">
+ <div class="label">
+ <label tal:attributes="for widget/name">
+ <span i18n:translate=""
+ tal:content="widget/label">label</span
+ ><span class="required" tal:condition="widget/required">*</span>
+ </label>
+ </div>
+ <div class="widget" tal:content="structure widget/render">
+ <input type="text" size="24" value="" />
+ </div>
+</div>
+</metal:block>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/form-macros.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/interfaces.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/interfaces.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/interfaces.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,125 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Address Book Interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.interface
+import zope.schema
+from zope.schema import vocabulary
+
+AddressNamesVocabulary = vocabulary.SimpleVocabulary((
+ vocabulary.SimpleTerm('home', title=u'Home'),
+ vocabulary.SimpleTerm('work', title=u'Work'),
+ vocabulary.SimpleTerm('other', title=u'Other')
+ ))
+
+class IAddress(zope.interface.Interface):
+ """An address."""
+
+ street = zope.schema.TextLine(
+ title=u'Street',
+ description=u'Street name and number.')
+
+ city = zope.schema.TextLine(
+ title=u'City',
+ description=u'City.')
+
+ state = zope.schema.TextLine(
+ title=u'State',
+ description=u'State or Province.')
+
+ zip = zope.schema.TextLine(
+ title=u'ZIP',
+ description=u'ZIP Code.')
+
+
+class IEMail(zope.interface.Interface):
+ """An E-mail address."""
+
+ user = zope.schema.TextLine(
+ title=u'User')
+
+ host = zope.schema.TextLine(
+ title=u'Host')
+
+ fullAddress = zope.schema.TextLine(
+ title=u'E-mail Address',
+ description=u'The full E-mail address.')
+
+
+class IPhone(zope.interface.Interface):
+ """A phone number."""
+
+ countryCode = zope.schema.TextLine(
+ title=u'Country Code',
+ default=u'1')
+
+ areaCode = zope.schema.TextLine(
+ title=u'Area Code')
+
+ number = zope.schema.TextLine(
+ title=u'Number')
+
+ extension = zope.schema.TextLine(
+ title=u'Extension',
+ required=False)
+
+
+class IContact(zope.interface.Interface):
+ """A contact in the address book."""
+
+ firstName = zope.schema.TextLine(
+ title=u'First Name',
+ description=u'First name of the person.')
+
+ lastName = zope.schema.TextLine(
+ title=u'Last Name',
+ description=u'Last name of the person.')
+
+ birthday = zope.schema.Date(
+ title=u'Birthday',
+ description=u'Birthday of the person.',
+ required=False)
+
+ addresses = zope.schema.Dict(
+ title=u'Addresses',
+ description=u'A mapping of addresses',
+ key_type=zope.schema.Choice(
+ __name__='addressName',
+ vocabulary=AddressNamesVocabulary),
+ value_type=zope.schema.Object(schema=IAddress))
+
+ emails = zope.schema.List(
+ title=u'E-mails',
+ description=u'E-mails of the person.',
+ value_type=zope.schema.Object(schema=IEMail))
+
+ homePhone = zope.schema.Object(
+ title=u'Home Phone',
+ description=u'Home Phone Number.',
+ schema=IPhone)
+
+ cellPhone = zope.schema.Object(
+ title=u'Cell Phone',
+ description=u'Cell Phone Number.',
+ schema=IPhone,
+ required=False)
+
+ workPhone = zope.schema.Object(
+ title=u'Work Phone',
+ description=u'Work Phone Number.',
+ schema=IPhone,
+ required=False)
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phone.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phone.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phone.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,4 @@
++<input tal:replace="structure view/widgets/countryCode/render" />
+( <input tal:replace="structure view/widgets/areaCode/render" /> )
+<input tal:replace="structure view/widgets/number/render" />
+ext. <input tal:replace="structure view/widgets/extension/render" />
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phone.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phones.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phones.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phones.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,4 @@
+<div class="row"
+ tal:repeat="widget view/forms">
+ <div metal:use-macro="macro:widget-row" />
+</div>
Property changes on: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/phones.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.formdemo/trunk/src/z3c/formdemo/addressbook/text-shadow.js
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/addressbook/text-shadow.js (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/addressbook/text-shadow.js 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,365 @@
+if(window.addEventListener)window.addEventListener('load',textShadows,false);
+else if(window.attachEvent)window.attachEvent('onload',textShadows);
+function setStyles(o,s){
+ var i;
+ s=s.split(';');
+ for(i in s){
+ var p=s[i].split(':');
+ o.style[p[0]]=p[1];
+ }
+}
+function textShadows(){
+ var ua=navigator.userAgent;
+ if(ua.indexOf('KHTML')>=0&&!(ua.indexOf('Safari')>=0))return;
+ var ss=document.styleSheets,a;
+ for(a in ss){
+ var theRules=[],b;
+ if(ss[a].cssRules)theRules=ss[a].cssRules;
+ else if(ss[a].rules)theRules=ss[a].rules;
+ for(b=0; b < theRules.length; b++){
+ var selector=theRules[b].selectorText,r=theRules[b].style.cssText;
+ if(/text-shadow/.test(r)){
+ r=r.replace(/([ ,]) /g,'$1').replace(/.*text-shadow[ :]+/,'').replace(/[ ]*;.*/,'');
+ var shadows=r.split(','),k,els=cssQuery(selector),l;
+ for(l in els){
+ var x=parseInt(els[l].offsetLeft),y=parseInt(els[l].offsetTop),el3=els[l].cloneNode(true);
+ setStyles(el3,'position:absolute;zIndex:50;margin:0');
+ for(k in shadows){
+ var parts=shadows[k].split(' ');
+ var newX=x+parseInt(parts[1]),newY=y+parseInt(parts[2]),rad=parseInt(parts[3]);
+ for(m=0-rad;m<=rad;++m)for(n=0-rad;n<=rad;++n)showShadow(els[l],newX+m,newY+n,parts[0]);
+ var el2=el3.cloneNode(true);
+ setStyles(el2,'left:'+x+'px;top:'+y+'px');
+ els[l].parentNode.appendChild(el2);
+ }
+ }
+ }
+ }
+ }
+}
+function showShadow(el,x,y,color){
+ var el2=el.cloneNode(true);
+ setStyles(el2,'position:absolute;color:'+color+';left:'+x+'px;top:'+y+'px;margin:0;textShadow:none;zIndex:49');
+ el2.style.opacity='.08';
+ el2.style.filter='alpha(opacity=8)';
+ el.parentNode.appendChild(el2);
+}
+
+
+
+/*
+ This work is licensed under a Creative Commons License.
+
+ License: http://creativecommons.org/licenses/by/1.0/
+
+ You are free:
+
+ to copy, distribute, display, and perform the work
+ to make derivative works
+ to make commercial use of the work
+
+ Under the following conditions:
+
+ Attribution. You must give the original author credit
+
+ Author: Dean Edwards/2004
+ Web: http://dean.edwards.name/
+*/
+
+/* keeping code tidy! */
+
+/* extendible css query function for common platforms
+
+ tested on IE5.0/5.5/6.0, Mozilla 1.6/Firefox 0.8, Opera 7.23/7.5
+ (all windows platforms - somebody buy me a mac!)
+*/
+
+// -----------------------------------------------------------------------
+// css query engine
+// -----------------------------------------------------------------------
+
+var cssQuery=function() {
+ var version="1.0.1"; // timestamp: 2004/05/25
+
+ // constants
+ var STANDARD_SELECT=/^[^>\+~\s]/;
+ var STREAM=/[\s>\+~:@#\.]|[^\s>\+~:@#\.]+/g;
+ var NAMESPACE=/\|/;
+ var IMPLIED_SELECTOR=/([\s>\+~\,]|^)([\.:#@])/g;
+ var ASTERISK ="$1*$2";
+ var WHITESPACE=/^\s+|\s*([\+\,>\s;:])\s*|\s+$/g;
+ var TRIM="$1";
+ var NODE_ELEMENT=1;
+ var NODE_TEXT=3;
+ var NODE_DOCUMENT=9;
+
+ // sniff for explorer (cos of one little bug)
+ var isMSIE=/MSIE/.test(navigator.appVersion), isXML;
+
+ // cache results for faster processing
+ var cssCache={};
+
+ // this is the query function
+ function cssQuery(selector, from) {
+ if (!selector) return [];
+ var useCache=arguments.callee.caching && !from;
+ from=(from) ? (from.constructor == Array) ? from : [from] : [document];
+ isXML=checkXML(from[0]);
+ // process comma separated selectors
+ var selectors=parseSelector(selector).split(",");
+ var match=[];
+ for (var i in selectors) {
+ // convert the selector to a stream
+ selector=toStream(selectors[i]);
+ // process the stream
+ var j=0, token, filter, cacheSelector="", filtered=from;
+ while (j < selector.length) {
+ token=selector[j++];
+ filter=selector[j++];
+ cacheSelector += token + filter;
+ // process a token/filter pair
+ filtered=(useCache && cssCache[cacheSelector]) ? cssCache[cacheSelector] : select(filtered, token, filter);
+ if (useCache) cssCache[cacheSelector]=filtered;
+ }
+ match=match.concat(filtered);
+ }
+ // return the filtered selection
+ return match;
+ };
+ cssQuery.caching=false;
+ cssQuery.reset=function() {
+ cssCache={};
+ };
+ cssQuery.toString=function () {
+ return "function cssQuery() {\n [version " + version + "]\n}";
+ };
+
+ var checkXML=(isMSIE) ? function(node) {
+ if (node.nodeType != NODE_DOCUMENT) node=node.document;
+ return node.mimeType == "XML Document";
+ } : function(node) {
+ if (node.nodeType == NODE_DOCUMENT) node=node.documentElement;
+ return node.localName != "HTML";
+ };
+
+ function parseSelector(selector) {
+ return selector
+ // trim whitespace
+ .replace(WHITESPACE, TRIM)
+ // encode attribute selectors
+ .replace(attributeSelector.ALL, attributeSelector.ID)
+ // e.g. ".class1" --> "*.class1"
+ .replace(IMPLIED_SELECTOR, ASTERISK);
+ };
+
+ // convert css selectors to a stream of tokens and filters
+ // it's not a real stream. it's just an array of strings.
+ function toStream(selector) {
+ if (STANDARD_SELECT.test(selector)) selector=" " + selector;
+ return selector.match(STREAM) || [];
+ };
+
+ var pseudoClasses={ // static
+ // CSS1
+ "link": function(element) {
+ for (var i=0; i < document.links; i++) {
+ if (document.links[i] == element) return true;
+ }
+ },
+ "visited": function(element) {
+ // can't do this without jiggery-pokery
+ },
+ // CSS2
+ "first-child": function(element) {
+ return !previousElement(element);
+ },
+ // CSS3
+ "last-child": function(element) {
+ return !nextElement(element);
+ },
+ "root": function(element) {
+ var document=element.ownerDocument || element.document;
+ return Boolean(element == document.documentElement);
+ },
+ "empty": function(element) {
+ for (var i=0; i < element.childNodes.length; i++) {
+ if (isElement(element.childNodes[i]) || element.childNodes[i].nodeType == NODE_TEXT) return false;
+ }
+ return true;
+ }
+ // add your own...
+ };
+
+ var QUOTED=/([\'\"])[^\1]*\1/;
+ function quote(value) {return (QUOTED.test(value)) ? value : "'" + value + "'"};
+ function unquote(value) {return (QUOTED.test(value)) ? value.slice(1, -1) : value};
+
+ var attributeSelectors=[];
+
+ function attributeSelector(attribute, compare, value) {
+ // properties
+ this.id=attributeSelectors.length;
+ // build the test expression
+ var test="element.";
+ switch (attribute.toLowerCase()) {
+ case "id":
+ test += "id";
+ break;
+ case "class":
+ test += "className";
+ break;
+ default:
+ test += "getAttribute('" + attribute + "')";
+ }
+ // continue building the test expression
+ switch (compare) {
+ case "=":
+ test += "==" + quote(value);
+ break;
+ case "~=":
+ test="/(^|\\s)" + unquote(value) + "(\\s|$)/.test(" + test + ")";
+ break;
+ case "|=":
+ test="/(^|-)" + unquote(value) + "(-|$)/.test(" + test + ")";
+ break;
+ }
+ push(attributeSelectors, new Function("element", "return " + test));
+ };
+ attributeSelector.prototype.toString=function() {
+ return attributeSelector.PREFIX + this.id;
+ };
+ // constants
+ attributeSelector.PREFIX="@";
+ attributeSelector.ALL=/\[([^~|=\]]+)([~|]?=?)([^\]]+)?\]/g;
+ // class methods
+ attributeSelector.ID=function(match, attribute, compare, value) {
+ return new attributeSelector(attribute, compare, value);
+ };
+
+ // select a set of matching elements.
+ // "from" is an array of elements.
+ // "token" is a character representing the type of filter
+ // e.g. ">" means child selector
+ // "filter" represents the tag name, id or class name that is being selected
+ // the function returns an array of matching elements
+ function select(from, token, filter) {
+ //alert("token="+token+",filter="+filter);
+ var namespace="";
+ if (NAMESPACE.test(filter)) {
+ filter=filter.split("|");
+ namespace=filter[0];
+ filter=filter[1];
+ }
+ var filtered=[], i;
+ switch (token) {
+ case " ": // descendant
+ for (i in from) {
+ var subset=getElementsByTagNameNS(from[i], filter, namespace);
+ for (var j=0; j < subset.length; j++) {
+ if (isElement(subset[j]) && (!namespace || compareNamespace(subset[j], namespace)))
+ push(filtered, subset[j]);
+ }
+ }
+ break;
+ case ">": // child
+ for (i in from) {
+ var subset=from[i].childNodes;
+ for (var j=0; j < subset.length; j++)
+ if (compareTagName(subset[j], filter, namespace)) push(filtered, subset[j]);
+ }
+ break;
+ case "+": // adjacent (direct)
+ for (i in from) {
+ var adjacent=nextElement(from[i]);
+ if (adjacent && compareTagName(adjacent, filter, namespace)) push(filtered, adjacent);
+ }
+ break;
+ case "~": // adjacent (indirect)
+ for (i in from) {
+ var adjacent=from[i];
+ while (adjacent=nextElement(adjacent)) {
+ if (adjacent && compareTagName(adjacent, filter, namespace)) push(filtered, adjacent);
+ }
+ }
+ break;
+ case ".": // class
+ filter=new RegExp("(^|\\s)" + filter + "(\\s|$)");
+ for (i in from) if (filter.test(from[i].className)) push(filtered, from[i]);
+ break;
+ case "#": // id
+ for (i in from) if (from[i].id == filter) push(filtered, from[i]);
+ break;
+ case "@": // attribute selector
+ filter=attributeSelectors[filter];
+ for (i in from) if (filter(from[i])) push(filtered, from[i]);
+ break;
+ case ":": // pseudo-class (static)
+ filter=pseudoClasses[filter];
+ for (i in from) if (filter(from[i])) push(filtered, from[i]);
+ break;
+ }
+ return filtered;
+ };
+
+ var getElementsByTagNameNS=(isMSIE) ? function(from, tagName) {
+ return (tagName == "*" && from.all) ? from.all : from.getElementsByTagName(tagName);
+ } : function(from, tagName, namespace) {
+ return (namespace) ? from.getElementsByTagNameNS("*", tagName) : from.getElementsByTagName(tagName);
+ };
+
+ function compareTagName(element, tagName, namespace) {
+ if (namespace && !compareNamespace(element, namespace)) return false;
+ return (tagName == "*") ? isElement(element) : (isXML) ? (element.tagName == tagName) : (element.tagName == tagName.toUpperCase());
+ };
+
+ var PREFIX=(isMSIE) ? "scopeName" : "prefix";
+ function compareNamespace(element, namespace) {
+ return element[PREFIX] == namespace;
+ };
+
+ // return the previous element to the supplied element
+ // previousSibling is not good enough as it might return a text or comment node
+ function previousElement(element) {
+ while ((element=element.previousSibling) && !isElement(element)) continue;
+ return element;
+ };
+
+ // return the next element to the supplied element
+ function nextElement(element) {
+ while ((element=element.nextSibling) && !isElement(element)) continue;
+ return element;
+ };
+
+ function isElement(node) {
+ return Boolean(node.nodeType == NODE_ELEMENT && node.tagName != "!");
+ };
+
+
+ // use a baby push function because IE5.0 doesn't support Array.push
+ function push(array, item) {
+ array[array.length]=item;
+ };
+
+ // fix IE5.0 String.replace
+ if ("i".replace(/i/,function(){return""})) {
+ // preserve String.replace
+ var string_replace=String.prototype.replace;
+ // create String.replace for handling functions
+ var function_replace=function(regexp, replacement) {
+ var match, newString="", string=this;
+ while ((match=regexp.exec(string))) {
+ // five string replacement arguments is sufficent for cssQuery
+ newString += string.slice(0, match.index) + replacement(match[0], match[1], match[2], match[3], match[4]);
+ string=string.slice(match.lastIndex);
+ }
+ return newString + string;
+ };
+ // replace String.replace
+ String.prototype.replace=function (regexp, replacement) {
+ this.replace=(typeof replacement == "function") ? function_replace : string_replace;
+ return this.replace(regexp, replacement);
+ };
+ }
+
+ return cssQuery;
+}();
Copied: z3c.formdemo/trunk/src/z3c/formdemo/browser/formatter.py (from rev 76833, z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/formatter.py)
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/browser/formatter.py (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/browser/formatter.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,128 @@
+##############################################################################
+#
+# 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
+ 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,
+ 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))
Modified: z3c.formdemo/trunk/src/z3c/formdemo/browser/index.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/browser/index.pt 2007-06-22 02:07:24 UTC (rev 76932)
+++ z3c.formdemo/trunk/src/z3c/formdemo/browser/index.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -28,4 +28,7 @@
<div>
<a href="../++skin++Z3CFormDemo/spreadsheet.html">Spreadsheet</a>
</div>
+ <div>
+ <a href="../++skin++Z3CFormDemo/addressbook.html">Address Book</a>
+ </div>
</div>
Copied: z3c.formdemo/trunk/src/z3c/formdemo/browser/table_sorted_header.pt (from rev 76833, z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/table_sorted_header.pt)
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/browser/table_sorted_header.pt (rev 0)
+++ z3c.formdemo/trunk/src/z3c/formdemo/browser/table_sorted_header.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -0,0 +1,16 @@
+<html tal:omit-tag="">
+ <a href=""
+ tal:attributes="href string:${request/URL}?sort-on=${options/name}"
+ tal:content="options/header" />
+
+ <img src="" width="7" height="4" style="vertical-align: middle"
+ alt="sort ascending"
+ tal:condition="options/isAscending"
+ tal:attributes="src
+ context/++resource++SpreadsheetImages/ascending.gif" />
+ <img src="" width="7" height="4" style="vertical-align: middle"
+ alt="sort ascending"
+ tal:condition="options/isDecending"
+ tal:attributes="src
+ context/++resource++SpreadsheetImages/decending.gif" />
+</html>
Modified: z3c.formdemo/trunk/src/z3c/formdemo/configure.zcml
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/configure.zcml 2007-06-22 02:07:24 UTC (rev 76932)
+++ z3c.formdemo/trunk/src/z3c/formdemo/configure.zcml 2007-06-22 02:20:21 UTC (rev 76933)
@@ -18,5 +18,6 @@
<include package=".calculator" />
<include package=".wizard" />
<include package=".spreadsheet" />
+ <include package=".addressbook" />
</configure>
Deleted: z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/formatter.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/formatter.py 2007-06-22 02:07:24 UTC (rev 76932)
+++ z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/formatter.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -1,129 +0,0 @@
-##############################################################################
-#
-# 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
-
-SORTED_ON_KEY = 'reflib.table.sorted-on'
-
-
-class ListFormatter(table.SortingFormatterMixin, table.AlternatingRowFormatter):
- """Provides a width for each column."""
-
- sortedHeaderTemplate = ViewPageTemplateFile('table_sorted_header.pt')
-
- 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)[SORTED_ON_KEY]
- 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
- 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,
- 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))
Modified: z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/spreadsheet.py
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/spreadsheet.py 2007-06-22 02:07:24 UTC (rev 76932)
+++ z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/spreadsheet.py 2007-06-22 02:20:21 UTC (rev 76933)
@@ -22,7 +22,8 @@
from z3c.formui import layout
from zc.table import table, column
-from z3c.formdemo.spreadsheet import content, formatter
+from z3c.formdemo.browser import formatter
+from z3c.formdemo.spreadsheet import content
class SpreadsheetDataColumn(column.SortingColumn):
@@ -160,4 +161,5 @@
self.context, self.request, rows,
prefix = self.sessionKey + '.', columns=columns,
sort_on=[('lastName', False)])
+ self.table.sortKey = 'formdemo.spreadsheet.sort-on'
self.table.widths = self.columnWidths + (100,)
Deleted: z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/table_sorted_header.pt
===================================================================
--- z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/table_sorted_header.pt 2007-06-22 02:07:24 UTC (rev 76932)
+++ z3c.formdemo/trunk/src/z3c/formdemo/spreadsheet/table_sorted_header.pt 2007-06-22 02:20:21 UTC (rev 76933)
@@ -1,16 +0,0 @@
-<html tal:omit-tag="">
- <a href=""
- tal:attributes="href string:${request/URL}?sort-on=${options/name}"
- tal:content="options/header" />
-
- <img src="" width="7" height="4" style="vertical-align: middle"
- alt="sort ascending"
- tal:condition="options/isAscending"
- tal:attributes="src
- context/++resource++SpreadsheetImages/ascending.gif" />
- <img src="" width="7" height="4" style="vertical-align: middle"
- alt="sort ascending"
- tal:condition="options/isDecending"
- tal:attributes="src
- context/++resource++SpreadsheetImages/decending.gif" />
-</html>
More information about the Checkins
mailing list