1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/MoinContentSupport.py Sun Aug 15 01:52:41 2010 +0200
1.3 @@ -0,0 +1,70 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - MoinContentSupport library
1.7 +
1.8 + @copyright: 2008, 2009, 2010 by Paul Boddie <paul@boddie.org.uk>
1.9 + @copyright: 2000-2004 Juergen Hermann <jh@web.de>,
1.10 + 2005-2008 MoinMoin:ThomasWaldmann.
1.11 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.12 +"""
1.13 +
1.14 +__version__ = "0.1"
1.15 +
1.16 +# Utility classes and associated functions.
1.17 +# NOTE: These are a subset of EventAggregatorSupport.
1.18 +
1.19 +class Form:
1.20 +
1.21 + """
1.22 + A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x
1.23 + environment.
1.24 + """
1.25 +
1.26 + def __init__(self, form):
1.27 + self.form = form
1.28 +
1.29 + def get(self, name, default=None):
1.30 + values = self.form.getlist(name)
1.31 + if not values:
1.32 + return default
1.33 + else:
1.34 + return values
1.35 +
1.36 + def __getitem__(self, name):
1.37 + return self.form.getlist(name)
1.38 +
1.39 +class ActionSupport:
1.40 +
1.41 + """
1.42 + Work around disruptive MoinMoin changes in 1.9, and also provide useful
1.43 + convenience methods.
1.44 + """
1.45 +
1.46 + def get_form(self):
1.47 + return get_form(self.request)
1.48 +
1.49 +def get_form(request):
1.50 +
1.51 + "Work around disruptive MoinMoin changes in 1.9."
1.52 +
1.53 + if hasattr(request, "values"):
1.54 + return Form(request.values)
1.55 + else:
1.56 + return request.form
1.57 +
1.58 +class send_headers:
1.59 +
1.60 + """
1.61 + A wrapper to preserve MoinMoin 1.8.x (and earlier) request behaviour in a
1.62 + 1.9.x environment.
1.63 + """
1.64 +
1.65 + def __init__(self, request):
1.66 + self.request = request
1.67 +
1.68 + def __call__(self, headers):
1.69 + for header in headers:
1.70 + parts = header.split(":")
1.71 + self.request.headers.add(parts[0], ":".join(parts[1:]))
1.72 +
1.73 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/actions/AddLinkToPage.py Sun Aug 15 01:52:41 2010 +0200
2.3 @@ -0,0 +1,127 @@
2.4 +# -*- coding: iso-8859-1 -*-
2.5 +"""
2.6 + MoinMoin - AddLinkToPage
2.7 +
2.8 + Add a link using a form in the page, getting details of the linked document
2.9 + and inserting them with the link itself.
2.10 +
2.11 + @copyright: 2010 Paul Boddie <paul@boddie.org.uk>
2.12 + @license: GNU GPL, see COPYING for details.
2.13 +"""
2.14 +
2.15 +Dependencies = ['pages']
2.16 +
2.17 +from MoinMoin.action import ActionBase
2.18 +from MoinMoin.PageEditor import PageEditor
2.19 +from MoinContentSupport import ActionSupport
2.20 +import re
2.21 +
2.22 +macro_pattern = re.compile(ur'^(?P<leading>.*?)<<AddLinkToPage\((?P<identifier>[^\s,)]+).*?\)>>(?P<trailing>.*)$',
2.23 + re.MULTILINE | re.UNICODE)
2.24 +
2.25 +# Action class and supporting functions.
2.26 +
2.27 +class AddLinkToPage(ActionBase, ActionSupport):
2.28 +
2.29 + "An action adding links to pages."
2.30 +
2.31 + def do_action(self):
2.32 +
2.33 + "Create the new event."
2.34 +
2.35 + _ = self._
2.36 + form = self.get_form()
2.37 +
2.38 + # If no title exists in the request, an error message is returned.
2.39 +
2.40 + identifier = form.get("identifier", [None])[0]
2.41 +
2.42 + if not identifier:
2.43 + return 0, _("No identifier specified.")
2.44 +
2.45 + link = form.get("link", [None])[0]
2.46 +
2.47 + if not link:
2.48 + return 0, _("No link specified.")
2.49 +
2.50 + return self.add_link_to_page(identifier, link)
2.51 +
2.52 + def render_success(self, msg, msgtype=None):
2.53 +
2.54 + """
2.55 + Render neither 'msg' nor 'msgtype' since redirection should occur
2.56 + instead.
2.57 + NOTE: msgtype is optional because MoinMoin 1.5.x does not support it.
2.58 + """
2.59 +
2.60 + pass
2.61 +
2.62 + def add_link_to_page(self, identifier, link):
2.63 +
2.64 + """
2.65 + For the macro with the given 'identifier', add 'link' to the current
2.66 + page.
2.67 + """
2.68 +
2.69 + _ = self._
2.70 + request = self.request
2.71 + page = self.page
2.72 + formatter = request.formatter
2.73 + form = self.get_form()
2.74 +
2.75 + # Get the link details.
2.76 +
2.77 + title = form.get('title', [link])[0]
2.78 + introduction = form.get('introduction', [""])[0]
2.79 + description = form.get('description', [""])[0]
2.80 + insert_before = form.get('insert_before', [""])[0]
2.81 +
2.82 + # Encode the link details.
2.83 + # NOTE: Should support different formatting options.
2.84 +
2.85 + link_details = "%s[[%s%s]]%s" % (
2.86 + introduction and ('"%s" ' % formatter.escapedText(introduction)) or "",
2.87 + link,
2.88 + title and ('|%s' % title) or "",
2.89 + description and (" - ''%s''" % description) or ""
2.90 + )
2.91 +
2.92 + # Open the page for editing.
2.93 +
2.94 + new_page = PageEditor(request, page.page_name)
2.95 +
2.96 + # Parse the page.
2.97 +
2.98 + page_body = page.get_raw_body()
2.99 +
2.100 + for match in macro_pattern.finditer(page_body):
2.101 + macro_identifier = match.group("identifier")
2.102 + leading_text = match.group("leading")
2.103 + trailing_text = match.group("trailing")
2.104 + start, end = match.span()
2.105 +
2.106 + # Where this identifier matches this macro's identifier, insert the
2.107 + # link details.
2.108 +
2.109 + if macro_identifier == identifier:
2.110 + if insert_before:
2.111 + page_body = page_body[:start] + leading_text + link_details + trailing_text + "\n" + page_body[start:]
2.112 + else:
2.113 + page_body = page_body[:end] + "\n" + leading_text + link_details + trailing_text + page_body[end:]
2.114 +
2.115 + # Save the new version of the page.
2.116 +
2.117 + new_page.saveText(page_body, 0)
2.118 + break
2.119 +
2.120 + # NOTE: Perhaps show a message upon failure.
2.121 +
2.122 + request.http_redirect(page.url(request))
2.123 + return 1, None
2.124 +
2.125 +# Action function.
2.126 +
2.127 +def execute(pagename, request):
2.128 + AddLinkToPage(pagename, request).render()
2.129 +
2.130 +# vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/macros/AddLinkToPage.py Sun Aug 15 01:52:41 2010 +0200
3.3 @@ -0,0 +1,199 @@
3.4 +# -*- coding: iso-8859-1 -*-
3.5 +"""
3.6 + MoinMoin - AddLinkToPage
3.7 +
3.8 + Add a link using a form in the page, getting details of the linked document
3.9 + and inserting them with the link itself.
3.10 +
3.11 + @copyright: 2010 Paul Boddie <paul@boddie.org.uk>
3.12 + @license: GNU GPL, see COPYING for details.
3.13 +"""
3.14 +
3.15 +Dependencies = ["pages"]
3.16 +
3.17 +from MoinMoin import wikiutil
3.18 +from MoinMoin.PageEditor import PageEditor
3.19 +from MoinContentSupport import get_form
3.20 +import urllib
3.21 +import re
3.22 +
3.23 +title_pattern = re.compile(ur'<(?P<tag>title|h\d)(\s.*?)?>(?P<title>.*?)</(?P=tag)>', re.MULTILINE | re.UNICODE | re.DOTALL)
3.24 +paragraph_pattern = re.compile(ur'<p(\s.*?)?>(?P<text>.*?)(?=<p(\s.*?)?>|</p>)', re.MULTILINE | re.UNICODE | re.DOTALL)
3.25 +tag_pattern = re.compile(ur'<.*?>', re.MULTILINE | re.UNICODE | re.DOTALL)
3.26 +
3.27 +def get_link_info(link):
3.28 +
3.29 + "Get information from the given 'link'."
3.30 +
3.31 + # NOTE: Insist on remote URLs!
3.32 +
3.33 + try:
3.34 + f = urllib.urlopen(link)
3.35 + except IOError:
3.36 + return None
3.37 +
3.38 + try:
3.39 + s = f.read()
3.40 + first_title = ""
3.41 +
3.42 + for title_match in title_pattern.finditer(s):
3.43 + title = title_match.group("title").strip()
3.44 + start, end = title_match.span()
3.45 +
3.46 + if not first_title:
3.47 + first_title = title
3.48 +
3.49 + for intro_match in paragraph_pattern.finditer(s[end:]):
3.50 + intro = get_flattened_content(intro_match.group("text")).strip()
3.51 + if intro:
3.52 + return title, intro
3.53 + finally:
3.54 + f.close()
3.55 +
3.56 + return first_title, ""
3.57 +
3.58 +def get_flattened_content(s):
3.59 +
3.60 + "Get HTML or XHTML without the tags."
3.61 +
3.62 + l = []
3.63 + last = 0
3.64 + for match in tag_pattern.finditer(s):
3.65 + start, end = match.span()
3.66 + l.append(s[last:start])
3.67 + last = end
3.68 + l.append(s[last:])
3.69 + return "".join(l).replace("\n", " ")
3.70 +
3.71 +# Macro functions.
3.72 +
3.73 +def execute(macro, args):
3.74 +
3.75 + """
3.76 + Execute the 'macro' with the given 'args':
3.77 + """
3.78 +
3.79 + request = macro.request
3.80 + formatter = macro.formatter
3.81 + page = formatter.page
3.82 + form = get_form(request)
3.83 + _ = macro._
3.84 +
3.85 + output = []
3.86 +
3.87 + # Interpret the arguments.
3.88 +
3.89 + try:
3.90 + parsed_args = args and wikiutil.parse_quoted_separated(args, name_value=False) or []
3.91 + except AttributeError:
3.92 + parsed_args = args.split(",")
3.93 +
3.94 + parsed_args = [arg for arg in parsed_args if arg]
3.95 +
3.96 + # The macro's identifier should always appear first.
3.97 +
3.98 + identifier = parsed_args[0]
3.99 +
3.100 + # Look for keywords determining the action of the macro.
3.101 +
3.102 + insert_before = "before" in parsed_args[1:] or not ("after" in parsed_args[1:])
3.103 +
3.104 + # If the request refers to this macro, another kind of form will be shown.
3.105 +
3.106 + active_identifier = form.get('add_link_to_page', [None])[0]
3.107 + link = form.get('add_link_to_page_link', [None])[0]
3.108 +
3.109 + # Test for usage of this macro.
3.110 + # Where this macro is not active, don't do anything.
3.111 +
3.112 + if identifier != active_identifier:
3.113 + show_macro = 1
3.114 +
3.115 + # Otherwise, show a form containing link details.
3.116 +
3.117 + else:
3.118 +
3.119 + # Acquire information from the link.
3.120 +
3.121 + link_info = get_link_info(link)
3.122 +
3.123 + # NOTE: Perhaps show a message upon success/failure.
3.124 +
3.125 + if link_info is None:
3.126 + show_macro = 1
3.127 +
3.128 + # Information was retrieved and is now shown.
3.129 +
3.130 + else:
3.131 + title, introduction = link_info
3.132 +
3.133 + # Show a form containing the retrieved information suitable for the
3.134 + # corresponding action.
3.135 +
3.136 + output.append(u'<form class="macro" method="POST" action="%s/%s">' % (
3.137 + request.getScriptname(), wikiutil.quoteWikinameURL(page.page_name)))
3.138 +
3.139 + output.append(u'''
3.140 + <input type="hidden" name="identifier" value="%(identifier)s" />
3.141 + <input type="hidden" name="doit" value="1" />
3.142 + <input type="hidden" name="insert_before" value="%(insert_before)s" />
3.143 + <input type="hidden" name="action" value="AddLinkToPage" />''' % {
3.144 + "identifier" : wikiutil.escape(identifier, 1),
3.145 + "insert_before" : insert_before and "true" or ""
3.146 + })
3.147 +
3.148 + output.append(u'''
3.149 + <table>
3.150 + <tr>
3.151 + <th>%(url_label)s</th>
3.152 + <td><input type="text" name="link" value="%(link)s" /></td>
3.153 + </tr>
3.154 + <tr>
3.155 + <th>%(title_label)s</th>
3.156 + <td><input type="text" name="title" value="%(title)s" /></td>
3.157 + </tr>
3.158 + <tr>
3.159 + <th>%(intro_label)s</th>
3.160 + <td><input type="text" name="introduction" value="%(intro)s" /></td>
3.161 + </tr>
3.162 + <tr>
3.163 + <th>%(description_label)s</th>
3.164 + <td><input type="text" name="description" /></td>
3.165 + </tr>
3.166 + <tr>
3.167 + <td colspan="2"><input type="submit" value="%(submit_label)s" /></td>
3.168 + </tr>
3.169 + </table>''' % {
3.170 + "link" : wikiutil.escape(link, 1),
3.171 + "title" : wikiutil.escape(title, 1),
3.172 + "intro" : wikiutil.escape(introduction, 1),
3.173 + "url_label" : wikiutil.escape(_("URL")),
3.174 + "title_label" : wikiutil.escape(_("Title")),
3.175 + "intro_label" : wikiutil.escape(_("Introduction")),
3.176 + "description_label" : wikiutil.escape(_("Description")),
3.177 + "submit_label" : wikiutil.escape(_("Submit link"))
3.178 + })
3.179 +
3.180 + output.append(u'</form>')
3.181 +
3.182 + # Don't show the macro.
3.183 +
3.184 + show_macro = 0
3.185 +
3.186 + # If the macro is to be shown, emit the usual fields.
3.187 +
3.188 + if show_macro:
3.189 + output.append(u'<form class="macro" method="POST" action="%s/%s">' % (
3.190 + request.getScriptname(), wikiutil.quoteWikinameURL(page.page_name)))
3.191 + output.append(u'<input type="hidden" name="add_link_to_page" value="%s" />' %
3.192 + wikiutil.escape(identifier, 1))
3.193 + output.append(u'<div>')
3.194 + output.append(u'<input type="text" name="add_link_to_page_link" />')
3.195 + output.append(u'<input type="submit" value="%s" />' %
3.196 + wikiutil.escape(_("Add link")))
3.197 + output.append(u'</div>')
3.198 + output.append(u'</form>')
3.199 +
3.200 + return formatter.rawHTML('\n'.join(output))
3.201 +
3.202 +# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/setup.py Sun Aug 15 01:52:41 2010 +0200
4.3 @@ -0,0 +1,13 @@
4.4 +#! /usr/bin/env python
4.5 +
4.6 +from distutils.core import setup
4.7 +
4.8 +setup(
4.9 + name = "MoinContentSuite",
4.10 + description = "Edit MoinMoin content using forms and structured editing techniques",
4.11 + author = "Paul Boddie",
4.12 + author_email = "paul@boddie.org.uk",
4.13 + url = "http://moinmo.in/MacroMarket/MoinContentSuite",
4.14 + version = "0.1",
4.15 + py_modules = ["MoinContentSupport"]
4.16 + )