Size: 29973
Comment:
|
Size: 34241
Comment: ready to publish this stuff
|
Deletions are marked like this. | Additions are marked like this. |
Line 2: | Line 2: |
I do not have the time to do this the proper way - isolate the minimum necessary core patches and test this extensively, write unit tests, document it... However, as some people have asked for more, I have at least created some patch files for all the affected modules. You probably do not even need all those patches, as some are for other features. |
I do not have the time to do this the proper way - isolate the minimum necessary core patches and test this extensively, write unit tests, document it, do i18n... However, as some people have asked for more info, I have at least created some patch files for all the affected modules and decided to publish the whole thing as-is. You probably do not even need all those patches, as some are for other features. |
Line 691: | Line 691: |
{{{ #the physical path to your /wiki url, needed to export smiley images etc. url_prefix_dir = 'E:\\moin13\\share\\moin\\htdocs\\' }}} You also need to have a way to configure the target export directory - at the moment I have not bothered to integrate this int the config, but rather define it in the used action or command batch. |
|
Line 719: | Line 727: |
You need to have Microsoft Word (2000) on your MoinMoin server and should have generated a python wrapper with {{{makepy}}} (oh yes, and you need Mark Hammonds win32 package (win32all build 163), of course). Due to some weird exceptions I have decided to serve the Word control with {{{Visible=1}}}, this means that you will watch Word "typing in" your target document! |
|
Line 724: | Line 734: |
It needs the {{{reportlab}}} package. | |
Line 732: | Line 742: |
This can be used to batch export multiple pages matching PAGEPATTERN - be aware that Word may be slow, though ;-(). {{{ set GATEWAY_INTERFACE=CGI/1.1 set DUMPNAME=word set PYTHONPATH=E:\moin13\Lib\site-packages set TARGETROOT=E:\moin13 set WIKIURL="http://localhost/moin13/" set DUMPPATH=%TARGETROOT%\dump_%DUMPNAME% set PAGEPATTERN=SyntaxReference set PAGEPATTERN="%PAGEPATTERN%" E:\python23\python.exe -c "from MoinMoin.scripts.moin_export import run; run()" --wiki=%WIKIURL% --format=word --pattern=%PAGEPATTERN% %DUMPPATH% 1>dump.log 2>dumperr.log pause }}} |
|
Line 733: | Line 761: |
To use this, you may have to modify the server to use a different request from {{{request_ors.py}}}, in my case I modified the {{{moin.cgi}}} (or you could try to create such a request inside the action?): {{{ from MoinMoin.request_ors import RequestORSCGI request = RequestORSCGI() #disable my more critical modifications request.ors_mod_active=0 }}} Here is a test action that can be applied to a single page to trigger the export of this page (in Word format, but for PDF it looks very similar). We will later provide an action with a proper user dialog (select format, output name ...maybe even return a link to the created file). Right now, the output directory is hardcoded and you must pick up the result file from the server. {{{#!python # Imports import string, time,sys,os,copy from MoinMoin import user, webapi, wikiutil from MoinMoin.PageEditor import PageEditor from MoinMoin.scripts.moin_export import MoinExporter def execute(pagename, request): _ = request.getText page = PageEditor(request,pagename) exp_format="word" # exp_format="html" # exp_format="plain" # exp_format="pdf" #must protect a function that is overrided by the exporter qfn_orig=wikiutil.quoteWikinameURL markup_orig=request.cfg.default_markup pname=pagename #open exporter exporter=MoinExporter() #assign a request (use a copy because we modify the request) exporter.request=copy.copy(request) #set target output directory exporter.setOutputDir(r"E:\moin13\dump_word") #redirect the request to action=print and indicate "export" mode exporter.request.user.show_topbottom=0 exporter.request.form['action']='print' exporter.request.form['export']='1' #assign the export formatter exporter.setFormatter(exp_format) #use special parser for some export formats if exp_format in ("word","pdf"): request.cfg.default_markup="wiki_word" #create target file name - this is the plain output of the formatter, the "real" target file #is different for word and pdf as they create it as a "side effect" file = wikiutil.quoteWikinameFS(pname) + exporter.ext #create error log file (right now we always use the same file for all - this may be bad) errfile = os.path.join(exporter.outputdir, 'error.log') exporter.errlog = open(errfile, 'w') #dump the page using the formatter output=exporter.dumpPage(pname,file) #close the error log exporter.errlog.close() #reset overrided function wikiutil.quoteWikinameURL = qfn_orig request.cfg.default_markup=markup_orig #use this to test output # return page.send_page(request, msg='<pre>%s</pre>' % output) return page.send_page(request, msg='<strong>%s</strong>' % _('Export of page %s completed.' % pagename)) }}} |
MoinMoin Exporter Package - Work in Progress
I do not have the time to do this the proper way - isolate the minimum necessary core patches and test this extensively, write unit tests, document it, do i18n...
However, as some people have asked for more info, I have at least created some patch files for all the affected modules and decided to publish the whole thing as-is. You probably do not even need all those patches, as some are for other features.
Patches to core MoinMoin 1.3.5
I put them here as code snippets rather than attachments, so I can comment on questions later on.
MoinMoin.Page
--- E:\Install\MoinMoin\moin-1.3.5.tar\moin-1.3.5\MoinMoin\Page.py Sun Jul 24 13:06:26 2005 +++ E:\moin13\Lib\site-packages\MoinMoin\Page.py Wed Sep 28 17:56:41 2005 @@ -1,21 +1,45 @@ # -*- coding: iso-8859-1 -*- """ MoinMoin - Page class @copyright: 2000-2004 by Jürgen Hermann <jh@web.de> @license: GNU GPL, see COPYING for details. + ORS modifications: + 02.01.04 RS implemented old "#locked" syntax as "#acl All:Read" + 05.01.04 RS no caching of "new Page" page + 05.01.04 RS activate IIS-patch for getScriptname, + 13.01.04 RS extensions for export mode + 20.01.04 RS fix for "extensions for export mode" in send_page + 05.02.04 RS more versions of "#locked_*" syntax using config.acl_line_locked_* + 24.02.04 RS fix for export mode in link_to + 28.10.04 RS patch to enable #pragma title for a display title + 04.11.04 RS patch to allow interwiki and relative links in #REDIRECT + 30.11.04 RS patch for acl handling of remotely created pages (they may have an extra \r after #locked_hard) + 17.10.04 RS patch to force #pragma section-numbers 0 in export mode + 1.3.3 re-migration of patches started 26.01.05 + * keywords and export_mode tricks - export_mode now a property of request, no tricks here -done + * acl specials - done + * IIS-patch - encapsulated in special request class, modify calls - done + * interwiki enhancements - needs code review, some code moved to themeing -open + * pragma enhancements - title done, var_* re-designed (request_ors.py,wiki.py) - done + * remotely created pages - needs redesign based on globaledit utilities! -open + + 03.02.05 RS all critical ORS modifications now check for request.ors_mod_active + """ -import StringIO, os, re, urllib, random, codecs +import sys, os, re, urllib, random, codecs,StringIO from MoinMoin import config, caching, user, util, wikiutil from MoinMoin.logfile import eventlog from MoinMoin.util import filesys, web +_debug=0 + class Page: """Page - Manage an (immutable) page associated with a WikiName. To change a page's content, use the PageEditor class. """ # Header regular expression, used to get header boundaries header_re = r'(^#+.*(?:\n\s*)+)+' @@ -760,17 +784,21 @@ @param querystr: the query string to add after a "?" after the url (str or dict, see util.web.makeQueryString) @param escpae: escape url for html, to be backward compatible with old code (bool) @rtype: str @return: complete url of this page, including scriptname """ - url = '%s/%s' % (request.getScriptname(), +#RS activate IIS-patch for getScriptname +## url = '%s/%s' % (request.getScriptname(), +## wikiutil.quoteWikinameURL(self.page_name)) + url = '%s/%s' % (request.getScriptname(patch=1), wikiutil.quoteWikinameURL(self.page_name)) - +#RS end + if querystr: querystr = web.makeQueryString(querystr) # TODO: remove in 1.4 # Escape query string to be compatible with old 3rd party code # New code should call with escape=0 to prevent the warning. if escape: @@ -898,14 +926,15 @@ from MoinMoin import i18n request.clock.start('send_page') _ = request.getText # determine modes print_mode = request.form.has_key('action') and request.form['action'][0] == 'print' if print_mode: + #raise AttributeError,"exporter: %s" % keywords media = request.form.has_key('media') and request.form['media'][0] or 'print' else: media = 'screen' content_only = keywords.get('content_only', 0) content_id = keywords.get('content_id', 'content') do_cache = keywords.get('do_cache', 1) send_missing_page = keywords.get('send_missing_page', 0) @@ -920,22 +949,26 @@ eventlog.EventLog(request).add(request, 'VIEWPAGE', {'pagename': self.page_name}) # load the text body = self.get_raw_body() # if necessary, load the default formatter if self.default_formatter: + if _debug: + sys.stderr.write("\nreset formatter to default!") from MoinMoin.formatter.text_html import Formatter self.formatter = Formatter(request, store_pagelinks=1) self.formatter.setPage(self) if self.hilite_re: self.formatter.set_highlight_re(self.hilite_re) request.formatter = self.formatter # default is wiki markup pi_format = self.cfg.default_markup or "wiki" + if _debug: + sys.stderr.write("\nMarkup: %s,frmat=%s" % (str(self.cfg.default_markup),pi_format)) pi_formatargs = '' pi_redirect = None pi_refresh = None pi_formtext = [] pi_formfields = [] wikiform = None @@ -960,21 +993,32 @@ # skip comments (lines with two hash marks) if line[1] == '#': continue # parse the PI verb, args = (line[1:]+' ').split(' ', 1) verb = verb.lower() args = args.strip() +#RS TOCHECK protect against remotely created pages (they may have an extra \r after #locked_hard + verb = verb.replace('\r','') +#RS end # check the PIs if verb == "format": # markup format - pi_format, pi_formatargs = (args+' ').split(' ',1) - pi_format = pi_format.lower() - pi_formatargs = pi_formatargs.strip() +#RS avoid reset if format=='wiki' (maybe we're in 'wiki_word' mode? +## pi_format, pi_formatargs = (args+' ').split(' ',1) +## pi_format = pi_format.lower() +## pi_formatargs = pi_formatargs.strip() + m_pi_format, m_pi_formatargs = (args+' ').split(' ',1) + if m_pi_format!="wiki": + pi_format=m_pi_format + pi_format = pi_format.lower() + pi_formatargs = m_pi_formatargs.strip() + sys.stderr.write("\nFORMAT Markup: %s,frmat=%s" % (str(self.cfg.default_markup),pi_format)) +#RS end elif verb == "refresh": if self.cfg.refresh: try: mindelay, targetallowed = self.cfg.refresh args = args.split() if len(args) >= 1: delay = max(int(args[0]), mindelay) @@ -995,19 +1039,26 @@ elif verb == "redirect": # redirect to another page # note that by including "action=show", we prevent # endless looping (see code in "request") or any # cascaded redirection pi_redirect = args if request.form.has_key('action') or request.form.has_key('redirect') or content_only: continue +#RS interwiki and anchor handling + (link,xanchor)=wikiutil.resolve_interwiki(request,self.page_name,pi_redirect) - request.http_redirect('%s/%s?action=show&redirect=%s' % ( - request.getScriptname(), - wikiutil.quoteWikinameURL(pi_redirect), - urllib.quote_plus(self.page_name.encode(config.charset), ''),)) +## request.http_redirect('%s/%s?action=show&redirect=%s' % ( +## request.getScriptname(), +## wikiutil.quoteWikinameURL(pi_redirect), +## urllib.quote_plus(self.page_name.encode(config.charset), ''),)) + request.http_redirect('%s?action=show&redirect=%s%s' % ( + link, +# urllib.quote_plus(self.page_name.encode(config.charset), ''))) + urllib.quote_plus(self.page_name.encode(config.charset), ''),xanchor)) +#RS end return elif verb == "deprecated": # deprecated page, append last backup version to current contents # (which should be a short reason why the page is deprecated) msg = '%s<strong>%s</strong><br>%s' % ( self.formatter.smiley('/!\\'), _('The backupped content of this page is deprecated and will not be included in search results!'), @@ -1038,37 +1089,51 @@ pi_formtext.append('<table border="1" cellspacing="1" cellpadding="3">\n' '<form method="POST" action="%s">\n' '<input type="hidden" name="action" value="formtest">\n' % self.url(request)) pi_formtext.append(wikiform.parseDefinition(request, args, pi_formfields)) elif verb == "acl": # We could build it here, but there's no request. pass +#RS 05.02.04 +#old-style ORS locking to be interpreted like an ACL + elif verb in ("locked","locked_hard","locked_test"): + # We could build it here, but there's no request. + pass +#RS end elif verb == "language": # Page language. Check if args is a known moin language if args in i18n.wikiLanguages(): self.language = args request.setContentLanguage(self.language) else: # unknown PI ==> end PI parsing, and show invalid PI as text body = line + '\n' + body break # Save values for later use self.pi_format = pi_format + if _debug: + sys.stderr.write("\nMarkup: %s,.frmat=%s" % (str(self.cfg.default_markup),self.pi_format)) # start document output doc_leader = self.formatter.startDocument(self.page_name) page_exists = self.exists() if not content_only: # send the document leader +#RS disable caching + if request.ors_mod_active==1: + request.disableHttpCaching() + +#RS end if page_exists: request.http_headers() else: request.http_headers(['Status: 404 NOTFOUND']) request.setResponseCode(404) + request.write(doc_leader) # send the page header if self.default_formatter: full_text_query = 'linkto:"%s"' % self.page_name link = '%s/%s?action=fullsearch&value=%s&context=180' % ( request.getScriptname(), @@ -1071,15 +1136,43 @@ if self.default_formatter: full_text_query = 'linkto:"%s"' % self.page_name link = '%s/%s?action=fullsearch&value=%s&context=180' % ( request.getScriptname(), wikiutil.quoteWikinameURL(self.page_name), urllib.quote_plus(full_text_query.encode(config.charset))) + def quote_whitespace(x): + if x.find(" ")!=-1: + return "'%s'" % x + else: + return x + page_needle = quote_whitespace(self.page_name) + if config.allow_subpages and page_needle.count('/'): + #parts = page_needle.split('/') + #for level in range(1, len(parts)): + # page_needle += (" !" + quote_whitespace( + # "/".join(parts[:level])) + " " + + # quote_whitespace( + # "/" + "/".join(parts[level:]))) + page_needle = '/' + page_needle.split('/')[-1] + +#RS activate IIS-patch for getScriptname +## link = '%s/%s?action=fullsearch&value=%s&literal=1&case=1&context=180' % ( +## request.getScriptname(), +## wikiutil.quoteWikinameURL(self.page_name), +## urllib.quote_plus(page_needle.encode(config.charset), '')) + link = '%s/%s?action=fullsearch&value=%s&literal=1&case=1&context=180' % ( + request.getScriptname(patch=1), + wikiutil.quoteWikinameURL(self.page_name), + urllib.quote_plus(page_needle.encode(config.charset), '')) +#RS end title = self.split_title(request) +#RS overwrite with nice title from pragma + title= request.getPragma('title', title) +#RS end if self.rev: msg = "<strong>%s</strong><br>%s" % ( _('Revision %(rev)d as of %(date)s') % { 'rev': self.rev, 'date': self.mtime_printable(request) }, msg) @@ -1118,23 +1211,44 @@ request.write(''.join(pi_formtext)) - +#RS extensions for export mode + else: +#nearly same as default formatter but used in export + if self.formatter.mimetype=="text/html": + title = self.split_title(request) +## wikiutil.send_title(request, title, page=self, link=link, msg=msg, +## pagename=self.page_name, print_mode=print_mode, +## media=media, pi_refresh=pi_refresh, +## allow_doubleclick=1, trail=trail, +## ) + wikiutil.send_title(request, title, page=self, link='', msg='', + pagename=self.page_name, print_mode=1, + media='print', pi_refresh=None, + allow_doubleclick=0,trail=None + ) +#RS end + + if _debug: + sys.stderr.write("\nMarkup: %s,self.pi_format=%s" % (str(self.cfg.default_markup),self.pi_format)) + sys.stderr.write("\nloading Parser for %s" % str(self.pi_format)) # try to load the parser Parser = wikiutil.importPlugin(self.request.cfg, "parser", self.pi_format, "Parser") if Parser is None: # default to plain text formatter (i.e. show the page source) del Parser from parser.plain import Parser + if _debug: + sys.stderr.write("\nParser=%s" % str(Parser)) # start wiki content div request.write(self.formatter.startContent(content_id)) # new page? if not page_exists and (not content_only or (content_only and send_missing_page)): if self.default_formatter and not content_only: @@ -1157,23 +1271,36 @@ if getattr(request, 'footnotes', None): from MoinMoin.macro.FootNote import emit_footnotes request.write(emit_footnotes(request, self.formatter)) # end wiki content div request.write(self.formatter.endContent()) +#RS do this later for proper sequence! +# doc_trailer = self.formatter.endDocument() +# # end document output - doc_trailer = self.formatter.endDocument() if not content_only: # send the page footer if self.default_formatter: wikiutil.send_footer(request, self.page_name, print_mode=print_mode) - - request.write(doc_trailer) - +#RS extensions for export mode + doc_trailer = self.formatter.endDocument() + request.write(doc_trailer) + elif self.formatter.mimetype=="text/html": + wikiutil.send_footer(request, self.page_name, print_mode=print_mode) + doc_trailer = self.formatter.endDocument() + request.write(doc_trailer) + else: + doc_trailer = self.formatter.endDocument() + request.write(doc_trailer) + +## request.write(doc_trailer) +#RS end + # cache the pagelinks if do_cache and self.default_formatter and page_exists: cache = caching.CacheEntry(request, self, 'pagelinks') if cache.needsUpdate(self._text_filename()): links = self.formatter.pagelinks cache.update('\n'.join(links) + '\n', True) @@ -1223,14 +1350,15 @@ Output the formatted wiki page, using caching, if possible. @param request: the request object @param Parser: the Parser @param body: text of the wiki page @param needsupdate: if 1, force update of the cached compiled page """ +# sys.stderr.write("Parser=%s" % str(Parser)) request.clock.start('send_page_content') formatter_name = self.getFormatterName() # if we should not or can not use caching if not (do_cache and self.canUseCache(Parser)): # parse the text and send the page content @@ -1335,14 +1463,28 @@ def _emptyPageText(self, request): """ Output the default page content for new pages. @param request: the request object """ +##RS deny creation of illegal pages + + if request.ors_mod_active==1: + import re + _ = request.getText + word_re=re.compile(ur"^(((?:[%(u)s][%(l)s]+){2,}/{0,1}))(?:[%(u)s][%(l)s]+){2,}$" % {'u':"A-Z", 'l':"0-9a-z"}) + + word_match = word_re.match(self.page_name) + if not word_match: + request.http_headers() + request.write('<p>' + _("This page name is illegal at ORS wikis and you can't create page") + ' "<tt>' + self.page_name + '</tt>".'+_('Use only CapitalizedWords and no special characters!')) + return +#RS end + missingpage = wikiutil.getSysPage(request, 'MissingPage') missingpagefn = missingpage._text_filename() missingpage.page_name = self.page_name missingpage._text_filename_force = missingpagefn missingpage.send_page(request, content_only=1, send_missing_page=1)
note that I had to remove an (insignificant) line containing '}'}'} from the generated diff, so the positions may be wrong, but you should apply those patches manually, anyway.
MoinMoin.parser.wiki
--- E:\Install\MoinMoin\moin-1.3.5.tar\moin-1.3.5\MoinMoin\parser\wiki.py Sat Jul 30 14:51:12 2005 +++ E:\moin13\Lib\site-packages\MoinMoin\parser\wiki.py Tue Sep 27 12:17:55 2005 @@ -1,13 +1,20 @@ # -*- coding: iso-8859-1 -*- """ MoinMoin - MoinMoin Wiki Markup Parser @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de> @license: GNU GPL, see COPYING for details. + ORS modifications: + 08.01.04 RS inline parser fix, makes inline extensions configurable + 08.01.04 RS colorizer, makes colorizer extensions configurable + 09.01.04 RS ignore character formatting inside DT + 26.01.04 RS fix colorizer patch + 1.3.3 re-migration of patches started 31.01.05 + * page variables in interwiki """ import os, re from MoinMoin import config, wikimacro, wikiutil from MoinMoin.Page import Page from MoinMoin.util import web @@ -161,14 +169,20 @@ # fancy link to subpage [wiki:/SubPage text] return self._word_repl(url, text) elif Page(self.request, url).exists(): # fancy link to local page [wiki:LocalPage text] return self._word_repl(url, text) wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, url) +#RS evaluate some keywords that can be set by pragmas + for key in self.request.pagevars: + value=self.request.getPragma("var_%s" % key, "") + wikiurl=wikiurl.replace("$var_%s" % key, value) +#RS + wikiurl = wikiutil.mapURL(self.request,wikiurl) href = wikiutil.join_wiki(wikiurl, wikitail) # check for image URL, and possibly return IMG tag if not kw.get('pretty_url', 0) and wikiutil.isPicture(wikitail): return self.formatter.image(src=href) # link to self? @@ -270,14 +284,15 @@ attrs='title="%s"' % (_('Edit drawing %(filename)s') % {'filename': self.formatter.text(fname)})) else: return self.formatter.image(alt=url, src=AttachFile.getAttachUrl(pagename, url, self.request, addts=1)) # try to inline the attachment (parser know what they # can handle) + base, ext = os.path.splitext(url) if inline: Parser = wikiutil.getParserForExtension(self.cfg, ext) if Parser is not None: content = file(fpath, 'r').read() # Try to decode text. It might return junk, but we don't # have enough information with attachments. @@ -526,15 +541,18 @@ """Handle definition lists.""" result = [] self._close_item(result) #self.inhibit_p = 1 self.in_dd = 1 result.extend([ self.formatter.definition_term(1), - self.formatter.text(match[1:-3]), +#RS ignore character formatting inside DT +# self.formatter.text(match[1:-3]), + self.formatter.text(match[1:-3].replace("'","")), +#RS end self.formatter.definition_term(0), self.formatter.definition_desc(1), ## CHANGE: no automatic paragraph ##self.formatter.paragraph(1) ]) return ''.join(result)
MoinMoin.formatter.base
--- E:\Install\MoinMoin\moin-1.3.5.tar\moin-1.3.5\MoinMoin\formatter\base.py Tue Jul 26 20:46:52 2005 +++ E:\moin13\Lib\site-packages\MoinMoin\formatter\base.py Tue Sep 06 23:52:30 2005 @@ -1,13 +1,15 @@ # -*- coding: iso-8859-1 -*- """ MoinMoin - Formatter Base Class @copyright: 2000 - 2004 by Jürgen Hermann <jh@web.de> @license: GNU GPL, see COPYING for details. + ORS modifications: + 08.01.04 RS mimetype and pure-handler (used in special formatters for dump) """ from MoinMoin import wikiutil import re, types class FormatterBase: """ This defines the output interface used all over the rest of the code. @@ -18,15 +20,17 @@ """ hardspace = ' ' def __init__(self, request, **kw): self.request = request self._ = request.getText - +#RS additional property "mimetype" + self.mimetype="text/base" +#RS end self._store_pagelinks = kw.get('store_pagelinks', 0) self._terse = kw.get('terse', 0) self.pagelinks = [] self.in_p = 0 self.in_pre = 0 self._highlight_re = None self._base_depth = 0 @@ -107,14 +111,27 @@ return u'<img%s>' % attrstr def smiley(self, text): return text # Text and Text Attributes ########################################### +#RS additional handler for pure +#may be obsolete as text is now properly used by parser?? + def pure(self, text): + """ + this handles the "not in any markup" case + used in formatters with "side effects" + """ + return self._text(text) + + def nbsp(self): + return self.hardspace + +#RS end def text(self, text): if not self._highlight_re: return self._text(text) result = [] lastpos = 0 match = self._highlight_re.search(text)
MoinMoin.formatter.text_html
--- E:\Install\MoinMoin\moin-1.3.5.tar\moin-1.3.5\MoinMoin\formatter\text_html.py Tue Jul 26 20:46:52 2005 +++ E:\moin13\Lib\site-packages\MoinMoin\formatter\text_html.py Tue Sep 27 18:15:01 2005 @@ -1,13 +1,22 @@ # -*- coding: iso-8859-1 -*- """ MoinMoin - "text/html+css" Formatter @copyright: 2000 - 2004 by Jürgen Hermann <jh@web.de> @license: GNU GPL, see COPYING for details. + ORS modifications: + 08.01.04 RS mimetype + 08.01.04 RS fix for heading depth calculation (not yet active, check if still needed) + 13.01.04 RS taken implementation of image from FormatterBase + 05.02.04 RS allow 'class' attribute in table/tr/td tags + 09.02.04 RS support for SVG viewer + 24.02.04 RS in pagelink, store request to Page(pagename) so that export mode can be checked in Page.link_to() + 1.3.3 re-migration of patches started 31.01.05 + 07.03.04 RS applied fix (patch 652++) for wiki:Self:../SubPage syntax """ from MoinMoin.formatter.base import FormatterBase from MoinMoin import wikiutil, i18n, config from MoinMoin.Page import Page class Formatter(FormatterBase): @@ -15,14 +24,17 @@ Send HTML data. """ hardspace = ' ' def __init__(self, request, **kw): apply(FormatterBase.__init__, (self, request), kw) +#RS additional property "mimetype" + self.mimetype="text/html" +#RS end # inline tags stack. When an inline tag is called, it goes into # the stack. When a block element starts, all inline tags in # the stack are closed. self._inlineStack = [] self._in_li = 0 @@ -144,14 +156,22 @@ # The code that calls us should keep correct calling order. if tag in self._inlineStack: self._inlineStack.remove(tag) return '</%s>' % tag # Public methods ################################################### + def startDocument(self, pagename): + return "" + + def endDocument(self): + if self.request.export_mode: + return "\n<!-- EOD -->\n</body>\n</html>\n" + return "" + def startContent(self, content_id='content', **kwargs): """ Start page content div """ # Setup id if content_id!='content': aid = 'top_%s' % (content_id,) @@ -733,10 +753,33 @@ attrs = self._checkTableAttr(attrs, '') return self.open(tag, newline=1, attr=attrs) return self.close(tag) def escapedText(self, text): return wikiutil.escape(text) +#RS taken from base + def image(self, **kw): + """ Take HTML <IMG> tag attributes in `attr`. + + Attribute names have to be lowercase! + """ + attrstr = u'' + for attr, value in kw.items(): + if attr=='html_class': + attr='class' + attrstr = attrstr + u' %s="%s"' % (attr, wikiutil.escape(value)) + +#RS special coding for SVG images + src=kw.get('src','') + if src.endswith('.svg') or src.endswith('.svgz'): + return u'<embed%s/>' % attrstr + else: + return u'<img%s/>' % attrstr + + def nbsp(self): + return ' ' + +#RS end + def rawHTML(self, markup): return markup -
Additions to the configuration
#the physical path to your /wiki url, needed to export smiley images etc. url_prefix_dir = 'E:\\moin13\\share\\moin\\htdocs\\'
You also need to have a way to configure the target export directory - at the moment I have not bothered to integrate this int the config, but rather define it in the used action or command batch.
Additional files
MoinMoin.request_ors
I have derived from the core request classes to encapsulate some general patches and enhancements. Again, you do probably not want all of those.
- attachment:request_ors.py
MoinMoin.parser.wiki_word
I had to create a modified wiki parser that is only used in the exporter context and only for the text_word and text_pdf formatters. Basically it parses also for unformatted text words and characters which are not needed by the normal parser-formatter combination.
- attachment:wiki_word.py
The Exporter Files
MoinMoin.scripts.moin_export
This is based on moin_dump.py but has been completely refactored into a class and enhanced to fit my purpose.
- attachment:moin_export.py
The new formatters
MoinMoin.formatter.text_word
The implementation is nearly finished for all the main markup features (however migration to 1.3.5 broke some tables etc.), see an export of page SyntaxReference: attachment:SyntaxReference.doc
You need to have Microsoft Word (2000) on your MoinMoin server and should have generated a python wrapper with makepy (oh yes, and you need Mark Hammonds win32 package (win32all build 163), of course). Due to some weird exceptions I have decided to serve the Word control with Visible=1, this means that you will watch Word "typing in" your target document!
- attachment:text_word.py
MoinMoin.formatter.text_pdf
This is still in its early stages and will be published by Alexander Bormann in a few weeks. It needs the reportlab package.
- attachment:text_pdf.py (not ready yet)
Usage Scenarios
Exporting from a command line batch
This can be used to batch export multiple pages matching PAGEPATTERN - be aware that Word may be slow, though ;-().
set GATEWAY_INTERFACE=CGI/1.1 set DUMPNAME=word set PYTHONPATH=E:\moin13\Lib\site-packages set TARGETROOT=E:\moin13 set WIKIURL="http://localhost/moin13/" set DUMPPATH=%TARGETROOT%\dump_%DUMPNAME% set PAGEPATTERN=SyntaxReference set PAGEPATTERN="%PAGEPATTERN%" E:\python23\python.exe -c "from MoinMoin.scripts.moin_export import run; run()" --wiki=%WIKIURL% --format=word --pattern=%PAGEPATTERN% %DUMPPATH% 1>dump.log 2>dumperr.log pause
Exporting from an Action
To use this, you may have to modify the server to use a different request from request_ors.py, in my case I modified the moin.cgi (or you could try to create such a request inside the action?):
from MoinMoin.request_ors import RequestORSCGI request = RequestORSCGI() #disable my more critical modifications request.ors_mod_active=0
Here is a test action that can be applied to a single page to trigger the export of this page (in Word format, but for PDF it looks very similar). We will later provide an action with a proper user dialog (select format, output name ...maybe even return a link to the created file). Right now, the output directory is hardcoded and you must pick up the result file from the server.
1 # Imports
2 import string, time,sys,os,copy
3 from MoinMoin import user, webapi, wikiutil
4 from MoinMoin.PageEditor import PageEditor
5 from MoinMoin.scripts.moin_export import MoinExporter
6
7 def execute(pagename, request):
8 _ = request.getText
9 page = PageEditor(request,pagename)
10 exp_format="word"
11 # exp_format="html"
12 # exp_format="plain"
13 # exp_format="pdf"
14 #must protect a function that is overrided by the exporter
15 qfn_orig=wikiutil.quoteWikinameURL
16 markup_orig=request.cfg.default_markup
17
18 pname=pagename
19
20 #open exporter
21 exporter=MoinExporter()
22 #assign a request (use a copy because we modify the request)
23 exporter.request=copy.copy(request)
24 #set target output directory
25 exporter.setOutputDir(r"E:\moin13\dump_word")
26 #redirect the request to action=print and indicate "export" mode
27 exporter.request.user.show_topbottom=0
28 exporter.request.form['action']='print'
29 exporter.request.form['export']='1'
30 #assign the export formatter
31 exporter.setFormatter(exp_format)
32 #use special parser for some export formats
33 if exp_format in ("word","pdf"):
34 request.cfg.default_markup="wiki_word"
35 #create target file name - this is the plain output of the formatter, the "real" target file
36 #is different for word and pdf as they create it as a "side effect"
37 file = wikiutil.quoteWikinameFS(pname) + exporter.ext
38 #create error log file (right now we always use the same file for all - this may be bad)
39 errfile = os.path.join(exporter.outputdir, 'error.log')
40
41 exporter.errlog = open(errfile, 'w')
42 #dump the page using the formatter
43 output=exporter.dumpPage(pname,file)
44 #close the error log
45 exporter.errlog.close()
46
47
48 #reset overrided function
49 wikiutil.quoteWikinameURL = qfn_orig
50 request.cfg.default_markup=markup_orig
51 #use this to test output
52 # return page.send_page(request, msg='<pre>%s</pre>' % output)
53
54 return page.send_page(request,
55 msg='<strong>%s</strong>' %
56 _('Export of page %s completed.' % pagename))