set up node processing; provide link manager, more details for link interface
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@3150 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
73ab6556d1
commit
aa43e289f8
9 changed files with 244 additions and 48 deletions
|
@ -27,10 +27,24 @@ The parser for restructured text and a corresponding HTML writer are the
|
|||
default plugins used, so we can already render the page as HTML.
|
||||
|
||||
>>> print startPage.render()
|
||||
visiting document
|
||||
visiting paragraph
|
||||
visiting strong
|
||||
visiting #text
|
||||
<p><strong>Welcome to the Demo Wiki</strong></p>
|
||||
|
||||
We now create another page that contains a link to the start page.
|
||||
|
||||
>>> aboutPage = wiki.createPage('about')
|
||||
>>> aboutPage.text = '''
|
||||
... **Information about the Demo Wiki**
|
||||
...
|
||||
... This is the cybertools demo wiki.
|
||||
...
|
||||
... `Back to the Start Page <start_page>`_
|
||||
... '''
|
||||
|
||||
>>> print aboutPage.render()
|
||||
processing reference:
|
||||
<reference name="Back to the Start Page"
|
||||
refuri="start_page">Back to the Start Page</reference>
|
||||
<p><strong>Information about the Demo Wiki</strong></p>
|
||||
<p>This is the cybertools demo wiki.</p>
|
||||
<p><a class="reference" href="start_page">Back to the Start Page</a></p>
|
||||
|
||||
|
|
|
@ -38,11 +38,16 @@ class BaseConfiguration(object):
|
|||
writer = parser = None
|
||||
|
||||
def getConfig(self, functionality):
|
||||
c = getattr(self, functionality, None)
|
||||
c = self.get(functionality)
|
||||
if c is None:
|
||||
return self.getParent().getConfig(functionality)
|
||||
parent = self.getParent()
|
||||
if parent is not None:
|
||||
return parent.getConfig(functionality)
|
||||
return c
|
||||
|
||||
def get(self, key, default=None):
|
||||
return getattr(self, key, None)
|
||||
|
||||
def getParent(self):
|
||||
return self.parent
|
||||
|
||||
|
@ -54,3 +59,6 @@ class WikiConfiguration(BaseConfiguration):
|
|||
writer = 'docutils.html'
|
||||
parser = 'docutils.rstx'
|
||||
processor = 'standard'
|
||||
linkManager = 'basic'
|
||||
|
||||
nodeProcessors = dict(reference=['default'])
|
||||
|
|
|
@ -35,18 +35,18 @@ class LinkManager(object):
|
|||
|
||||
def __init__(self):
|
||||
self.links = {}
|
||||
self.linksBySource = {}
|
||||
|
||||
def registerLink(self, link):
|
||||
if link.identifier is None:
|
||||
self.generateLinkIdentifier(link)
|
||||
if link.identifier not in self.links:
|
||||
self.links[link.identifier] = link
|
||||
def createLink(self, name, source, target, **kw):
|
||||
link = Link(name, source, target, **kw)
|
||||
link.manager = self
|
||||
id = self.generateLinkIdentifier(link)
|
||||
self.linksBySource[source] = self.links[id] = link
|
||||
|
||||
def unregisterLink(self, link):
|
||||
def removeLink(self, link):
|
||||
if link.identifier in self.links:
|
||||
del self.links[link.identifier]
|
||||
link.manager = None
|
||||
del self.links[link.identifier]
|
||||
|
||||
def generateLinkIdentifier(self, link):
|
||||
identifier = 'l%07i' % (max(self.links.keys() or [0]) + 1)
|
||||
|
@ -60,9 +60,21 @@ class Link(object):
|
|||
|
||||
identifier = None
|
||||
manager = None
|
||||
formatName = None
|
||||
|
||||
def __init__(self, source, target):
|
||||
def __init__(self, name, source, target, **kw):
|
||||
self.name = name
|
||||
self.source = source
|
||||
self.target = target
|
||||
for k, v in kw.items():
|
||||
if k not in ILink:
|
||||
raise AttributeError(k)
|
||||
setattr(self, k, v)
|
||||
|
||||
def getManager(self):
|
||||
return self.manager
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr not in ILink:
|
||||
raise AttributeError(attr)
|
||||
return getattr(self, attr, None)
|
||||
|
||||
|
|
|
@ -24,8 +24,10 @@ $Id$
|
|||
|
||||
from zope.interface import implements
|
||||
from zope.component import adapts
|
||||
from zope import component
|
||||
|
||||
from cybertools.wiki.interfaces import ITreeProcessor, IWikiPage
|
||||
from cybertools.wiki.interfaces import ITreeProcessor, INodeProcessor
|
||||
from cybertools.wiki.interfaces import IWikiPage
|
||||
|
||||
|
||||
class TreeProcessor(object):
|
||||
|
@ -37,18 +39,35 @@ class TreeProcessor(object):
|
|||
adapts(IWikiPage)
|
||||
|
||||
tree = None
|
||||
visitor = None
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def process(self):
|
||||
self.tree.walk(Visitor(self.tree))
|
||||
self.visitor = visitor = Visitor(self)
|
||||
self.tree.walk(visitor)
|
||||
|
||||
|
||||
class Visitor(object):
|
||||
|
||||
def __init__(self, document):
|
||||
self.document = document
|
||||
def __init__(self, context):
|
||||
self.context = context # the tree processor
|
||||
self.document = context.tree # needed internally
|
||||
self.processors = {} # cache
|
||||
self.processorNames = self.context.context.getConfig('nodeProcessors')
|
||||
|
||||
def dispatch_visit(self, node):
|
||||
print 'visiting', node.tagname
|
||||
#print 'visiting', node.tagname
|
||||
tag = node.tagname
|
||||
procs = self.processors.get(tag)
|
||||
if procs is None:
|
||||
procs = self.processors[tag] = []
|
||||
procNames = self.processorNames.get(tag, [])
|
||||
for n in procNames:
|
||||
proc = component.queryAdapter(node, INodeProcessor, name=n)
|
||||
if proc is not None:
|
||||
proc.parent = self.context
|
||||
procs.append(proc)
|
||||
for p in procs:
|
||||
p.process()
|
||||
|
|
|
@ -46,6 +46,17 @@ class WikiManager(BaseConfiguration):
|
|||
wiki.manager = self
|
||||
return wiki
|
||||
|
||||
def removeWiki(self, wiki):
|
||||
name = wiki.name
|
||||
if name in self.wikis:
|
||||
del self.wikis[name]
|
||||
|
||||
def listWikis(self):
|
||||
return self.wikis.values()
|
||||
|
||||
def getPlugin(self, type, name):
|
||||
return component.getUtility(type, name=name)
|
||||
|
||||
# configuration
|
||||
|
||||
def getParent(self):
|
||||
|
@ -63,6 +74,9 @@ class Wiki(BaseConfiguration):
|
|||
self.title = title or name
|
||||
self.pages = {}
|
||||
|
||||
def getManager(self):
|
||||
return self.manager
|
||||
|
||||
def createPage(self, name, title=None):
|
||||
if name in self.pages:
|
||||
raise ValueError("Name '%s' already present." % name)
|
||||
|
@ -70,10 +84,20 @@ class Wiki(BaseConfiguration):
|
|||
page.wiki = self
|
||||
return page
|
||||
|
||||
def removePage(self, name):
|
||||
if name in self.pages:
|
||||
del self.pages[name]
|
||||
|
||||
def getPage(self, name):
|
||||
return self.pages.get(name)
|
||||
|
||||
def listPages(self):
|
||||
return self.pages.values()
|
||||
|
||||
# configuration
|
||||
|
||||
def getParent(self):
|
||||
return self.manager
|
||||
return self.getManager()
|
||||
|
||||
|
||||
class WikiPage(BaseConfiguration):
|
||||
|
@ -87,6 +111,9 @@ class WikiPage(BaseConfiguration):
|
|||
self.name = name
|
||||
self.title = title or name
|
||||
|
||||
def getWiki(self):
|
||||
return self.wiki
|
||||
|
||||
def render(self):
|
||||
source = self.preprocess(self.text)
|
||||
tree = self.parse(source)
|
||||
|
@ -119,5 +146,5 @@ class WikiPage(BaseConfiguration):
|
|||
# configuration
|
||||
|
||||
def getParent(self):
|
||||
return self.wiki
|
||||
return self.getWiki()
|
||||
|
||||
|
|
51
wiki/dcu/process.py
Normal file
51
wiki/dcu/process.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Node processor implementations for docutils nodes.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from docutils.nodes import reference
|
||||
from zope.interface import implements
|
||||
from zope.component import adapts
|
||||
|
||||
from cybertools.wiki.interfaces import INodeProcessor, ILinkManager
|
||||
|
||||
|
||||
class Reference(object):
|
||||
|
||||
implements(INodeProcessor)
|
||||
adapts(reference)
|
||||
|
||||
parent = None # parent (tree) processor
|
||||
|
||||
def __init__(self, context):
|
||||
self.node = self.context = context
|
||||
|
||||
def process(self):
|
||||
print 'processing reference:', self.node
|
||||
source = self.parent.context
|
||||
wiki = source.getWiki()
|
||||
sourceName = ':'.join((wiki.name, source.name))
|
||||
targetName = self.node['refuri']
|
||||
lmName = source.getConfig('linkManager')
|
||||
lm = wiki.getManager().getPlugin(ILinkManager, lmName)
|
||||
target = wiki.getPage(targetName)
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
#
|
||||
|
||||
"""
|
||||
A Wiki manager managing wikis and wiki-related objects, esp plugins.
|
||||
A parser implementation based on the docutils restructured text parser.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
|
|
@ -35,23 +35,21 @@ class IWikiConfiguration(Interface):
|
|||
parser = Attribute('Plug-in component converting from text input '
|
||||
'format to internal tree format.')
|
||||
|
||||
def getConfig(functionality):
|
||||
""" Return the name of the plugin that should used for the
|
||||
functionality given.
|
||||
"""
|
||||
|
||||
def getParent():
|
||||
""" Return the parent object in case this configuration does not
|
||||
provide configuration information for a certain functionality.
|
||||
"""
|
||||
|
||||
def getConfig(functionality):
|
||||
""" Return the name of the plugin that should used for the
|
||||
functionality given.
|
||||
"""
|
||||
|
||||
|
||||
class IWikiManager(Interface):
|
||||
""" Manages wikis and wiki-related objects, like plugins.
|
||||
"""
|
||||
|
||||
wikis = Attribute('A collection of wikis managed by this object.')
|
||||
|
||||
def addWiki(wiki):
|
||||
""" Register the wiki given.
|
||||
"""
|
||||
|
@ -60,15 +58,26 @@ class IWikiManager(Interface):
|
|||
""" Remove the wiki given from the list of wikis.
|
||||
"""
|
||||
|
||||
def listWikis():
|
||||
""" Return a collection of wikis managed by this object.
|
||||
"""
|
||||
|
||||
def getPlugin(type, name):
|
||||
""" Return the plugin of the type given with the name given.
|
||||
"""
|
||||
|
||||
|
||||
class IWiki(Interface):
|
||||
""" A collection of wiki pages, or - more generally - wiki components.
|
||||
"""
|
||||
|
||||
manager = Attribute('The wiki manager this wiki is managed by.')
|
||||
name = Attribute('The name or address of the wiki unique within the '
|
||||
'scope of the wiki manager.')
|
||||
pages = Attribute('A collection of the pages belonging to this wiki.')
|
||||
pages = Attribute('')
|
||||
|
||||
def getManager():
|
||||
""" Return the wiki manager this wiki is managed by.
|
||||
"""
|
||||
|
||||
def createPage(name, title=None):
|
||||
""" Create a new wiki page identified by the name (address -
|
||||
|
@ -80,17 +89,28 @@ class IWiki(Interface):
|
|||
all information related to the page.
|
||||
"""
|
||||
|
||||
def getPage(name):
|
||||
""" Return the page with the name given or None if not present.
|
||||
"""
|
||||
|
||||
def listPages():
|
||||
""" Return a collection of the pages belonging to this wiki.
|
||||
"""
|
||||
|
||||
|
||||
class IWikiPage(Interface):
|
||||
""" An object representing a page of a wiki.
|
||||
"""
|
||||
|
||||
wiki = Attribute('The wiki this page belongs to.')
|
||||
name = Attribute('A page name or address unique within the wiki.')
|
||||
title = Attribute('A short string describing the wiki page the may be '
|
||||
'use as a page title.')
|
||||
text = Attribute('The page content in input text format.')
|
||||
|
||||
def getWiki():
|
||||
""" The wiki this page belongs to.'
|
||||
"""
|
||||
|
||||
def render():
|
||||
""" Convert the source text of the page to presentation format.
|
||||
"""
|
||||
|
@ -148,32 +168,73 @@ class ITreeProcessor(Interface):
|
|||
"""
|
||||
|
||||
|
||||
class INodeProcessor(Interface):
|
||||
""" Processes a document tree.
|
||||
"""
|
||||
|
||||
context = Attribute('The node to be processed.')
|
||||
parent = Attribute('The parent (=tree) processor.')
|
||||
|
||||
def process():
|
||||
""" Do what is necessary.
|
||||
"""
|
||||
|
||||
|
||||
# wiki elements
|
||||
|
||||
class ILinkManager(Interface):
|
||||
"""Manages (and possibly contains) all kinds of wiki-related links.
|
||||
""" Manages (and possibly contains) all kinds of wiki-related links.
|
||||
"""
|
||||
|
||||
def registerLink(link):
|
||||
"""Register (store) a link.
|
||||
def createLink(name, source, target, **kw):
|
||||
""" Create and register a link record.
|
||||
|
||||
Optional attributes are given as keyword arguments.
|
||||
"""
|
||||
|
||||
def unregisterLink(link):
|
||||
"""Remove a link.
|
||||
def removeLink(link):
|
||||
""" Remove a link.
|
||||
"""
|
||||
|
||||
def getLink(identifier):
|
||||
""" Return the link record identfied by the identifier given or None if
|
||||
not present.
|
||||
"""
|
||||
|
||||
def query(source=None, target=None, name=None, **kw):
|
||||
""" Search for link records matching the criteria given. One of
|
||||
source or target must be given, the other one and name are optional.
|
||||
|
||||
Additional (optional) criteria may be supported by the implementation.
|
||||
"""
|
||||
|
||||
# TODO: convert the following stuff so that it fits in the parser/writer
|
||||
# paradigm.
|
||||
|
||||
class ILink(Interface):
|
||||
"""A hyperlink between two local or foreign objects.
|
||||
""" A hyperlink between two local or foreign objects.
|
||||
|
||||
There may be more than one link records with the same name
|
||||
that represent the real link at different times or under
|
||||
different conditions.
|
||||
"""
|
||||
|
||||
identifier = Attribute('Identifier of the link, unique within its link manager.')
|
||||
manager = Attribute('The manager that this link is managed by.')
|
||||
formatName = Attribute('Name of the link format that identified the link.')
|
||||
|
||||
source = Attribute('Link source.')
|
||||
target = Attribute('Link target.')
|
||||
identifier = Attribute('An internal identifier of the link record, '
|
||||
'unique within the link manager.')
|
||||
name = Attribute('The external identifier for the link, i.e. the '
|
||||
'string used in the source text to address the link.')
|
||||
title = Attribute('A short text, may be used as the default text for '
|
||||
'the link or for the alt tag of an image. Could also serve '
|
||||
'for identifying a new link.')
|
||||
description = Attribute('Optional: some text, may be used as a title attribute.')
|
||||
state = Attribute('A short string denoting the state of the link entry.')
|
||||
source = Attribute('Identifier of the link\'s source object.')
|
||||
target = Attribute('Identifier of the link\'s target object or - '
|
||||
'for external links - the target URI.')
|
||||
targetFragment = Attribute('Optional: an address part leading to a '
|
||||
'text anchor or the part of an image.')
|
||||
user = Attribute('Optional: a string denoting the creator of the record.')
|
||||
run = Attribute('Optional: May be used to group the links from a certain '
|
||||
'source at different times.')
|
||||
|
||||
def getManager():
|
||||
""" Return the link manager this link is managed by.
|
||||
"""
|
||||
|
|
|
@ -12,8 +12,10 @@ from zope import component
|
|||
|
||||
from cybertools.wiki.base.config import WikiConfiguration
|
||||
from cybertools.wiki.base.process import TreeProcessor
|
||||
from cybertools.wiki.base.link import LinkManager
|
||||
from cybertools.wiki.dcu.html import Writer as DocutilsHTMLWriter
|
||||
from cybertools.wiki.dcu.rstx import Parser as DocutilsRstxParser
|
||||
from cybertools.wiki.dcu import process
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
@ -28,6 +30,8 @@ def setUp(testCase):
|
|||
component.provideUtility(DocutilsHTMLWriter(), name='docutils.html')
|
||||
component.provideUtility(DocutilsRstxParser(), name='docutils.rstx')
|
||||
component.provideAdapter(TreeProcessor, name='standard')
|
||||
component.provideAdapter(process.Reference, name='default')
|
||||
component.provideUtility(LinkManager(), name='basic')
|
||||
|
||||
|
||||
def test_suite():
|
||||
|
|
Loading…
Add table
Reference in a new issue