RE: RE: Speeding up FTP upstreams

"Garth T Kidd" <garth-OnzZ1s1DREKDegMON/[email protected]> Sat, 31 Jul 2004 00:06:33 +1000
Newsgroups gmane.comp.pythin.pyds.devel
Organization Deadly Bloody Serious
Message-ID <[email protected]>
This is a multi-part message in MIME format.

------=_NextPart_000_009B_01C47692.3F040F70
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Here's another patch, chockers full of changes. PLEASE TEST BEFORE
APPLICATION: there's a lot of stuff in there. If you get into trouble,
delete the affected files (``Tool.py`` and ``WikiTool.py``) and ``cvs
update`` again to get 'em back.=20

All the changes are for the Wiki tool. Amongst them:=20

* Stray links PyDS-wide match against Wiki titles again. Oops.=20

* The toolbar is above the title, not between the title and the text. I
don't know what I was smoking, before.=20

* Breadcrumbs are generated, which is pretty handy for people like me =
that
tend to stack Wiki nodes inside each other rather than all alongside =
each
other. As usual, the user-visible breadcrumbs point to other pages. =
Yours
point back to the Wiki tool.=20

  TODO: add a way to turn them off. =20

* Along with the breadcrumbs, one level of subnodes are displayed.=20

  TODO: add a way to configure how deep to go, and to turn them off.=20

* There's MUCH better protection against adding nodes with invalid IDs.
Invalid IDs are adjusted before the node is saved. It's still saved, =
though,
so you won't end up caught out and losing data. You even get told why it =
was
changed, and have the opportunity to edit the ID again to fix it.=20

* If you're looking at a node and use the New button, you can set the =
parent
for the new node to be anywhere from the root of the Wiki to the node =
you
were just looking at. The default is to create a peer of the node you =
were
looking at. This is MUCH cleaner than hitting / a lot.=20

  TODO: make that the default for clicking on unresolved links, also.=20

  TODO: disable use of / inside the ID box now it's no longer necessary. =


* If you're using MSIE, try: Alt-N, Alt-E, Alt-V, and Alt-B. Whilst =
editing,
try Alt-S. All these have been there for ages, but I bet you didn't know
that. :)=20

* If the Wiki tool is set to level 0, you'll find the /wiki part of the =
path
isn't generated. It's all part of my Evil Plan. I'll tell you the rest
later.=20

Georg, can you suggest a better way to prevent ``addNode('index')`` in
``_initopts`` than I'm using? At present it's failing, I guess because =
the
tool level hasn't yet been set...=20

Regards,
Garth.=20

-----Original Message-----
From: pyds-dev-admin-iYtK5bfT9M//Ad8WF/[email protected]
[mailto:pyds-dev-admin-iYtK5bfT9M//Ad8WF/[email protected]] On Behalf Of Bauer, Georg
Sent: Friday, 30 July 2004 5:59 PM
To: 'Garth T Kidd'; 'List PyDS'
Cc: Peter Wilkinson
Subject: AW: [Pyds-dev] RE: Speeding up FTP upstreams

Hi!

His problems arise in the MirrorTool. That uses the RSS methods to fetch
items from tools that are hooked into the mirroring. For example =
mirroring
is used for the cloud search engine. Why PyDS thinks there is some =
posting
that doesn't exist is beyond me - Peter does have a bit weird =
installation,
so maybe his data file is borked.

Garth: I added both your patches. I changed the patch to getRSSItem, =
though,
because you returned None. If people access methods via XMLRPC, this =
would
pose a problem, as None can't be transported by XMLRPC, so I changed the
return value to {} (empty hash).

bye, Georg

-----Urspr=FCngliche Nachricht-----
Von: Garth T Kidd [mailto:garth-OnzZ1s1DREKDegMON/[email protected]]
Gesendet: Freitag, 30. Juli 2004 07:19
An: 'List PyDS'
Cc: Peter Wilkinson
Betreff: [Pyds-dev] RE: Speeding up FTP upstreams


I'm not entirely sure why WeblogTool is trying to RSS-render items that
don't exist, but hopefully the attached patch will help Peter's =
`upstreaming
woes`__.

__ http://www.pycs.net/users/0000348/weblog/2004/07/28.html#P403

Regards,
Garth.=20

_______________________________________________
Pyds-dev mailing list
Pyds-dev-iYtK5bfT9M//Ad8WF/[email protected]
http://www.westfalen.de/cgi-bin/mailman/listinfo/pyds-dev

------=_NextPart_000_009B_01C47692.3F040F70
Content-Type: application/octet-stream;
	name="20040730-2342-ratherlarge.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="20040730-2342-ratherlarge.diff"

? .pyds.css.swp
? Settings
? Thumbs.db
? and
? in.txt
? out.txt
? testSomething.py
? PyDS/.Tool.py.swp
Index: pyds.css
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /pyds/PyDS/pyds.css,v
retrieving revision 1.24
diff -c -r1.24 pyds.css
*** pyds.css	6 Jul 2004 08:30:36 -0000	1.24
--- pyds.css	30 Jul 2004 12:54:21 -0000
***************
*** 29,34 ****
--- 29,38 ----
  */
 =20
  /* basic styles */
+ #toolbar input {
+ 	text-padding: 1px;
+ 	font-size: 10px;
+ }
  body {
  	font-family: verdana, sans-serif;
  	background-color: white;
***************
*** 141,146 ****
--- 145,162 ----
  	padding: 0.25em;
  	text-align: right;
  	font-size: 0.8em;
+ }
+ .wikicrumbs {
+ 	background-color: #f0fff0;
+ 	/* border: solid;
+ 	border-color: green;
+ 	border-width: 1px; */
+ 	padding: 0.25em;
+ 	text-align: left;
+ 	font-size: 0.8em;
+ }
+ .undefinedwikicrumb {
+ 	color: red;=20
  }
 =20
  /* message/text styles */
Index: PyDS/MeshTool.py
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /pyds/PyDS/PyDS/MeshTool.py,v
retrieving revision 1.27
diff -c -r1.27 MeshTool.py
*** PyDS/MeshTool.py	14 Jul 2004 15:55:18 -0000	1.27
--- PyDS/MeshTool.py	20 Jul 2004 06:14:32 -0000
***************
*** 396,402 ****
  		instance. The latter should have already been walked over the
  		document. `itemDetail` should be an `ItemDetail` object =
corresponding=20
  		to the source being rendered, or None."""
! 		PyDS.Tool.traceargs()
  		docutils.nodes.SparseNodeVisitor.__init__(self, document)
  		self.targetVisitor =3D targetVisitor
  		self.foundTools =3D toolsWithStrayLinkResolvers()
--- 396,402 ----
  		instance. The latter should have already been walked over the
  		document. `itemDetail` should be an `ItemDetail` object =
corresponding=20
  		to the source being rendered, or None."""
! 		# PyDS.Tool.traceargs()
  		docutils.nodes.SparseNodeVisitor.__init__(self, document)
  		self.targetVisitor =3D targetVisitor
  		self.foundTools =3D toolsWithStrayLinkResolvers()
Index: PyDS/Tool.py
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /pyds/PyDS/PyDS/Tool.py,v
retrieving revision 1.192
diff -c -r1.192 Tool.py
*** PyDS/Tool.py	15 Jul 2004 14:10:01 -0000	1.192
--- PyDS/Tool.py	30 Jul 2004 13:49:54 -0000
***************
*** 1728,1745 ****
  		mainindex =3D 0
  		if toolname =3D=3D None:
  			toolname =3D self.name
  		if year and month and day:
! 			dn =3D os.path.join(_PyDS.ROOTDIR, toolname, category,
  				'%04d' % year,
  				'%02d' % month)
  			fn =3D os.path.join(dn, '%02d.html' % day)
  		elif year and month:
! 			dn =3D os.path.join(_PyDS.ROOTDIR, toolname, category,
  				'%04d' % year,
  				'%02d' % month)
  			fn =3D os.path.join(dn, page)
  		else:
! 			dn =3D os.path.join(_PyDS.ROOTDIR, toolname, category)
  			d, f =3D os.path.split(page) # WikiTool specifying paths in `page`
  			if d:=20
  				dn =3D os.path.join(dn, d)
--- 1728,1749 ----
  		mainindex =3D 0
  		if toolname =3D=3D None:
  			toolname =3D self.name
+ 		if toolname =3D=3D 'wiki' and self.level =3D=3D 0:=20
+ 			toolRoot =3D _PyDS.ROOTDIR
+ 		else:=20
+ 			toolRoot =3D os.path.join(_PyDS.ROOTDIR, toolname)
  		if year and month and day:
! 			dn =3D os.path.join(toolRoot, category,
  				'%04d' % year,
  				'%02d' % month)
  			fn =3D os.path.join(dn, '%02d.html' % day)
  		elif year and month:
! 			dn =3D os.path.join(toolRoot, category,
  				'%04d' % year,
  				'%02d' % month)
  			fn =3D os.path.join(dn, page)
  		else:
! 			dn =3D os.path.join(toolRoot, category)
  			d, f =3D os.path.split(page) # WikiTool specifying paths in `page`
  			if d:=20
  				dn =3D os.path.join(dn, d)
***************
*** 1854,1860 ****
  	# get flat filenames instead of structured directories. This is
  	# usefull for exports to CD-ROM or stuff like that. In that case,
  	# base is usually '/'
! 	def getStaticUrl(self, page=3DNone, tool=3DNone, year=3DNone, =
month=3DNone, day=3DNone, category=3D'', base=3DNone, flat=3D0):
  		if not(page) and year and month and day:
  			page =3D '%04d/%02d/%02d.html' % (year, month, day)
  		elif not(page) and year and month:
--- 1858,1865 ----
  	# get flat filenames instead of structured directories. This is
  	# usefull for exports to CD-ROM or stuff like that. In that case,
  	# base is usually '/'
! 	def getStaticUrl(self, page=3DNone, tool=3DNone, year=3DNone, =
month=3DNone, day=3DNone, category=3D'', base=3DNone, flat=3D0, =
stripToolPrefix=3D0):
! 		# traceargs()
  		if not(page) and year and month and day:
  			page =3D '%04d/%02d/%02d.html' % (year, month, day)
  		elif not(page) and year and month:
***************
*** 1865,1870 ****
--- 1870,1876 ----
  			tool =3D self.getToolByNamespace(tool)
  		else:
  			tool =3D self
+ 		# PyDS.Tool.debugOutput("tool level: %d" % tool.level)
  		if not(base):
  			upstream =3D self.getToolByNamespace('upstream')
  			base =3D upstream.get('prefs','cloudurl')
***************
*** 1878,1888 ****
  			else:
  				return '%s%s-%s' % (base, tool.name, page)
  		else:
  			url =3D ''
  			if category:
! 				url =3D '%s%s/%s/%s' % (base, tool.name, category, page)
  			else:
! 				url =3D '%s%s/%s' % (base, tool.name, page)
  			if len(url) >=3D 11 and url[-11:] =3D=3D '/index.html':
  				url =3D url[:-10]
  			return url
--- 1884,1899 ----
  			else:
  				return '%s%s-%s' % (base, tool.name, page)
  		else:
+ 			# print "Tool level: %d" % tool.level
+ 			if stripToolPrefix and tool.level=3D=3D0:=20
+ 				toolPart =3D ''
+ 			else:=20
+ 				toolPart =3D '%s/' % tool.name
  			url =3D ''
  			if category:
! 				url =3D '%s%s%s/%s' % (base, toolPart, category, page)
  			else:
! 				url =3D '%s%s%s' % (base, toolPart, page)
  			if len(url) >=3D 11 and url[-11:] =3D=3D '/index.html':
  				url =3D url[:-10]
  			return url
Index: PyDS/WikiTool.py
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /pyds/PyDS/PyDS/WikiTool.py,v
retrieving revision 1.26
diff -c -r1.26 WikiTool.py
*** PyDS/WikiTool.py	15 Jul 2004 22:08:09 -0000	1.26
--- PyDS/WikiTool.py	30 Jul 2004 13:33:52 -0000
***************
*** 78,94 ****
  	def _initopts(self):
  		self.rss =3D 1
  		self.showCalendar =3D0=20
! 		if self._getNode('index') is None:=20
  			# If I add a preference for rendering Wiki pages to the main site=20
  			# rather than a tool-specific subdirectory, I'll need to suppress=20
  			# automatic creation of this file.=20
  			self.addNode('index',=20
  			             _("Wiki Index"),=20
! 				     _("Edit this page to begin your Wiki"))
  		if self._getNode('404') is None:=20
  			self.addNode('404',=20
  			             _("Unresolved Target"),=20
! 				     _("Not-yet-resolved links in the Wiki are pointed here."))
  =09
  	def _initactive(self):
  		navigation =3D self.getToolByNamespace('navigation')
--- 78,94 ----
  	def _initopts(self):
  		self.rss =3D 1
  		self.showCalendar =3D0=20
! 		if self.level>0 and self._getNode('index') is None:=20
  			# If I add a preference for rendering Wiki pages to the main site=20
  			# rather than a tool-specific subdirectory, I'll need to suppress=20
  			# automatic creation of this file.=20
  			self.addNode('index',=20
  			             _("Wiki Index"),=20
! 			             _("Edit this page to begin your Wiki"))
  		if self._getNode('404') is None:=20
  			self.addNode('404',=20
  			             _("Unresolved Target"),=20
! 			             _("Not-yet-resolved links in the Wiki are pointed =
here."))
  =09
  	def _initactive(self):
  		navigation =3D self.getToolByNamespace('navigation')
***************
*** 156,168 ****
  	# this method returns an URL to the cloud in the context of the =
current tool
  	# or the given tool. Weblog patches the URL if radio compatibility is =
requested.
  	def getStaticUrl(self, page=3DNone, tool=3DNone, year=3DNone, =
month=3DNone, day=3DNone, category=3D'', base=3DNone, flat=3D0):
! 		if filter(None, (year, month, day, category)):=20
! 			pass # aah, ignore it for the time being=20
! 			# raise NotImplementedError, _("argument not supported by Wiki =
tool")
! 		if page is None:=20
! 			pass # aah, ignore it for the time being
! 			# raise ValueError, _("page argument required by Wiki tool")
! 		url =3D PyDS.Tool.StandardTool.getStaticUrl(self, page, tool, year, =
month, day, category, base, flat)
  		return url
 =20
  	# This method returns the URL for a node. Depending on context it
--- 156,165 ----
  	# this method returns an URL to the cloud in the context of the =
current tool
  	# or the given tool. Weblog patches the URL if radio compatibility is =
requested.
  	def getStaticUrl(self, page=3DNone, tool=3DNone, year=3DNone, =
month=3DNone, day=3DNone, category=3D'', base=3DNone, flat=3D0):
! 		url =3D PyDS.Tool.StandardTool.getStaticUrl(self, page, tool, year,=20
! 		                                          month, day, category,=20
! 												  base, flat, stripToolPrefix=3D1)
! 		# PyDS.Tool.debugOutput("=3D> %s" % url)
  		return url
 =20
  	# This method returns the URL for a node. Depending on context it
***************
*** 210,216 ****
  			# baseid match
  			lambda: baseid =3D=3D m,=20
  			# title match
! 			lambda: m =3D=3D _munge(node.title()),
  			)
 =20
  		# prepare filter results dictionary
--- 207,213 ----
  			# baseid match
  			lambda: baseid =3D=3D m,=20
  			# title match
! 			lambda: m =3D=3D _munge(node.title),
  			)
 =20
  		# prepare filter results dictionary
***************
*** 278,286 ****
  	# Return a link to a creation page for an item, based on link text.=20
  	def getDesktopCreateLinkDetailsForProposedLinkText(self, linkText):=20
  		"""Return the edit URL for a non-existent item, based on =
`linkText`."""
  		return ('undefinednode',=20
! 		        self.getUrl('edit_html', id=3D_munge(linkText)),
! 			_("Create this item in WikiTool"))
 =20
  	# Render an item by its unique ID
  	def renderItemByUniqueId(self, uniqueId):
--- 275,296 ----
  	# Return a link to a creation page for an item, based on link text.=20
  	def getDesktopCreateLinkDetailsForProposedLinkText(self, linkText):=20
  		"""Return the edit URL for a non-existent item, based on =
`linkText`."""
+ 		# split linkText into words on whitespace
+ 		words =3D re.split(r"\s+", str(linkText))
+ 		# remove non-alphanumerics from each word
+ 		words =3D [re.sub(r"\W", '', word) for word in words]
+ 		# capitalise each word
+ 		words =3D [word[0:1].upper() + word[1:].lower() for word in words]
+ 		# string 'em together
+ 		id =3D ''.join(words)
+ 		# figure out our Wiki context, and prepend it if found
+ 		concatid =3D _flet.get('categoryid', '').lower()
+ 		if concatid:=20
+ 			id =3D '/'.join(concatid, id)
+ 		# et voila!=20
  		return ('undefinednode',=20
! 		        self.getUrl('edit_html', id=3Did),
! 		        _("Create this item in WikiTool"))
 =20
  	# Render an item by its unique ID
  	def renderItemByUniqueId(self, uniqueId):
***************
*** 323,333 ****
  		html =3D [_("<h3>Your Wiki Nodes</h3>")]
  		append =3D html.append
  		editvars =3D {
! 			'edit_html': self.getUrl('edit_html'),
  			'editlabel': _("New")
  		}
! 		append('<form action=3D"%(edit_html)s" method=3D"GET">' % editvars)
! 		append('<input type=3D"submit" value=3D"%(editlabel)s" =
accesskey=3D"n">' % editvars)
  		hashedNodes =3D {}
  		for node in self.nodes:=20
  			nids =3D _splitPath(node.id)
--- 333,344 ----
  		html =3D [_("<h3>Your Wiki Nodes</h3>")]
  		append =3D html.append
  		editvars =3D {
! 			'edit_html': self.getUrl('mux_redir'),=20
  			'editlabel': _("New")
  		}
! 		append('<div id=3D"toolbar"><form action=3D"%(edit_html)s" =
method=3D"POST">' % editvars)
! 		append('<input type=3D"submit" name=3D"WikiNew" =
value=3D"%(editlabel)s" accesskey=3D"n"></div>' % editvars)
!=20
  		hashedNodes =3D {}
  		for node in self.nodes:=20
  			nids =3D _splitPath(node.id)
***************
*** 371,376 ****
--- 382,392 ----
  		macros =3D self.getToolByNamespace('macros')
  		id =3D req.getFirstValue('id')
  		node =3D self.getNode(id)
+ 		subnodes =3D req.getFirstValue('subnodes')
+ 		if 1: # subnodes and subnodes=3D=3D'yes':=20
+ 			subnodehtml =3D self.renderSubNodes(id, depthLimit=3D1)
+ 		else:=20
+ 			subnodehtml =3D ''
  		template =3D ''
  		if node.get('template',0):
  			template =3D _(' (Template)')
***************
*** 378,402 ****
  		# _flet.begin(categoryid=3Dnode.get('categoryid',''), id=3Did)
  		rendered =3D req.renderText(
  			node.get('text',_('This node has no text.')),=20
! 			structured =3D 1,
  			uniqueId =3D id,=20
! 			homeTool =3D self)
! 		# breadcrumbs
! 		nids =3D _splitPath(id)
! 		sofar =3D ''
! 		crumbs =3D ['<strong><a href=3D"%s">%s</a></strong>' % =
(self.getUrl('index_html'), _('Wiki'))]
! 		for nid in nids:=20
! 			if sofar:=20
! 				sofar =3D sofar + '/' + nid
! 			else:=20
! 				sofar =3D nid
! 			if self._getNode(sofar) is None:=20
! 				cssclass =3D 'undefinednode'
! 			else:=20
! 				cssclass =3D 'node'
! 			crumbs.append('<a class=3D"%s" href=3D"%s">%s</a>' % (
! 				cssclass, self.getUrl('show_html', id=3Dsofar), nid
! 			))
  		viewhtml =3D ''
  		if not(node.get('template',0)):
  			viewhtml =3D '<input type=3D"submit" name=3D"WikiView" =
value=3D"%(viewlabel)s" accesskey=3D"v">' % {
--- 394,402 ----
  		# _flet.begin(categoryid=3Dnode.get('categoryid',''), id=3Did)
  		rendered =3D req.renderText(
  			node.get('text',_('This node has no text.')),=20
! 			structured =3D 2, # TODO: check 'structured' pref
  			uniqueId =3D id,=20
! 			homeTool =3D self)=20
  		viewhtml =3D ''
  		if not(node.get('template',0)):
  			viewhtml =3D '<input type=3D"submit" name=3D"WikiView" =
value=3D"%(viewlabel)s" accesskey=3D"v">' % {
***************
*** 404,430 ****
  				'viewurl': self.getStaticUrl(page=3D'%s.html' % id),
  			}
  		html =3D """\
! <p>%(crumbs)s</p>
! <h2>%(title)s%(template)s</h2>
! <form action=3D"%(mux_redir)s" method=3D"POST">
  <input type=3D"hidden" name=3D"id" value=3D"%(id)s">
  <input type=3D"submit" name=3D"WikiEdit" value=3D"%(editlabel)s" =
accesskey=3D"e">
  <input type=3D"submit" name=3D"WikiDelete" value=3D"%(deletelabel)s">
  %(viewhtml)s
  <input type=3D"submit" name=3D"WikiClone" value=3D"%(clonelabel)s" =
accesskey=3D"c">
  <input type=3D"submit" name=3D"WikiBlog" value=3D"%(bloglabel)s" =
accesskey=3D"b">
! </form>
  %(rendered)s
  <p align=3D"right" class=3D"smallfont">%(lastlabel)s =
%(pubtimestr)s</p>
  <p align=3D"right"><a href=3D"%(toolurl)s" =
accesskey=3D"i">%(index)s</a></p>""" % {
! 			'title': node.get('title',_('Set your page title here')),=20
! 			'crumbs': '&nbsp;/&nbsp;'.join(crumbs),=20
  			'mux_redir': self.getUrl('mux_redir'),
  			'id': str(id),=20
  			'editlabel': _("Edit"),=20
  			'deletelabel': _("Delete"),=20
  			'clonelabel': _("Clone"),
  			'bloglabel': _("Blog"),
  			'rendered': rendered,=20
  			'lastlabel': _("last change"),=20
  			'pubtimestr': macros.Today(node.get('pubtime',time.time()), =
withtime=3D1),=20
--- 404,438 ----
  				'viewurl': self.getStaticUrl(page=3D'%s.html' % id),
  			}
  		html =3D """\
! %(breadcrumbs)s
! %(subnodes)s
! <div id=3D"toolbar"><form action=3D"%(mux_redir)s" method=3D"POST">
  <input type=3D"hidden" name=3D"id" value=3D"%(id)s">
+ <input type=3D"hidden" name=3D"concatid" value=3D"%(concatid)s">
+ <input type=3D"submit" name=3D"WikiNew" value=3D"%(newlabel)s" =
accesskey=3D"n">
  <input type=3D"submit" name=3D"WikiEdit" value=3D"%(editlabel)s" =
accesskey=3D"e">
  <input type=3D"submit" name=3D"WikiDelete" value=3D"%(deletelabel)s">
  %(viewhtml)s
  <input type=3D"submit" name=3D"WikiClone" value=3D"%(clonelabel)s" =
accesskey=3D"c">
  <input type=3D"submit" name=3D"WikiBlog" value=3D"%(bloglabel)s" =
accesskey=3D"b">
! <!-- input type=3D"submit" name=3D"WikiSubNodes" =
value=3D"%(subnodeslabel)s" accesskey=3D"s" -->
! </form></div>
! <h2>%(title)s%(template)s</h2>
  %(rendered)s
  <p align=3D"right" class=3D"smallfont">%(lastlabel)s =
%(pubtimestr)s</p>
  <p align=3D"right"><a href=3D"%(toolurl)s" =
accesskey=3D"i">%(index)s</a></p>""" % {
! 			'title': cgi.escape(node.get('title',_('Set your page title =
here'))),=20
! 			'breadcrumbs': self.renderBreadCrumbs(id, startWithTool=3D1),=20
! 			'subnodes': subnodehtml,=20
  			'mux_redir': self.getUrl('mux_redir'),
  			'id': str(id),=20
+ 			'concatid': '/'.join(_splitPath(str(id))[:-1]),=20
+ 			'newlabel': _("New"),=20
  			'editlabel': _("Edit"),=20
  			'deletelabel': _("Delete"),=20
  			'clonelabel': _("Clone"),
  			'bloglabel': _("Blog"),
+ 			'subnodeslabel': _("SubNodes"),
  			'rendered': rendered,=20
  			'lastlabel': _("last change"),=20
  			'pubtimestr': macros.Today(node.get('pubtime',time.time()), =
withtime=3D1),=20
***************
*** 440,445 ****
--- 448,460 ----
  		id =3D req.getFirstValue('id')
  		if not id:=20
  			id =3D ''
+ 		if req.getFirstValue('WikiNew'):=20
+ 			concatid =3D id # req.getFirstValue('concatid')
+ 			if concatid:=20
+ 				id =3D concatid + '/<new node>'
+ 			else:=20
+ 				id =3D '<new node>'
+ 			return self.getUrl('edit_html', id=3Dstr(id), title=3D'', =
text=3D'')
  		if req.getFirstValue('WikiEdit'):=20
  			return self.getUrl('edit_html', id=3Dstr(id))
  		if req.getFirstValue('WikiClone'):=20
***************
*** 455,460 ****
--- 470,477 ----
  				ptitle=3Dnode['title'],
  				plink=3Dself.getStaticUrl(page=3D'%s.html' % id)
  			)
+ 		if req.getFirstValue('WikiSubNodes'):=20
+ 			return self.getUrl('show_html', id=3Dstr(id), subnodes=3D'yes')
  		return self.getUrl('show_html', id=3Dstr(id))
 =20
  	def delete_html(self, req):
***************
*** 462,475 ****
  		id =3D req.getFirstValue('id')
  		node =3D self.getNode(id)
  		html =3D """\
! %(rendered)s
! <form action=3D"%(delete_redir)s" method=3D"POST">
  <input type=3D"hidden" name=3D"id" value=3D"%(id)s">
  <input type=3D"submit" name=3D"WikiDeleteConfirm" =
value=3D"%(confirmlabel)s" accesskey=3D"d">
  <input type=3D"submit" name=3D"WikiDeleteCancel" =
value=3D"%(cancellabel)s" accesskey=3D"c">
! </form>
  <p align=3D"right" class=3D"smallfont">%(lastlabel)s =
%(pubtimestr)s</p>""" % {
! 			'title': node['title'],=20
  			'show_html': self.getUrl('show_html', id=3Dstr(id)),=20
  			'delete_redir': self.getUrl('delete_redir', id=3Dstr(id)),=20
  			'id': str(id),=20
--- 479,494 ----
  		id =3D req.getFirstValue('id')
  		node =3D self.getNode(id)
  		html =3D """\
! %(breadcrumbs)s
! <div id=3D"toolbar"><form action=3D"%(delete_redir)s" method=3D"POST">
  <input type=3D"hidden" name=3D"id" value=3D"%(id)s">
  <input type=3D"submit" name=3D"WikiDeleteConfirm" =
value=3D"%(confirmlabel)s" accesskey=3D"d">
  <input type=3D"submit" name=3D"WikiDeleteCancel" =
value=3D"%(cancellabel)s" accesskey=3D"c">
! </form></div>
! <h2>%(title)s</h2>
! %(rendered)s
  <p align=3D"right" class=3D"smallfont">%(lastlabel)s =
%(pubtimestr)s</p>""" % {
! 			'title': cgi.escape(node['title']),=20
  			'show_html': self.getUrl('show_html', id=3Dstr(id)),=20
  			'delete_redir': self.getUrl('delete_redir', id=3Dstr(id)),=20
  			'id': str(id),=20
***************
*** 477,489 ****
  			'confirmlabel': _("Confirm Deletion"),=20
  			'rendered': req.renderText(
  				node['text'],=20
! 				structured =3D 1,=20
  				#categoryid=3Dnode['categoryid'],=20
  				#id=3Did,
  				uniqueId =3D id,=20
  				homeTool =3D self),
  			'lastlabel': _("last change"),=20
  			'pubtimestr': macros.Today(node['pubtime'], withtime=3D1),=20
  		}
  		req.setLocalValue('title', node['title'])
  		return req.renderPage('BaseTemplate', body=3Dhtml, title=3D"Wiki: =
Delete: %s" % node.get('title', '(no title)'))
--- 496,509 ----
  			'confirmlabel': _("Confirm Deletion"),=20
  			'rendered': req.renderText(
  				node['text'],=20
! 				structured =3D 2, # TODO: check 'structured' pref
  				#categoryid=3Dnode['categoryid'],=20
  				#id=3Did,
  				uniqueId =3D id,=20
  				homeTool =3D self),
  			'lastlabel': _("last change"),=20
  			'pubtimestr': macros.Today(node['pubtime'], withtime=3D1),=20
+ 			'breadcrumbs': self.renderBreadCrumbs(id, startWithTool=3D1),
  		}
  		req.setLocalValue('title', node['title'])
  		return req.renderPage('BaseTemplate', body=3Dhtml, title=3D"Wiki: =
Delete: %s" % node.get('title', '(no title)'))
***************
*** 517,536 ****
  				node['title'] =3D self.getNode(template)['title']
  				node['text'] =3D self.getNode(template)['text']
  		values =3D {}=20
! 		for field in ['id', 'title', 'text']:=20
! 			value =3D cgi.escape(node.get(field,id))
! 			values[field+'value'] =3D value
  		for field in ['Id', 'Title', 'Text', 'delete', 'save']:=20
  			values[field.lower()+'label'] =3D _(field)
  		values['edit_redir'] =3D self.getUrl('edit_redir')
  		values['templatelabel'] =3D _('Template')
  		values['templateselect'] =3D macros.checkBox('template', =
node.get('template',0))
  		html =3D """
  <form action=3D"%(edit_redir)s" method=3D"POST">
  <table border=3D0>
  <tr>
    <th align=3D"right">%(idlabel)s</th>
!   <td><input name=3D"oldid" value=3D"%(idvalue)s" type=3D"hidden">
        <input name=3D"id" value=3D"%(idvalue)s" size=3D50></td>
  </tr><tr>
    <th align=3D"right">%(titlelabel)s</th>
--- 537,592 ----
  				node['title'] =3D self.getNode(template)['title']
  				node['text'] =3D self.getNode(template)['text']
  		values =3D {}=20
! 		values['idvalue'] =3D node.get('id', id)
! 		values['titlevalue'] =3D node.get('title', '')
! 		values['textvalue'] =3D node.get('text', '')
  		for field in ['Id', 'Title', 'Text', 'delete', 'save']:=20
  			values[field.lower()+'label'] =3D _(field)
  		values['edit_redir'] =3D self.getUrl('edit_redir')
  		values['templatelabel'] =3D _('Template')
  		values['templateselect'] =3D macros.checkBox('template', =
node.get('template',0))
+ 	=09
+ 		# Make a copy of the full ID before we truncate it
+ 		values['oldidvalue'] =3D values['idvalue']
+ 	=09
+ 		# Try and figure out the context selector
+ 		catids =3D []
+ 		segs =3D _splitPath(id)
+ 		values['idvalue'] =3D segs[-1]
+ 		for seg in segs[:-1]:=20
+ 			if catids:=20
+ 				catids.append('%s/%s' % (catids[-1], seg))
+ 			else:=20
+ 				catids.append(seg)
+ 		catids.reverse()
+ 		catids.append(_("(The Wiki)"))
+ 		if node or len(catids)<2:=20
+ 			catidvalue =3D catids[0]
+ 		else:=20
+ 			catidvalue =3D catids[1]
+ 		values['breadcrumbs'] =3D self.renderBreadCrumbs(catids[0], =
startWithTool=3D1)
+ 		catidoptions =3D []
+ 		for catid in catids:=20
+ 			if catid =3D=3D catidvalue:=20
+ 				selected =3D ' selected'
+ 			else:=20
+ 				selected =3D ''
+ 			catidoptions.append('<option value=3D"%s"%s>%s</option>' % (
+ 				cgi.escape(catid), selected, cgi.escape(catid)))
+ 		values['catidoptions'] =3D '\n'.join(catidoptions)
+=20
+ 		# Now for the text
  		html =3D """
+ %(breadcrumbs)s
  <form action=3D"%(edit_redir)s" method=3D"POST">
  <table border=3D0>
  <tr>
+   <th align=3D"right">Context</th>
+   <td><select name=3D"catid">%(catidoptions)s
+ </select></td>
+ </tr><tr>
    <th align=3D"right">%(idlabel)s</th>
!   <td><input name=3D"oldid" value=3D"%(oldidvalue)s" type=3D"hidden">
        <input name=3D"id" value=3D"%(idvalue)s" size=3D50></td>
  </tr><tr>
    <th align=3D"right">%(titlelabel)s</th>
***************
*** 561,585 ****
  		self.deleteNode(id)
  		return self.getUrl()
 =20
  	def edit_redir(self, req):
! 		id, oldid, title, text, desc, template =3D map(req.getFirstValue,=20
! 			('id', 'oldid', 'title', 'text', 'desc', 'template'))
! 		id =3D _normPath(id)
  		if req.getFirstValue('WikiDelete'):
  			return self.getUrl('delete_html', id=3Dstr(id))
  		else:
  			if not id:
  				id =3D ''
! 			if oldid and text and oldid !=3D id:=20
! 				self.renameNode(oldid, id, renderNew=3D0)
! 			if id and text:
! 				id =3D self.addNode(id, title, text, template=3Dint(template))
! 				return self.getUrl('show_html', id=3Dstr(id))
! 			else:
  				if id:
  					return self.getUrl('edit_html', id=3Dstr(id), errmsg=3D_('You =
need to give id and text!'))
  				else:
  					return self.getUrl('edit_html', errmsg=3D_('You need to give id =
and text!'))
 =20
  	# this method renames an existing node
  	def renameNode(self, id, newid, renderNew=3D1):=20
--- 617,683 ----
  		self.deleteNode(id)
  		return self.getUrl()
 =20
+ 	def invalid_id(self, id):=20
+ 		"Is the ID invalid? Why?"
+ 		if ' ' in id:=20
+ 			return _("Spaces not allowed.")
+ 		if re.match(r"^[\\\/].*", id):=20
+ 			return _("Can't start with a slash.")
+ 		if re.match(r"^.*[\\\/]$", id):=20
+ 			return _("Can't end with a slash.")
+ 		if not re.match(r"^\w+([\\\/]\w+)*$", id):=20
+ 			return _("Can't figure out exactly why. Probably a non-alphanumeric =
character.")
+ 		splits =3D _splitPath(id)
+ 		first =3D splits[0]
+ 		try:=20
+ 			tool =3D self.getToolByNamespace(first.lower())=20
+ 			return _("First path component %s conflicts with a tool name") % =
repr(first)
+ 		except KeyError:=20
+ 			pass
+ 		if re.match(r"^[0-9]{4}$", first):=20
+ 			return _("First path component %s might conflict with a year") % =
repr(first)
+ 		return ''
+=20
+ 	def fixid(self, id):=20
+ 		"Return a FixId for the invalid id."
+ 		if id:=20
+ 			return '%s%s' % (
+ 				   time.strftime("%Y%m%d%H%M_"),=20
+ 				   _munge(id))
+ 		else:
+ 			return ''
+ 	=09
  	def edit_redir(self, req):
! 		catid, id, oldid, title, text, desc, template =3D =
map(req.getFirstValue,=20
! 			('catid', 'id', 'oldid', 'title', 'text', 'desc', 'template'))
  		if req.getFirstValue('WikiDelete'):
  			return self.getUrl('delete_html', id=3Dstr(id))
  		else:
  			if not id:
  				id =3D ''
! 			errmsg =3D self.invalid_id(id)
! 			if errmsg:=20
! 				id =3D self.fixid(id)
! 			# if we have a context, use it -- unless it starts with a=20
! 			# bracket, in which case the context is the Wiki itself
! 			if catid and catid[0] !=3D '(':=20
! 				id =3D '/'.join((catid, id))
! 			if not text:=20
  				if id:
  					return self.getUrl('edit_html', id=3Dstr(id), errmsg=3D_('You =
need to give id and text!'))
  				else:
  					return self.getUrl('edit_html', errmsg=3D_('You need to give id =
and text!'))
+ 			id =3D _normPath(id)
+ 			if oldid and text and oldid !=3D id:=20
+ 				self.renameNode(oldid, id, renderNew=3D0)
+ 			id =3D self.addNode(id, title, text, template=3Dint(template))
+ 			if errmsg:=20
+ 				errmsg =3D ' '.join([
+ 					_("Adjusted invalid ID before saving your record: "),=20
+ 					errmsg])
+ 				return self.getUrl('edit_html', id=3Dstr(id), errmsg=3Derrmsg)
+ 			else:=20
+ 				return self.getUrl('show_html', id=3Dstr(id))
 =20
  	# this method renames an existing node
  	def renameNode(self, id, newid, renderNew=3D1):=20
***************
*** 611,616 ****
--- 709,715 ----
  			meshTool.delItem(id, self)
  		finally: self._release()
 =20
+ 	# This method deletes the rendered output for a given node.=20
  	def _deleteRenderedNode(self, id, dummy):
  		self.logVerbose("Deleting rendered output for Wiki node %s", id)
  		self.deleteFile('%s.html' % id)
***************
*** 624,632 ****
  		=09
  	# Internal getNode; returns the row, not a dict.
  	def _getNode(self, id):=20
! 		(res,found) =3D self.nodes.locate({'id':id})
! 		if found: return self.nodes[res]
! 		else: return None
 =20
  	# get a posting by ID
  	def getNode(self, id):
--- 723,738 ----
  		=09
  	# Internal getNode; returns the row, not a dict.
  	def _getNode(self, id):=20
! 		try:
! 			# self._acquire()
! 			(res,found) =3D self.nodes.locate({'id':id})
! 			if found:=20
! 				return self.nodes[res]
! 			else:=20
! 				return None
! 		finally:=20
! 			# self._release
! 			pass
 =20
  	# get a posting by ID
  	def getNode(self, id):
***************
*** 776,782 ****
--- 882,980 ----
  				msg +=3D '<br>%s[%s] in %s' % (file, line, function)
  			self.logError(msg.replace('%', '%%'))
 =20
+ 	def renderBreadCrumbs(self, id, startWithTool=3D0, skipLevels=3D0, =
nodiv=3D0):=20
+ 		nids =3D _splitPath(id)
+ 		sofar =3D ''
+ 		crumbs =3D []
+ 		if startWithTool:=20
+ 			crumbs.append('<strong><a href=3D"%s" =
class=3D"wikicrumb">%s</a></strong>' % (
+ 				self.getUrl('index_html'), _('Wiki')))
+ 		levels =3D 0
+ 		for nid in nids:=20
+ 			if sofar:=20
+ 				sofar =3D sofar + '/' + nid
+ 			else:=20
+ 				sofar =3D nid
+ 			levels =3D levels + 1
+ 			if levels <=3D skipLevels:
+ 				continue
+ 			found =3D self._getNode(sofar) is not None
+ 			if not _flet.desktop:=20
+ 				if found:=20
+ 					cssclass =3D 'wikicrumb'
+ 					target =3D self.getCloudUrlForNode(sofar)
+ 					crumbs.append('<a class=3D"%s" href=3D"%s">%s</a>' % (
+ 						cssclass, target, nid))
+ 				else:=20
+ 					cssclass =3D 'undefinedwikicrumb'
+ 					crumbs.append('<span class=3D"%s">%s</span>' % (
+ 						cssclass, nid))
+ 			else:=20
+ 				if found:=20
+ 					cssclass =3D 'wikicrumb'
+ 					target =3D self.getCloudUrlForNode(sofar)
+ 				else:=20
+ 					cssclass =3D 'undefinedwikicrumb'
+ 					target =3D self.getUrl('show_html', id=3Dsofar)
+ 				crumbs.append('<a class=3D"%s" href=3D"%s">%s</a>' % (
+ 					cssclass, target, nid))
+ 		crumbhtml =3D '<span class=3D"wikicrumbs">%s</span>\n' % =
('&nbsp;/&nbsp;'.join(crumbs))
+ 		if not nodiv:=20
+ 			crumbhtml =3D '<div id=3D"wikicrumbsdiv">%s</div>' % crumbhtml
+ 		return crumbhtml
+ =09
+ 	def subNodes(self, id):=20
+ 		"What subnodes does this node have?"
+ 		if id:=20
+ 			spec =3D '/'.join((str(id), ''))
+ 		else:=20
+ 			spec =3D '' # all nodes
+ 		try:
+ 			self._acquire()
+ 			return [row.id for row in self.nodes if row.id.startswith(spec)]
+ 		finally:=20
+ 			self._release()
+ 	=09
+ 	def renderSubNodes(self, id, depthLimit=3D0):
+ 		idsegs =3D _splitPath(id)
+ 		skip =3D len(idsegs)
+ 		subnodeids =3D self.subNodes(id)
+=20
+ 		base =3D {}
+ 		for subnodeid in subnodeids:=20
+ 			segs =3D _splitPath(subnodeid)[skip:]
+ 			cursor =3D base
+ 			for seg in segs:=20
+ 				cursor =3D cursor.setdefault(seg, {})
+ 		PyDS.Tool.debugOutput("RSN: %s" % repr(base))
+ 		def spit(out, baseids, cursor, depthLimit, depth=3D1):=20
+ 			ids =3D cursor.keys()
+ 			ids.sort()
+ 			if len(ids):=20
+ 				out.append('<ul>')
+ 				for id in ids:
+ 					nbi =3D list(baseids) + [id]
+ 					where =3D '/'.join(nbi)
+ 					out.append('<li>')
+ 					out.append(self.renderBreadCrumbs(where, =
skipLevels=3Dlen(baseids), nodiv=3D1))
+ 					if depth < depthLimit:=20
+ 						spit(out, nbi, cursor[id], depthLimit, depth+1)
+ 					out.append('</li>')
+ 				out.append('</ul>')
+ 		output =3D []
+ 		spit(output, idsegs, base, depthLimit)
+ 		return '<div id=3D"subnodes">%s</div>' % '\n'.join(output)
+=20
+ 			=09
+ 		subnodes =3D []
+ 		for subnodeid in subnodeids:=20
+ 			subnodes.append('<li>%s</li>' % self.renderBreadCrumbs(subnodeid, =
skipLevels=3Dskip))
+ 		if len(subnodes):
+ 			return '<div id=3D"subnodes"><ul>%s</ul></div>' % ''.join(subnodes)
+ 		return '<div id=3D"subnodes"></div>'
+ 	=09
  	def __renderNodeOnline(self, key, data):
+ 		PyDS.Tool.traceargs()
  		(id,) =3D key
  		mirror =3D self.getToolByNamespace('mirror')
  		node =3D self.getNode(id=3Did)
***************
*** 788,799 ****
  		toolname =3D self.name # consider ''
  		body =3D req.renderText(
  			node['text'],=20
! 			structured =3D 1,
  			uniqueId =3D id,
  			homeTool =3D self)
  		node['cloud'] =3D body
! 		html =3D req.renderPage('WikiRendering', node=3Dnode)
  		src =3D req.renderPage('BaseRendering', body=3Dhtml, category=3D'', =
title=3Dnode.get('title', '(no title)'))
  		fn =3D self.storeHTML(src, page=3Dpagename, toolname=3Dtoolname)
  		try:
  			self._acquire()
--- 986,1003 ----
  		toolname =3D self.name # consider ''
  		body =3D req.renderText(
  			node['text'],=20
! 			structured =3D 2, # TODO: check 'structured' pref
  			uniqueId =3D id,
  			homeTool =3D self)
  		node['cloud'] =3D body
! 		crumbhtml =3D self.renderBreadCrumbs(id, startWithTool=3D0)
! 		subnodeshtml =3D self.renderSubNodes(id, depthLimit=3D1)
! 		PyDS.Tool.debugOutput("rendering the page")
! 		html =3D crumbhtml + subnodeshtml + req.renderPage('WikiRendering', =
node=3Dnode)
! 		PyDS.Tool.debugOutput("finished rendering the page")
! 		# render the result into a full page
  		src =3D req.renderPage('BaseRendering', body=3Dhtml, category=3D'', =
title=3Dnode.get('title', '(no title)'))
+ 		# ... and store it
  		fn =3D self.storeHTML(src, page=3Dpagename, toolname=3Dtoolname)
  		try:
  			self._acquire()

------=_NextPart_000_009B_01C47692.3F040F70--