[z3-checkins] r55607 - in z3/deliverance/sandboxes/paul/dvplone: etc lib var/themesets/nuplone var/themesets/plone
paul at codespeak.net
paul at codespeak.net
Thu Jun 5 22:20:09 CEST 2008
Author: paul
Date: Thu Jun 5 22:20:08 2008
New Revision: 55607
Added:
z3/deliverance/sandboxes/paul/dvplone/lib/mgmtui.xsl
z3/deliverance/sandboxes/paul/dvplone/lib/tsm.py
z3/deliverance/sandboxes/paul/dvplone/lib/utils.py
Removed:
z3/deliverance/sandboxes/paul/dvplone/lib/theme1.html
Modified:
z3/deliverance/sandboxes/paul/dvplone/etc/serve.ini
z3/deliverance/sandboxes/paul/dvplone/lib/dvngfilter.py
z3/deliverance/sandboxes/paul/dvplone/lib/dvplone.py
z3/deliverance/sandboxes/paul/dvplone/lib/dvploneapp.py
z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/contentcustom.xsl
z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themeset.xml
z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themesource-plain.html
z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/contentcustom.xsl
z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themeset.xml
z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-plain.html
z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-tables.html
Log:
Theme selection via ++dvmanage++ now works
Modified: z3/deliverance/sandboxes/paul/dvplone/etc/serve.ini
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/etc/serve.ini (original)
+++ z3/deliverance/sandboxes/paul/dvplone/etc/serve.ini Thu Jun 5 22:20:08 2008
@@ -1,3 +1,6 @@
+[DEFAULT]
+debug = True
+
[server:main]
use = egg:Paste#http
Modified: z3/deliverance/sandboxes/paul/dvplone/lib/dvngfilter.py
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/lib/dvngfilter.py (original)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/dvngfilter.py Thu Jun 5 22:20:08 2008
@@ -1,64 +1,128 @@
"""WSGI middleware to switch Deliverance themes"""
-from dvngcompiler import DVNG
import os
import lxml.html
from lxml import etree
from wsgifilter import Filter
+from webob import Request, Response
+import urllib
+from tsm import ThemesetManager
+
TSHEADER = "X-DV-Themeset"
class DVNGFilter(Filter):
- default_themeid = "plone"
+ current_themeid = "nuplone"
+ moduledir = os.path.dirname(os.path.abspath(__file__))
+
+ def __init__(self, app, varthemesets, debug):
- def __init__(self, app, varthemesets):
+ # app is the DVPlone instance, pretending to be Plone as the
+ # WSGI endpoint.
self.app = app
- # The directory for var/themesets holds the cached versions of
- # compiled themesets. Passed in from the .ini file.
- self.varthemesets = varthemesets
-
- # Cache the processors for themesets we have already loaded.
- # Obviously we need a way to tell these things to update
- self.cached_themesets = {}
-
-
- def loadThemeset(self, themesetid):
- """Load themesetid if not loaded, then return DVNG processor"""
-
- # XXX This might be a terrible idea. Need to make sure
- # that lxml/libxml2 caching of XSLT processors doesn't
- # vomit. If so, we just reload the processor on each request.
- processor = self.cached_themesets.get(themesetid, None)
- if processor is None:
- # Need to load, store, and return the themeset
- fn = "%s/themeset.xml" % themesetid
- fullfn = os.path.join(self.varthemesets, fn)
- themesetfn = os.path.join(fullfn)
- dvng = DVNG(themesetfn)
- processor = etree.XSLT(dvng.xslt)
- self.cached_themesets[themesetid] = processor
+ # The themeset manager handles the local storage of download
+ # themesets, browsing for new themesets, making/caching
+ # processor, etc.
+ self.tsm = ThemesetManager(varthemesets, debug)
- return processor
+ self.debug = debug
+
+
+ def getManageScreen(self, req):
+ """Return the HTML body for a Themeset Management screen"""
+
+ # There is a Themeset Management UI. It runs outside of
+ # Plone, but is made to look like part of Plone via the
+ # miracle of Deliverance and WSGI. Run outside of Plone, of
+ # course, because the goal is to apply consistent
+ # look-and-feel across applications.
+ mgmtuifn = os.path.join(self.moduledir, "mgmtui.xsl")
+ mgmtdoc = etree.ElementTree(file=mgmtuifn)
+ mgmtprocessor = etree.XSLT(mgmtdoc)
+
+ # If this was a POST (self-posting form), do the work before
+ # displaying the results
+ if req.method == "POST":
+ # We only look for certain actions. It is all one big
+ # form, so dispatch based on which button was clicked.
+ dispatch_names = {
+ 'apply-local': self.applyLocal,
+ 'reload-remote': self.reloadRemote,
+ }
+ for dn in dispatch_names.items():
+ if req.POST.get(dn[0], None) is not None:
+ # Found the method to match the submit button
+ dn[1](req)
+
+ # Get the webob Response ready
+ res = Response(content_type="text/html")
+ screenid = "'%s'" % req.path_info[13:]
+ params = {'screenid': screenid}
+
+ # Apply XSLT and assign result to WebOb Response
+ result = mgmtprocessor(self.tsm.asXML(), **params)
+ res.body = str(result)
+
+ return res
+
+ def applyLocal(self, req):
+ """Apply changes to local cached themesets"""
+
+ current = req.POST['current']
+ self.tsm.setCurrentThemesetId(current)
+
+
+ def reloadRemote(self, req):
+
+ self.tsm.reloadRemote()
- def filter(self, environ, headers, data):
- """Turn incoming HTML4 data into etree, apply XSLT"""
-
- # First find out which themeset to use
- themesetid = environ.get(TSHEADER, None)
- if themesetid is None:
- themesetid = self.default_themeid
+
+ def __call__(self, environ, start_response):
+ """Called on the way into the application"""
+
+ req = Request(environ)
+ url = urllib.unquote(req.url)
+ if url.find("/++dvmanage++/") > -1:
+ res = self.getManageScreen(req)
+ res.body = self.handle_body(res.body, self.current_themeid)
+ return res(environ, start_response)
+
+ return super(DVNGFilter, self).__call__(environ, start_response)
+
+
+ def handle_body(self, data, themesetid):
+ """Run the transform, do all the work, return a string"""
# Get the processor from cache, or force a load
- processor = self.loadThemeset(themesetid)
+ processor = self.tsm.getProcessor(themesetid)
- # Apply the processor to the HTML and return the themed
- # result.
+ # Apply the processor to HTML and return themed result.
htmldoc = lxml.html.document_fromstring(data)
result = processor(htmldoc)
response = str(result)
+
+ return response
+
+
+ def _getThemesetId(self, environ):
+ """Single place to determine which themeset to use"""
+
+ themesetid = environ.get(TSHEADER, None)
+ if themesetid is None:
+ themesetid = self.tsm.current_themesetid
+
+ return themesetid
+
+
+ def filter(self, environ, headers, data):
+ """Turn incoming HTML4 data into etree, apply XSLT"""
+
+ # First find out which themeset to use
+ themesetid = self._getThemesetId(environ)
+ response = self.handle_body(data, themesetid)
return response
Modified: z3/deliverance/sandboxes/paul/dvplone/lib/dvplone.py
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/lib/dvplone.py (original)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/dvplone.py Thu Jun 5 22:20:08 2008
@@ -3,12 +3,16 @@
from dvngfilter import DVNGFilter
from dvploneapp import DVPlone
+def asbool(arg):
+ return arg in (True, 'True', 'true', 'yes', '1', 'on', 1)
def make_dvng(app, global_conf, varthemesets, **kw):
"""Choose which Deliverance theme should be used"""
- return DVNGFilter(app, varthemesets)
+ debug = asbool(global_conf.get('debug', False))
+ return DVNGFilter(app, varthemesets, debug)
def make_dvplone(global_config, document_root, **local_conf):
+ """Simulate a Plone application, including the handshake"""
return DVPlone(document_root)
Modified: z3/deliverance/sandboxes/paul/dvplone/lib/dvploneapp.py
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/lib/dvploneapp.py (original)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/dvploneapp.py Thu Jun 5 22:20:08 2008
@@ -6,6 +6,8 @@
class DVPlone(StaticURLParser):
def __call__(self, environ, start_response):
- print "IN DVPlone"
- environ[TSHEADER] = "nuplone"
+ print "In DVPlone at URL", environ['PATH_INFO']
+
+ # Perhaps the endpoint wants to override the decisionmaking
+ #environ[TSHEADER] = "nuplone"
return super(DVPlone, self).__call__(environ, start_response)
Added: z3/deliverance/sandboxes/paul/dvplone/lib/mgmtui.xsl
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/mgmtui.xsl Thu Jun 5 22:20:08 2008
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="html" indent="yes"/>
+ <xsl:variable name="dvmanage">/++dvmanage++</xsl:variable>
+ <xsl:param name="screenid">manage</xsl:param>
+ <xsl:template match="/">
+ <html>
+ <head>
+ <title>Some Title</title>
+ <meta name="dv.section" content="DVNG Articles"/>
+ </head>
+ <body>
+ <div id="content">
+ <h1>Themeset Manager</h1>
+ <p>This screen lets administrators manage the DVNG themesets for this site.</p>
+
+ <form method="post" action="{$dvmanage}{$screenid}">
+ <h3 style="margin-top: 3em">Currently Installed Themesets</h3>
+ <table width="95%" border="1" cellpadding="6" cellspacing="0">
+ <tr>
+ <th>Theme Title</th>
+ <th>ID</th>
+ <th>Version</th>
+ <th>Current</th>
+ <th>Remove?</th>
+ </tr>
+ <xsl:for-each select="/tsm/local/theme">
+ <tr>
+ <td>
+ <xsl:value-of select="@title"/>
+ </td>
+ <td align="center">
+ <xsl:value-of select="@id"/>
+ </td>
+ <td align="center">
+ <xsl:value-of select="@version"/>
+ </td>
+ <td align="center">
+ <input name="current" value="{@id}" type="radio" >
+ <xsl:if test="@current">
+ <xsl:attribute name="checked">checked</xsl:attribute>
+ </xsl:if>
+ </input>
+ </td>
+ <td align="center">
+ <input type="checkbox" name="remove"/>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ <p>
+ <input name="apply-local" type="submit" value="Apply"/>
+ </p>
+
+ <div style="float:right">
+ <input name="reload-remote" type="submit" value="Reload Listings"/>
+ </div>
+ <h3 style="margin-top:3em">All Known Themes</h3>
+ <p>Based on the theme repositories listed in the <code>plone.conf</code>
+ file, the following is a list of themes available for installation.</p>
+ <table width="95%" border="1" cellpadding="6" cellspacing="0">
+ <tr>
+ <th>Site/Theme Title</th>
+ <th>ID</th>
+ <th>Version</th>
+ <th>Date Modified</th>
+ <th>Install</th>
+ </tr>
+ <xsl:for-each select="/tsm/publishers/publisher">
+ <tr>
+ <td colspan="5"
+ style="font-size: x-large; background-color:silver">
+ <xsl:value-of select="@title"/>
+ </td>
+ </tr>
+ <xsl:for-each select="theme">
+ <tr style="font-size: small">
+ <td style="padding-left: 2em">
+ <xsl:value-of select="@title"/>
+ </td>
+ <td align="center">
+ <xsl:value-of select="@id"/>
+ </td>
+ <td align="center">
+ <xsl:value-of select="@version"/>
+ </td>
+ <td align="center">
+ <xsl:value-of select="@modified"/>
+ </td>
+ <td align="center">
+ <input type="checkbox" name="load" value="{@id}"/>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </xsl:for-each>
+ </table>
+ </form>
+ </div>
+ </body>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
Deleted: /z3/deliverance/sandboxes/paul/dvplone/lib/theme1.html
==============================================================================
--- /z3/deliverance/sandboxes/paul/dvplone/lib/theme1.html Thu Jun 5 22:20:08 2008
+++ (empty file)
@@ -1,11 +0,0 @@
-<html>
- <head>
- <title>Theme Page Title</title>
- </head>
- <body>
- <h1 id="pageheading">Theme Page Heading</h1>
- <div id="pagecontent">
- <p>Some sample theme content.</p>
- </div>
- </body>
-</html>
\ No newline at end of file
Added: z3/deliverance/sandboxes/paul/dvplone/lib/tsm.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/tsm.py Thu Jun 5 22:20:08 2008
@@ -0,0 +1,111 @@
+"""Themeset Manager
+
+Manage storage, retrieval, and updates of themesets.
+
+"""
+from lxml import etree
+import os
+from dvngcompiler import DVNG
+
+
+class ThemesetManager:
+
+ default_themesetid = "plone"
+
+ def __init__(self, storage_dir, debug):
+
+ # Should be the directory in "var" that contains
+ # all the themeset information
+ self.storage_dir = storage_dir
+ self.current_themesetid_fn = os.path.join(storage_dir,
+ "current_themesetid")
+
+ # Write the default to the file if one hasn't been customized
+ if self.current_themesetid is None:
+ self.setCurrentThemesetId(self.default_themesetid)
+
+ # Cache the processors for themesets we have already loaded.
+ # Obviously we need a way to tell these things to update
+ self.cached_themesets = {}
+
+ self.debug = debug
+
+ @property
+ def current_themesetid(self, newid=None):
+ v = open(self.current_themesetid_fn, "r").read()
+
+ return v
+
+ def setCurrentThemesetId(self, newid):
+ """Write newly-chosen themeset id to disk"""
+
+ f = open(self.current_themesetid_fn, "w")
+ f.write(newid)
+ f.close()
+
+ def reloadRemote(self):
+ """Go through each repository and re-fetch their listings"""
+
+ pass
+
+
+ def getProcessor(self, themesetid):
+ """Either return a cached processor, or load a processor"""
+
+ # XXX This might be a terrible idea. Need to make sure
+ # that lxml/libxml2 caching of XSLT processors doesn't
+ # vomit. If so, we just reload the processor on each request.
+ processor = self.cached_themesets.get(themesetid, None)
+ if processor is None or self.debug:
+ print "######## --- Reloading processor for", themesetid
+ # Need to load, store, and return the themeset
+ fn = "%s/themeset.xml" % themesetid
+ fullfn = os.path.join(self.storage_dir, fn)
+ themesetfn = os.path.join(fullfn)
+ dvng = DVNG(themesetfn)
+ processor = etree.XSLT(dvng.xslt)
+ self.cached_themesets[themesetid] = processor
+
+ return processor
+
+
+ def asXML(self):
+ """Give an XML representation of the themeset manager"""
+
+ ese = etree.SubElement
+ root = etree.Element("tsm")
+ local = ese(root, "local")
+ lthemes = (
+ ('plone', 'Plone', '3.1', '2008/03/03'),
+ ('nuplone', 'NuPlone', '3.0', '2007/11/23'),
+ )
+ for ts in lthemes:
+ theme = ese(local, "theme",
+ id=ts[0],
+ title=ts[1],
+ version=ts[2],
+ modified=ts[3],
+ )
+ if ts[0] == self.current_themesetid:
+ theme.set("current", "current")
+
+ # Eventually, contact the themeset global site and get a list
+ # of known themesets
+ publishers = ese(root, "publishers")
+ sites = ('plone.org', 'Theme Warehouse', 'Internal Project')
+ themes = (
+ ('elevatorplone', 'Plone for Elevators', '0.1', '2007/11/27'),
+ ('kittyplone', 'Hello Kitty', '0.8', '2006/02/19'),
+ )
+ for p in sites:
+ publisher = ese(publishers, 'publisher', title=p)
+ for t in themes:
+ theme = ese(publisher, "theme",
+ id=t[0], title=t[1], version=t[2],
+ modified=t[3])
+
+ return root
+
+if __name__ == "__main__":
+ tsm = ThemesetManager("../var/themesets")
+ print tsm.current_themeid(33)
Added: z3/deliverance/sandboxes/paul/dvplone/lib/utils.py
==============================================================================
--- (empty file)
+++ z3/deliverance/sandboxes/paul/dvplone/lib/utils.py Thu Jun 5 22:20:08 2008
@@ -0,0 +1,29 @@
+"""Standalone utility functions for DVNG middleware"""
+
+from lxml import etree
+
+def hasMarker(node_or_doc, marker, value=None):
+ """Return true or false if an HTML doc has a marker value"""
+
+ if value is None:
+ # Check for the existence of the marker, not the value
+ xpfmt = "head/meta[@name='%s' and @id='%s']'"
+ xp = xpfmt % ('marker', marker)
+ else:
+ # Confirm both the existence of the marker and a certain
+ # value
+ xpfmt = "head/meta[@name='%s' and @id='%s']/@content='%s'"
+ xp = xpfmt % ('marker', marker, value)
+
+ # Both xpaths resolve to True or False
+ return node_or_doc.xpath(xp)
+
+
+def setMarker(self, node_or_doc, markerid, value=None):
+ """Change content HTML to have a certain /html/head/meta"""
+
+ head = node_or_doc.xpath("head")[0]
+ marker = etree.SubElement(head, "meta", name="marker",
+ id=markerid, content=value)
+
+
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/contentcustom.xsl
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/contentcustom.xsl (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/contentcustom.xsl Thu Jun 5 22:20:08 2008
@@ -1,15 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
- <xsl:template match="/">
- <div>I overroad everything!</div>
- </xsl:template>
<xsl:template match="ul[@id='breadcrumbs']">
<div id="breadcrumbs">
- <strong>You are here: </strong>
+ <strong>You are here: </strong>
<xsl:for-each select="li/a">
- <a href="{@href}"><xsl:value-of select="."/></a>
+ <a href="{@href}">
+ <xsl:value-of select="."/>
+ </a>
<xsl:if test="position() != last()"> | </xsl:if>
</xsl:for-each>
</div>
</xsl:template>
+ <!-- For the DVNG management screen, support looking up "markers"
+ in the HTML and inserting some HTML, for example, the Themeset
+ Management UI. -->
+ <xsl:template match="div[@id='dv-manage']">
+ <xsl:variable name="marker" select="/html/head/object[@id='current-theme-list']"/>
+ <xsl:variable name="curr" select="$marker/*[@name='current-themeid']/@value"></xsl:variable>
+ <div id="dv-mgmtblurb">
+ <h4>Current Themeset: <xsl:value-of select="$marker/*[@name='current-themetitle']/@value"/></h4>
+ <form action="." method="post"> Change to: <select id="dv-newtheme" size="4">
+ <xsl:for-each select="$marker/param[@name='themeid']">
+ <option value="{@id}">
+ <xsl:if test="@id=$curr">
+ <xsl:attribute name="selected">selected</xsl:attribute>
+ </xsl:if>
+ <xsl:value-of select="@value"/>
+ </option>
+ </xsl:for-each>
+ </select>
+ <input value="Save" type="submit"/>
+ </form>
+ </div>
+ </xsl:template>
</xsl:stylesheet>
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themeset.xml
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themeset.xml (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themeset.xml Thu Jun 5 22:20:08 2008
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<?oxygen RNGSchema="themeset.rng" type="xml"?>
<themeset xmlns="http://openplans.org/deliverance">
+ <properties>
+ <id>nuplone</id>
+ <title>NuPlone</title>
+ <version>3.0</version>
+ <modified>2007/10/29</modified>
+ </properties>
<customizers theme="themecustom.xsl" content="contentcustom.xsl"/>
<theme href="themesource-tables.html">
<!-- A pretty theme with a sidebar -->
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themesource-plain.html
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themesource-plain.html (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/nuplone/themesource-plain.html Thu Jun 5 22:20:08 2008
@@ -5,6 +5,7 @@
body {margin: 3em;font-family:sans-serif;font-size:large}
#banner {background-color: silver; text-align: center; height: 1.5em; padding:0.5em}
</style>
+ <link rel="stylesheet" type="text/css" href="static/basic.css"/>
</head>
<body>
<h1 id="banner">I AM NUPLONE, HEAR ME ROAR</h1>
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/contentcustom.xsl
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/contentcustom.xsl (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/contentcustom.xsl Thu Jun 5 22:20:08 2008
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
- <xsl:template match="/">
+ <xsl:template match="/foo">
<div>I overroad everything!</div>
</xsl:template>
<xsl:template match="ul[@id='breadcrumbs']">
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themeset.xml
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themeset.xml (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themeset.xml Thu Jun 5 22:20:08 2008
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<?oxygen RNGSchema="themeset.rng" type="xml"?>
<themeset xmlns="http://openplans.org/deliverance">
+ <properties>
+ <id>plone</id>
+ <title>Plone</title>
+ <version>3.1</version>
+ <modified>2007/11/13</modified>
+ </properties>
<customizers theme="themecustom.xsl" content="contentcustom.xsl"/>
<theme href="themesource-tables.html">
<!-- A pretty theme with a sidebar -->
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-plain.html
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-plain.html (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-plain.html Thu Jun 5 22:20:08 2008
@@ -3,6 +3,7 @@
<title>Theme Page Title</title>
</head>
<body>
+ <h1 style="text-align: right">Plone, not NuPlone</h1>
<h1 id="pageheading">Theme Page Heading</h1>
<div id="pagecontent">
<p>Some sample theme content.</p>
Modified: z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-tables.html
==============================================================================
--- z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-tables.html (original)
+++ z3/deliverance/sandboxes/paul/dvplone/var/themesets/plone/themesource-tables.html Thu Jun 5 22:20:08 2008
@@ -3,6 +3,7 @@
<title>Second Theme Page Title</title>
</head>
<body>
+ <h1 style="text-align: right">Plone, not NuPlone</h1>
<table border="0" height="300" cellpadding="20">
<tr>
<td width="200" bgcolor="gray" valign="top">
More information about the z3-checkins
mailing list