Mercurial > moin > 1.9
changeset 407:bea43f99cc27
star-merged moin--refactor--1.5 (formatter, parser, converter fixes, see docs/CHANGES.refactor)
Patches applied:
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--base-0
tag of arch@arch.thinkmo.de--2003-archives/moin--main--1.5--patch-399
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-1
CHANGES.refactor file to read and use here
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-2
change version to 1.5.refactor
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-3
deron meranda's formatter-patch-r4.diff
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-4
PEP8 whitespace changes, fixed typos, comments, NO non-trivial code changes
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-5
text_html: use python2.3 sets instead of own code
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-6
some src cosmetics, removed unused code, kwargs -> kw
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-7
make prettyprinting and lineanchors configurable (see TOF), optimize, fix typos
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-8
revert text_gedit's invalid list nesting
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-9
converter: fixed nested lists
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-10
converter: made dl processing similar to ul
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-11
fixed hr crash in blockquote, but needs more fixes to work correctly
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-12
html formatter cleanup and extension (div, span), fix FootNote action, fix rst headline levels
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-13
use formatter.{span,div}
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-14
disabled xml:lang stuff, src whitespace cosmetics
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-15
fix for having multiple p in one li
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-16
fix _open/_close calls for text_gedit, new . bulletless list markup
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-17
updated CHANGES
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-18
fixed MoinMoinBugs/WikiParserThinksItIsInsidePreWhenItIsNot
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-19
allow hex and symbolic entities
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-20
removed some unused code, src cosmetics
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-21
fixed MoinMoinBugs/ListItemGeneratedOutsideList
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-22
fix for wrong p after macro
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-23
html formatter now know about blockquote being a block element
* arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-24
GUI editor converter now also accepts relative/same server http: URLs
imported from: moin--main--1.5--patch-411
author | Thomas Waldmann <tw@waldmann-edv.de> |
---|---|
date | Tue, 31 Jan 2006 21:17:13 +0000 |
parents | 0ff631c36afb |
children | bf40a8d29393 |
files | ChangeLog MoinMoin/PageEditor.py MoinMoin/converter/text_html_text_x_moin.py MoinMoin/formatter/__init__.py MoinMoin/formatter/base.py MoinMoin/formatter/dom_xml.py MoinMoin/formatter/pagelinks.py MoinMoin/formatter/text_gedit.py MoinMoin/formatter/text_html.py MoinMoin/formatter/text_plain.py MoinMoin/formatter/text_python.py MoinMoin/formatter/text_xml.py MoinMoin/formatter/xml_docbook.py MoinMoin/macro/FootNote.py MoinMoin/macro/Include.py MoinMoin/parser/python.py MoinMoin/parser/rst.py MoinMoin/parser/wiki.py MoinMoin/search.py MoinMoin/version.py MoinMoin/wikimacro.py docs/CHANGES.refactor wiki/htdocs/classic/css/common.css wiki/htdocs/modern/css/common.css wiki/htdocs/rightsidebar/css/common.css |
diffstat | 25 files changed, 1346 insertions(+), 598 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Tue Jan 31 21:09:45 2006 +0000 +++ b/ChangeLog Tue Jan 31 21:17:13 2006 +0000 @@ -2,6 +2,142 @@ # arch-tag: automatic-ChangeLog--arch@arch.thinkmo.de--2003-archives/moin--main--1.5 # +2006-01-31 22:17:13 GMT Thomas Waldmann <tw@waldmann-edv.de> patch-411 + + Summary: + star-merged moin--refactor--1.5 (formatter, parser, converter fixes, see docs/CHANGES.refactor) + Revision: + moin--main--1.5--patch-411 + + star-merged moin--refactor--1.5 (formatter, parser, converter fixes, see docs/CHANGES.refactor) + + Patches applied: + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--base-0 + tag of arch@arch.thinkmo.de--2003-archives/moin--main--1.5--patch-399 + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-1 + CHANGES.refactor file to read and use here + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-2 + change version to 1.5.refactor + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-3 + deron meranda's formatter-patch-r4.diff + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-4 + PEP8 whitespace changes, fixed typos, comments, NO non-trivial code changes + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-5 + text_html: use python2.3 sets instead of own code + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-6 + some src cosmetics, removed unused code, kwargs -> kw + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-7 + make prettyprinting and lineanchors configurable (see TOF), optimize, fix typos + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-8 + revert text_gedit's invalid list nesting + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-9 + converter: fixed nested lists + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-10 + converter: made dl processing similar to ul + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-11 + fixed hr crash in blockquote, but needs more fixes to work correctly + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-12 + html formatter cleanup and extension (div, span), fix FootNote action, fix rst headline levels + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-13 + use formatter.{span,div} + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-14 + disabled xml:lang stuff, src whitespace cosmetics + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-15 + fix for having multiple p in one li + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-16 + fix _open/_close calls for text_gedit, new . bulletless list markup + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-17 + updated CHANGES + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-18 + fixed MoinMoinBugs/WikiParserThinksItIsInsidePreWhenItIsNot + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-19 + allow hex and symbolic entities + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-20 + removed some unused code, src cosmetics + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-21 + fixed MoinMoinBugs/ListItemGeneratedOutsideList + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-22 + fix for wrong p after macro + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-23 + html formatter now know about blockquote being a block element + + * arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-24 + GUI editor converter now also accepts relative/same server http: URLs + + + new files: + docs/.arch-ids/CHANGES.refactor.id docs/CHANGES.refactor + + modified files: + ChangeLog MoinMoin/PageEditor.py + MoinMoin/converter/text_html_text_x_moin.py + MoinMoin/formatter/__init__.py MoinMoin/formatter/base.py + MoinMoin/formatter/dom_xml.py MoinMoin/formatter/pagelinks.py + MoinMoin/formatter/text_gedit.py + MoinMoin/formatter/text_html.py + MoinMoin/formatter/text_plain.py + MoinMoin/formatter/text_python.py + MoinMoin/formatter/text_xml.py + MoinMoin/formatter/xml_docbook.py MoinMoin/macro/FootNote.py + MoinMoin/macro/Include.py MoinMoin/parser/python.py + MoinMoin/parser/rst.py MoinMoin/parser/wiki.py + MoinMoin/search.py MoinMoin/version.py MoinMoin/wikimacro.py + wiki/htdocs/classic/css/common.css + wiki/htdocs/modern/css/common.css + wiki/htdocs/rightsidebar/css/common.css + + new patches: + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--base-0 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-1 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-2 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-3 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-4 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-5 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-6 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-7 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-8 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-9 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-10 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-11 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-12 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-13 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-14 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-15 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-16 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-17 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-18 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-19 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-20 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-21 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-22 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-23 + arch@arch.thinkmo.de--2003-archives/moin--refactor--1.5--patch-24 + + 2006-01-31 22:09:45 GMT Thomas Waldmann <tw@waldmann-edv.de> patch-410 Summary:
--- a/MoinMoin/PageEditor.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/PageEditor.py Tue Jan 31 21:17:13 2006 +0000 @@ -402,14 +402,16 @@ self.request.write("</form>") # QuickHelp originally by Georg Mischler <schorsch@lightingwiki.com> - self.request.write('<div id="editor-help">\n' + _(""" Emphasis:: [[Verbatim('')]]''italics''[[Verbatim('')]]; [[Verbatim(''')]]'''bold'''[[Verbatim(''')]]; [[Verbatim(''''')]]'''''bold italics'''''[[Verbatim(''''')]]; [[Verbatim('')]]''mixed ''[[Verbatim(''')]]'''''bold'''[[Verbatim(''')]] and italics''[[Verbatim('')]]; [[Verbatim(----)]] horizontal rule. + self.request.write(self.request.formatter.div(1, id="editor-help")) + self.request.write(_(""" Emphasis:: [[Verbatim('')]]''italics''[[Verbatim('')]]; [[Verbatim(''')]]'''bold'''[[Verbatim(''')]]; [[Verbatim(''''')]]'''''bold italics'''''[[Verbatim(''''')]]; [[Verbatim('')]]''mixed ''[[Verbatim(''')]]'''''bold'''[[Verbatim(''')]] and italics''[[Verbatim('')]]; [[Verbatim(----)]] horizontal rule. Headings:: [[Verbatim(=)]] Title 1 [[Verbatim(=)]]; [[Verbatim(==)]] Title 2 [[Verbatim(==)]]; [[Verbatim(===)]] Title 3 [[Verbatim(===)]]; [[Verbatim(====)]] Title 4 [[Verbatim(====)]]; [[Verbatim(=====)]] Title 5 [[Verbatim(=====)]]. Lists:: space and one of: * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents. Links:: [[Verbatim(JoinCapitalizedWords)]]; [[Verbatim(["brackets and double quotes"])]]; url; [url]; [url label]. Tables:: || cell text |||| cell text spanning 2 columns ||; no trailing white space allowed after tables or titles. (!) For more help, see HelpOnEditing or SyntaxReference. -""") + '\n</div>\n') +""")) + self.request.write(self.request.formatter.div(0)) if preview is not None: if staytop:
--- a/MoinMoin/converter/text_html_text_x_moin.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/converter/text_html_text_x_moin.py Tue Jan 31 21:17:13 2006 +0000 @@ -537,24 +537,6 @@ def visit_text(self, node): self.text.append(node.data) - def process_dl(self, node): - self.depth += 1 - indent = " " * self.depth - for i in node.childNodes: - if i.nodeType == Node.ELEMENT_NODE: - if i.localName == 'dt': - self.text.append(indent) - text = self.node_list_text_only(i.childNodes) - self.text.append(text.replace("\n", " ")) - elif i.localName == 'dd': - self.text.append(":: ") - self.process_list_item(i) - else: - raise ConvertError("Illegal list element %s" % i.localName) - if self.depth == 1: - self.text.append("\n") - self.depth -= 1 - def process_heading(self, node): text = self.node_list_text_only(node.childNodes).strip() if text: @@ -565,22 +547,54 @@ self.text.append(self.new_line) def _get_list_item_markup(self, list, listitem): - markup = " " * self.depth - type = None - if list.localName == 'ol': + before = "" + #indent = str(self.depth) * self.depth # nice for debugging :) + indent = " " * self.depth + markup = "" + name = list.localName + if name == 'ol': + class_ = listitem.getAttribute("class") + if class_ == "gap": + before = "\n" if list.hasAttribute("type"): type = list.getAttribute("type") else: type = "1" - markup = "%s%s. " % (markup, type) - else: + markup = "%s. " % type + elif name == 'ul': class_ = listitem.getAttribute("class") if class_ == "gap": - markup = "\n" + markup + before = "\n" style = listitem.getAttribute("style") - if not re.match(u"list-style-type:\s*none", style, re.I): - markup += "* " - return markup + if re.match(u"list-style-type:\s*none", style, re.I): + markup = ". " + else: + markup = "* " + elif name == 'dl': + markup = ":: " + else: + raise ConvertError("Illegal list type %s" % name) + return before, indent, markup + + def process_dl(self, node): + self.depth += 1 + markup = ":: " # can there be a dl dd without dt? + for i in node.childNodes: + if i.nodeType == Node.ELEMENT_NODE: + name = i.localName + if name == 'dt': + before, indent, markup = self._get_list_item_markup(node, i) + self.text.append(before+indent) + text = self.node_list_text_only(i.childNodes) + self.text.append(text.replace("\n", " ")) + elif name == 'dd': + self.text.append(markup) + self.process_list_item(i, indent) + else: + raise ConvertError("Illegal list element %s" % i.localName) + self.depth -= 1 + if self.depth == 0: + self.text.append("\n") def process_list(self, node): self.depth += 1 @@ -588,27 +602,33 @@ if i.nodeType == Node.ELEMENT_NODE: name = i.localName if name == 'li': - self.text.append(self._get_list_item_markup(node, i)) - self.process_list_item(i) + before, indent, markup = self._get_list_item_markup(node, i) + self.text.append(before+indent+markup) + self.process_list_item(i, indent) elif name in ('ol', 'ul',): self.process_list(i) elif name == 'dl': self.process_dl(i) else: raise ConvertError("Illegal list element %s" % i.localName) - if self.depth == 1: - self.text.append("\n") self.depth -= 1 + if self.depth == 0: + self.text.append("\n") - def process_list_item(self, node): + def process_list_item(self, node, indent): found = False + first_child = True for i in node.childNodes: name = i.localName if name == 'p': + if not first_child: + self.text.append(indent) self.process_paragraph_item(i) self.text.append("\n") found = True elif name == 'pre': + if not first_child: + self.text.append(indent) self.process_preformatted_item(i) found = True elif name in ('ol', 'ul',): @@ -618,16 +638,23 @@ self.process_dl(i) found = True elif name == 'table': + if not first_child: + self.text.append(indent) self.process_table(i) found = True #else: # self.process_inline(i) + first_child = False if not found: self.process_paragraph_item(node) self.text.append("\n") def process_blockquote(self, node): + # XXX this does not really work. e.g.: + # <bq>aaaaaa + # <hr----------> + # <bq>bbbbbb self.depth += 1 for i in node.childNodes: if i.nodeType == Node.ELEMENT_NODE: @@ -652,7 +679,9 @@ self.visit_node_list_element_only(i.childNodes) elif name == 'blockquote': self.process_blockquote(i) - elif name in ('br',): + elif name == 'hr': + self.process_hr(i) + elif name == 'br': self.process_br(i) else: raise ConvertError("process_blockquote: Don't support %s element" % name) @@ -1130,7 +1159,7 @@ pass #print name, data, filename, alt raise ConvertError("Unknown smiley icon '%s'" % filename) # Image URL - elif src and src.startswith("http://") and wikiutil.isPicture(src): + elif src and src.startswith("http:") and wikiutil.isPicture(src): self.text.extend([self.white_space, src, self.white_space]) else: raise ConvertError("Strange image src: '%s'" % src)
--- a/MoinMoin/formatter/__init__.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/__init__.py Tue Jan 31 21:17:13 2006 +0000 @@ -10,3 +10,4 @@ from MoinMoin.util import pysupport modules = pysupport.getPackageModules(__file__) +
--- a/MoinMoin/formatter/base.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/base.py Tue Jan 31 21:17:13 2006 +0000 @@ -62,7 +62,7 @@ def endDocument(self): return "" - def startContent(self, content_id="content", **kwargs): + def startContent(self, content_id="content", **kw): return "" def endContent(self): @@ -87,7 +87,7 @@ # call pagelink() for internal interwikilinks # to make shure they get counted for self.pagelinks wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename)) - if wikitag=='Self' or wikitag==self.request.cfg.interwikiname: + if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname: if wikitail.find('#') > -1: wikitail, kw['anchor'] = wikitail.split('#', 1) wikitail = wikiutil.url_unquote(wikitail) @@ -128,30 +128,33 @@ return self.attachment_link(url, text) - def anchordef(self, name): return "" def line_anchordef(self, lineno): return "" - def anchorlink(self, on, name='', id=None): + def anchorlink(self, on, name='', **kw): return "" def line_anchorlink(self, on, lineno=0): return "" - def image(self, **kw): - """ Take HTML <IMG> tag attributes in `attr`. + def image(self, src=None, **kw): + """An inline image. - Attribute names have to be lowercase! + Extra keyword arguments are according to the HTML <img> tag attributes. + In particular an 'alt' or 'title' argument should give a description + of the image. """ - attrstr = u'' - for attr, value in kw.items(): - if attr=='html_class': - attr='class' - attrstr = attrstr + u' %s="%s"' % (attr, wikiutil.escape(value)) - return u'<img%s>' % attrstr + title = src + for titleattr in ('title', 'html__title', 'alt', 'html__alt'): + if kw.has_key(titleattr): + title = kw[titleattr] + break + if title: + return '[Image:%s]' % title + return '[Image]' def smiley(self, text): return text @@ -161,7 +164,7 @@ # Text and Text Attributes ########################################### - def text(self, text): + def text(self, text, **kw): if not self._highlight_re: return self._text(text) @@ -185,42 +188,42 @@ def _text(self, text): raise NotImplementedError - def strong(self, on): - raise NotImplementedError - - def emphasis(self, on): - raise NotImplementedError - - def underline(self, on): + def strong(self, on, **kw): raise NotImplementedError - def highlight(self, on): + def emphasis(self, on, **kw): raise NotImplementedError - def sup(self, on): + def underline(self, on, **kw): raise NotImplementedError - def sub(self, on): + def highlight(self, on, **kw): raise NotImplementedError - def strike(self, on): + def sup(self, on, **kw): + raise NotImplementedError + + def sub(self, on, **kw): + raise NotImplementedError + + def strike(self, on, **kw): raise NotImplementedError def code(self, on, **kw): raise NotImplementedError - def preformatted(self, on): + def preformatted(self, on, **kw): self.in_pre = on != 0 - def small(self, on): + def small(self, on, **kw): raise NotImplementedError - def big(self, on): + def big(self, on, **kw): raise NotImplementedError # special markup for syntax highlighting ############################# - def code_area(self, on, code_id, **kwargs): + def code_area(self, on, code_id, **kw): raise NotImplementedError def code_line(self, on): @@ -234,10 +237,10 @@ def linebreak(self, preformatted=1): raise NotImplementedError - def paragraph(self, on): - self.in_p = (on != 0) + def paragraph(self, on, **kw): + self.in_p = on != 0 - def rule(self, size=0): + def rule(self, size=0, **kw): raise NotImplementedError def icon(self, type): @@ -245,22 +248,22 @@ # Lists ############################################################## - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): raise NotImplementedError - def bullet_list(self, on): + def bullet_list(self, on, **kw): raise NotImplementedError def listitem(self, on, **kw): raise NotImplementedError - def definition_list(self, on): + def definition_list(self, on, **kw): raise NotImplementedError - def definition_term(self, on, compact=0): + def definition_term(self, on, compact=0, **kw): raise NotImplementedError - def definition_desc(self, on): + def definition_desc(self, on, **kw): raise NotImplementedError def heading(self, on, depth, **kw): @@ -268,13 +271,13 @@ # Tables ############################################################# - def table(self, on, attrs={}): + def table(self, on, attrs={}, **kw): raise NotImplementedError - def table_row(self, on, attrs={}): + def table_row(self, on, attrs={}, **kw): raise NotImplementedError - def table_cell(self, on, attrs={}): + def table_cell(self, on, attrs={}, **kw): raise NotImplementedError # Dynamic stuff / Plugins ############################################ @@ -284,7 +287,7 @@ return macro_obj.execute(name, args) def _get_bang_args(self, line): - if line[:2]=='#!': + if line[:2] == '#!': try: name, args = line[2:].split(None, 1) except ValueError: @@ -293,7 +296,7 @@ return args return None - def processor(self, processor_name, lines, is_parser = 0): + def processor(self, processor_name, lines, is_parser=0): """ processor_name MUST be valid! writes out the result instead of returning it! """ @@ -306,14 +309,14 @@ processor_name, "Parser") args = self._get_bang_args(lines[0]) if args is not None: - lines=lines[1:] - p = parser('\n'.join(lines), self.request, format_args = args) + lines = lines[1:] + p = parser('\n'.join(lines), self.request, format_args=args) p.format(self) del p return '' - def dynamic_content(self, parser, callback, arg_list = [], arg_dict = {}, - returns_content = 1): + def dynamic_content(self, parser, callback, arg_list=[], arg_dict={}, + returns_content=1): content = parser[callback](*arg_list, **arg_dict) if returns_content: return content @@ -322,6 +325,14 @@ # Other ############################################################## + def div(self, on, **kw): + """ open/close a blocklevel division """ + return "" + + def span(self, on, **kw): + """ open/close a inline span """ + return "" + def rawHTML(self, markup): """ This allows emitting pre-formatted HTML markup, and should be used wisely (i.e. very seldom). @@ -342,7 +353,7 @@ return self.text(f.getvalue()) - def escapedText(self, on): + def escapedText(self, on, **kw): """ This allows emitting text as-is, anything special will be escaped (at least in HTML, some text output format would possibly do nothing here) @@ -351,3 +362,4 @@ def comment(self, text): return "" +
--- a/MoinMoin/formatter/dom_xml.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/dom_xml.py Tue Jan 31 21:17:13 2006 +0000 @@ -29,8 +29,8 @@ 'p', 'ol', 'ul', 'li', 'pre', 'a', 'table', 'td', 'tr'] - need_p = [] #format_tags[:] - need_p.extend(['ol', 'a', 'pagelink', 'interwiki', 'macro']) #XXX add more + need_p = [] # format_tags[:] + need_p.extend(['ol', 'a', 'pagelink', 'interwiki', 'macro']) # XXX add more no_p_after = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'ol', 'ul', 'pre', 'small', 'big', 'table', 'td', 'tr', 'dt', @@ -38,25 +38,25 @@ 'sysmesg'] close_on_open = { - 'h1' : ['p'], - 'li' : ['li'], - 'p' : ['p'], - #'pre' : ['p'], + 'h1': ['p'], + 'li': ['li'], + 'p': ['p'], + #'pre': ['p'], } - for i in xrange(2,7): + for i in xrange(2, 7): close_on_open['h%i' % i] = close_on_open['h1'] close_on_open = {} # XXX close_on_close = { - 'table' : ['td', 'tr'], - 'td' : ['tr'], - 'tr' : ['td'], - 'ol' : ['li'], - 'ul' : ['li'], + 'table': ['td', 'tr'], + 'td': ['tr'], + 'tr': ['td'], + 'ol': ['li'], + 'ul': ['li'], } - close_on_close = {} #XXX + close_on_close = {} # XXX def __init__(self, request, **kw): self.request = request @@ -95,7 +95,7 @@ must be the last opened tag!!! """ if tag == 'p': - self.in_p = 0 #XXX + self.in_p = 0 # XXX if self.tag_stack[-1][0] != tag: raise ValueError, "<%s> expected <%s> given" % (self.tag_stack[-1][0], tag) self.position = self.position.parentNode @@ -220,8 +220,8 @@ self.text('\n'.join(lines)) + self._set_tag('processor', False)) - def dynamic_content(self, parser, callback, arg_list = [], arg_dict = {}, - returns_content = 1): + def dynamic_content(self, parser, callback, arg_list=[], arg_dict={}, + returns_content=1): content = parser[callback](*arg_list, **arg_dict) if returns_content: return content @@ -232,7 +232,7 @@ kw['href'] = str(url) if css: kw['class'] = str(css) - return self._set_tag('a', on, **kw) + return self._set_tag('a', on, **kw) def attachment_link(self, on, url='', **kw): kw['href'] = url @@ -253,7 +253,7 @@ kw['type'] = 'inline' return self._add_tag('attachment', **kw) - def rule(self, size=0): + def rule(self, size=0, **kw): return self._add_tag('hr', size=str(size)) def icon(self, type): @@ -262,41 +262,41 @@ def smiley(self, type): return self._add_tag('smiley', type=type) - def strong(self, on): + def strong(self, on, **kw): return self._set_tag('b', on) - def emphasis(self, on): + def emphasis(self, on, **kw): return self._set_tag('em', on) - def highlight(self, on): + def highlight(self, on, **kw): return self._set_tag('highlight', on) - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): return self._set_tag('ol', on, type=type, start=start) - def bullet_list(self, on): + def bullet_list(self, on, **kw): return self._set_tag('ul', on) def listitem(self, on, **kw): return self._set_tag('li', on) - def sup(self, on): + def sup(self, on, **kw): return self._set_tag('sup', on) - def sub(self, on): + def sub(self, on, **kw): return self._set_tag('sub', on) - def strike(self, on): + def strike(self, on, **kw): return self._set_tag('strike', on) def code(self, on, **kw): return self._set_tag('code', on) - def preformatted(self, on): + def preformatted(self, on, **kw): self.in_pre = on != 0 return self._set_tag('pre', on) - def paragraph(self, on): + def paragraph(self, on, **kw): FormatterBase.paragraph(self, on) return self._set_tag('p', on) @@ -315,31 +315,28 @@ result[str(name)] = value return result - def table(self, on, attrs={}): + def table(self, on, attrs={}, **kw): return self._set_tag('table', on, **self._check_attrs(attrs)) - def table_row(self, on, attrs={}): + def table_row(self, on, attrs={}, **kw): return self._set_tag('tr', on, **self._check_attrs(attrs)) - def table_cell(self, on, attrs={}): + def table_cell(self, on, attrs={}, **kw): return self._set_tag('td', on, **self._check_attrs(attrs)) def anchordef(self, name): return self._add_tag('anchor', name=name) - def anchorlink(self, on, name, id=None): - kw = {} - if id: - kw['id'] = str(id) + def anchorlink(self, on, name, **kw): return self.url(on, "#" + name, **kw) - def underline(self, on): + def underline(self, on, **kw): return self._set_tag('u', on) - def definition_list(self, on): + def definition_list(self, on, **kw): return self._set_tag('dl', on) - def definition_term(self, on, compact=0): + def definition_term(self, on, compact=0, **kw): # XXX may be not correct # self._langAttr() missing if compact and on: @@ -347,30 +344,32 @@ else: return self._set_tag('dt', on) - def definition_desc(self, on): + def definition_desc(self, on, **kw): # self._langAttr() missing return self._set_tag('dd', on) - def image(self, **kw): + def image(self, src=None, **kw): """ Take HTML <IMG> tag attributes in `attr`. Attribute names have to be lowercase! """ + if src: + kw['src'] = src return self._add_tag('img', **kw) - def escapedText(self, text): + def escapedText(self, text, **kw): return wikiutil.escape(text) - def small(self, on): + def small(self, on, **kw): return self._set_tag('small', on) - def big(self, on): + def big(self, on, **kw): return self._set_tag('big', on) def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): - kw = {'id' : code_id, - 'type' : code_type, - 'show' : show, + kw = {'id': code_id, + 'type': code_type, + 'show': show, } if start != -1: kw['start'] = start
--- a/MoinMoin/formatter/pagelinks.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/pagelinks.py Tue Jan 31 21:17:13 2006 +0000 @@ -1,14 +1,13 @@ # -*- coding: iso-8859-1 -*- """ -MoinMoin - pagelinks Formatter + MoinMoin - pagelinks Formatter -@copyright: 2005 Nir Soffer <nirs@freeshell.org> -@license: GNU GPL, see COPYING for details. + @copyright: 2005 Nir Soffer <nirs@freeshell.org> + @license: GNU GPL, see COPYING for details. """ from MoinMoin.formatter.base import FormatterBase - class Formatter(FormatterBase): """ Collect pagelinks and format nothing :-) """ @@ -57,13 +56,4 @@ attachment_link = null attachment_image = null attachment_drawing = null - - # These are private additions to formatter added by text_html, and - # some code use or might use them. - open = null - close = null - formatAttributes = null - - def langAttr(self, lang=None): - return {} - +
--- a/MoinMoin/formatter/text_gedit.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/text_gedit.py Tue Jan 31 21:17:13 2006 +0000 @@ -1,6 +1,6 @@ # -*- coding: iso-8859-1 -*- """ - MoinMoin - "text/html+css" Formatter + MoinMoin - "text/html+css" Formatter for feeding the GUI editor @copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann @license: GNU GPL, see COPYING for details. @@ -19,7 +19,7 @@ # Block elements #################################################### - def heading(self, on, depth, id = None, **kw): + def heading(self, on, depth, id=None, **kw): # remember depth of first heading, and adapt counting depth accordingly if not self._base_depth: self._base_depth = depth @@ -29,9 +29,9 @@ # closing tag, with empty line after, to make source more readable if not on: - return self.close('h%d' % heading_depth) + return self._close('h%d' % heading_depth) else: - return self.open('h%d' % heading_depth) + return self._open('h%d' % heading_depth) # Links ############################################################## @@ -60,25 +60,8 @@ return self.url(1, href, title=title, unescaped=0, css=html_class) # unescaped=1 was changed to 0 to make interwiki links with pages with umlauts (or other non-ascii) work - ''' - def attachment_link(self, url, text, **kw): - if url==text: - return "attachment:%s" % url - else: - return "[attachment:%s %s]" % (url, text) - - def attachment_image(self, url, **kw): - return "attachment:%s" % url - - def attachment_drawing(self, url, text, **kw): - if url==text: - return "drawing:%s" % url - else: - return "[drawing:%s %s]" % (url, text) -''' - def attachment_inlined(self, url, text, **kw): - if url==text: + if url == text: return '<span style="background-color:#ffff11">inline:%s</span>' % url else: return '<span style="background-color:#ffff11">[inline:%s %s]</span>' % (url, text) @@ -123,7 +106,7 @@ result = "[[%s]]" % name return '<span style="background-color:#ffff11">%s</span>' % result - def processor(self, processor_name, lines, is_parser = 0): + def processor(self, processor_name, lines, is_parser=0): """ processor_name MUST be valid! writes out the result instead of returning it! """ @@ -135,41 +118,17 @@ return "".join(result) - - # Lists ############################################################## - - # Change nesting: sub lists are no longer within the <li> tags - - def number_list(self, on, type=None, start=None): - li = "" - if self._in_li: # close <li> - li = self.listitem(False) - return li + text_html.Formatter.number_list(self, on, type, start) - - def bullet_list(self, on): - li = "" - if self._in_li: # close <li> - li = self.listitem(False) - return li + text_html.Formatter.bullet_list(self, on) - - def listitem(self, on, **kw): - # only if not already closed - if on or self._in_li: - return text_html.Formatter.listitem(self, on, **kw) - else: - return "" - # Other ############################################################## style2attribute = { 'width': 'width', 'height': 'height', - 'background' : 'bgcolor', - 'background-color' : 'bgcolor', + 'background': 'bgcolor', + 'background-color': 'bgcolor', #if this is used as table style="text-align: right", it doesn't work #if it is transformed to align="right": - #'text-align' : 'align', - #'vertical-align' : 'valign' + #'text-align': 'align', + #'vertical-align': 'valign' } def _style_to_attributes(self, attrs): @@ -197,7 +156,7 @@ attrs = text_html.Formatter._checkTableAttr(self, attrs, prefix) return self._style_to_attributes(attrs) - def table(self, on, attrs=None): + def table(self, on, attrs=None, **kw): """ Create table @param on: start table @@ -214,36 +173,38 @@ #result.append(self.rawHTML("<!-- ATTRS1: %s -->" % repr(attrs))) attrs = self._checkTableAttr(attrs, 'table') #result.append(self.rawHTML("<!-- ATTRS2: %s -->" % repr(attrs))) - result.append(self.open('table', newline=1, attr=attrs)) + result.append(self._open('table', newline=1, attr=attrs)) else: # Close table then div - result.append(self.close('table')) + result.append(self._close('table')) return ''.join(result) - def comment(self, text): + def comment(self, text, **kw): text = text.rstrip() # workaround for growing amount of blanks at EOL return self.preformatted(1, attr={'class': 'comment'}) + text + self.preformatted(0) - def underline(self, on): + def underline(self, on, **kw): tag = 'u' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag) + return self._close(tag) - def strong(self, on): + def strong(self, on, **kw): tag = 'b' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag) + return self._close(tag) - def emphasis(self, on): + def emphasis(self, on, **kw): tag = 'i' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag) + return self._close(tag) - def code(self, on, css=None): + def code(self, on, css=None, **kw): + if not css and kw.has_key('css_class'): + css = kw['css_class'] tag = 'tt' # Maybe we don't need this, because we have tt will be in inlineStack. self._in_code = on @@ -253,8 +214,8 @@ attrs = None if on: - return self.open(tag, attr=attrs) - return self.close(tag) + return self._open(tag, attr=attrs) + return self._close(tag) def line_anchordef(self, lineno): return '' # not needed for gui editor feeding
--- a/MoinMoin/formatter/text_html.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/text_html.py Tue Jan 31 21:17:13 2006 +0000 @@ -6,17 +6,167 @@ @license: GNU GPL, see COPYING for details. """ import os.path, re +from sets import Set # TODO: when we require Python 2.4+ use the builtin 'set' type from MoinMoin.formatter.base import FormatterBase from MoinMoin import wikiutil, i18n, config from MoinMoin.Page import Page from MoinMoin.action import AttachFile +line_anchors = False +prettyprint = False + +# These are the HTML elements that we treat as block elements. +_blocks = Set(['dd', 'div', 'dl', 'dt', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'hr', 'li', 'ol', 'p', 'pre', 'table', 'tbody', 'td', 'tfoot', 'th', + 'thead', 'tr', 'ul', 'blockquote', ]) + +# These are the HTML elements which are typically only used with +# an opening tag without a separate closing tag. We do not +# include 'script' or 'style' because sometimes they do have +# content, and also IE has a parsing bug with those two elements (only) +# when they don't have a closing tag even if valid XHTML. + +_self_closing_tags = Set(['area', 'base', 'br', 'col', 'frame', 'hr', 'img', 'input', + 'isindex', 'link', 'meta', 'param']) + +# These are the elements which generally should cause an increase in the +# indention level in the html souce code. +_indenting_tags = Set(['ol', 'ul', 'dl', 'li', 'dt', 'dd', 'tr', 'td']) + +# These are the elements that discard any whitespace they contain as +# immediate child nodes. +_space_eating_tags = Set(['colgroup', 'dl', 'frameset', 'head', 'map' 'menu', + 'ol', 'optgroup', 'select', 'table', 'tbody', 'tfoot', + 'thead', 'tr', 'ul']) + +# These are standard HTML attributes which are typically used without any +# value; e.g., as boolean flags indicated by their presence. +_html_attribute_boolflags = Set(['compact', 'disabled', 'ismap', 'nohref', + 'noresize', 'noshade', 'nowrap', 'readonly', + 'selected', 'wrap']) + +# These are all the standard HTML attributes that are allowed on any element. +_common_attributes = Set(['accesskey', 'class', 'dir', 'disabled', 'id', 'lang', + 'style', 'tabindex', 'title']) + + +def rewrite_attribute_name(name, default_namespace='html'): + """Takes an attribute name and tries to make it HTML correct. + + This function takes an attribute name as a string, as it may be + passed in to a formatting method using a keyword-argument syntax, + and tries to convert it into a real attribute name. This is + necessary because some attributes may conflict with Python + reserved words or variable syntax (such as 'for', 'class', or + 'z-index'); and also to help with backwards compatibility with + older versions of MoinMoin where different names may have been + used (such as 'content_id' or 'css'). + + Returns a tuple of strings: (namespace, attribute). + + Namespaces: The default namespace is always assumed to be 'html', + unless the input string contains a colon or a double-underscore; + in which case the first such occurance is assumed to separate the + namespace prefix from name. So, for example, to get the HTML + attribute 'for' (as on a <label> element), you can pass in the + string 'html__for' or even '__for'. + + Hyphens: To better support hyphens (which are not allowed in Python + variable names), all occurances of two underscores will be replaced + with a hyphen. If you use this, then you must also provide a + namespace since the first occurance of '__' separates a namespace + from the name. + + Special cases: Within the 'html' namespace, mainly to preserve + backwards compatibility, these exceptions ars recognized: + 'content_type', 'content_id', 'css_class', and 'css'. + Additionally all html attributes starting with 'on' are forced to + lower-case. Also the string 'xmlns' is recognized as having + no namespace. + + Examples: + 'id' -> ('html', 'id') + 'css_class' -> ('html', 'class') + 'content_id' -> ('html', 'id') + 'content_type' -> ('html', 'type') + 'html__for' -> ('html', 'for) + 'xml__space' -> ('xml', 'space') + '__z__index' -> ('html', 'z-index') + '__http__equiv' -> ('html', 'http-equiv') + 'onChange' -> ('html', 'onchange') + 'xmlns' -> ('', 'xmlns') + 'xmlns__abc' -> ('xmlns', 'abc') + + (In actuality we only deal with namespace prefixes, not any real + namespace URI...we only care about the syntax not the meanings.) + """ + + # Handle any namespaces (just in case someday we support XHTML) + if ':' in name: + ns, name = name.split(':', 1) + elif '__' in name: + ns, name = name.split('__', 1) + elif name == 'xmlns': + ns = '' + else: + ns = default_namespace + + name.replace('__', '-') + if ns == 'html': + # We have an HTML attribute, fix according to DTD + if name == 'content_type': # MIME type such as in <a> and <link> elements + name = 'type' + elif name == 'content_id': # moin historical convention + name = 'id' + elif name in ('css_class', 'css'): # to avoid python word 'class' + name = 'class' + elif name.startswith('on'): # event handler hook + name = name.lower() + return ns, name + + +def extend_attribute_dictionary(attributedict, ns, name, value): + """Add a new attribute to an attribute dictionary, merging values where possible. + + The attributedict must be a dictionary with tuple-keys of the form: + (namespace, attrname). + + The given ns, name, and value will be added to the dictionary. It + will replace the old value if it existed, except for a few special + cases where the values are logically merged instead (CSS class + names and style rules). + + As a special case, if value is None (not just ''), then the + attribute is actually deleted from the dictionary. + """ + + key = ns, name + if value is None: + if attributedict.has_key(key): + del attributedict[key] + else: + if ns == 'html' and attributedict.has_key(key): + if name == 'class': + # CSS classes are appended by space-separated list + value = attributedict[key] + ' ' + value + elif name == 'style': + # CSS styles are appended by semicolon-separated rules list + value = attributedict[key] + '; ' + value + elif name in _html_attribute_boolflags: + # All attributes must have a value. According to XHTML those + # traditionally used as flags should have their value set to + # the same as the attribute name. + value = name + attributedict[key] = value + + class Formatter(FormatterBase): """ Send HTML data. """ hardspace = ' ' + indentspace = ' ' def __init__(self, request, **kw): apply(FormatterBase.__init__, (self, request), kw) @@ -26,8 +176,11 @@ # the stack are closed. self._inlineStack = [] - self._in_li = 0 - self._in_code = 0 + # stack of all tags + self._tag_stack = [] + self._indent_level = 0 + + self._in_code = 0 # used by text_gedit self._in_code_area = 0 self._in_code_line = 0 self._code_area_num = 0 @@ -36,7 +189,7 @@ self._show_section_numbers = None self._content_ids = [] self.pagelink_preclosed = False - self._is_included = kw.get('is_included',False) + self._is_included = kw.get('is_included', False) self.request = request self.cfg = request.cfg @@ -49,8 +202,9 @@ # code clean and handle pathological cases like unclosed p and # inline tags. - def langAttr(self, lang=None): + def _langAttr(self, lang=None): """ Return lang and dir attribute + (INTERNAL USE BY HTML FORMATTER ONLY!) Must be used on all block elements - div, p, table, etc. @param lang: if defined, will return attributes for lang. if not @@ -67,65 +221,159 @@ # lang is inherited from content div return {} + #attr = {'xml:lang': lang, 'lang': lang, 'dir': i18n.getDirection(lang),} attr = {'lang': lang, 'dir': i18n.getDirection(lang),} return attr - def formatAttributes(self, attr=None): - """ Return formatted attributes string + def _formatAttributes(self, attr=None, allowed_attrs=None, **kw): + """ Return HTML attributes formatted as a single string. (INTERNAL USE BY HTML FORMATTER ONLY!) @param attr: dict containing keys and values - @rtype: string ? + @param allowed_attrs: A list of allowable attribute names + @param **kw: other arbitrary attributes expressed as keyword arguments. + @rtype: string @return: formated attributes or empty string + + The attributes and their values can either be given in the + 'attr' dictionary, or as extra keyword arguments. They are + both merged together. See the function + rewrite_attribute_name() for special notes on how to name + attributes. + + Setting a value to None rather than a string (or string + coercible) will remove that attribute from the list. + + If the list of allowed_attrs is provided, then an error is + raised if an HTML attribute is encountered that is not in that + list (or is not a common attribute which is always allowed or + is not in another XML namespace using the double-underscore + syntax). """ + + # Merge the attr dict and kw dict into a single attributes + # dictionary (rewriting any attribute names, extracting + # namespaces, and merging some values like css classes). + attributes = {} # dict of key=(namespace,name): value=attribute_value if attr: - attr = [' %s="%s"' % (k, v) for k, v in attr.items()] - return ''.join(attr) + for a, v in attr.items(): + a_ns, a_name = rewrite_attribute_name(a) + extend_attribute_dictionary(attributes, a_ns, a_name, v) + if kw: + for a, v in kw.items(): + a_ns, a_name = rewrite_attribute_name(a) + extend_attribute_dictionary(attributes, a_ns, a_name, v) + + # Add title attribute if missing, but it has an alt. + if attributes.has_key(('html', 'alt')) and not attributes.has_key(('html', 'title')): + attributes[('html', 'title')] = attributes[('html', 'alt')] + + # Force both lang and xml:lang to be present and identical if + # either exists. The lang takes precedence over xml:lang if + # both exist. + #if attributes.has_key(('html', 'lang')): + # attributes[('xml', 'lang')] = attributes[('html', 'lang')] + #elif attributes.has_key(('xml', 'lang')): + # attributes[('html', 'lang')] = attributes[('xml', 'lang')] + + # Check all the HTML attributes to see if they are known and + # allowed. Ignore attributes if in non-HTML namespaces. + if allowed_attrs: + for name in [key[1] for key in attributes.keys() if key[0] == 'html']: + if name in _common_attributes or name in allowed_attrs: + pass + elif name.startswith('on'): + pass # Too many event handlers to enumerate, just let them all pass. + else: + # Unknown or unallowed attribute. + err = 'Illegal HTML attribute "%s" passed to formatter' % name + raise ValueError(err) + + # Finally, format them all as a single string. + if attributes: + # Construct a formatted string containing all attributes + # with their values escaped. Any html:* namespace + # attributes drop the namespace prefix. We build this by + # separating the attributes into three categories: + # + # * Those without any namespace (should only be xmlns attributes) + # * Those in the HTML namespace (we drop the html: prefix for these) + # * Those in any other non-HTML namespace, including xml: + + xmlnslist = ['%s="%s"' % (k[1], wikiutil.escape(v, 1)) + for k, v in attributes.items() if not k[0]] + htmllist = ['%s="%s"' % (k[1], wikiutil.escape(v, 1)) + for k, v in attributes.items() if k[0] == 'html'] + otherlist = ['%s:%s="%s"' % (k[0], k[1], wikiutil.escape(v, 1)) + for k, v in attributes.items() if k[0] and k[0] != 'html'] + + # Join all these lists together in a space-separated string. Also + # prefix the whole thing with a space too. + htmllist.sort() + otherlist.sort() + all = [''] + xmlnslist + htmllist + otherlist + return ' '.join(all) return '' - # TODO: use set when we require Python 2.3 - # TODO: The list is not complete, add missing from dtd - _blocks = 'p div pre table tr td ol ul dl li dt dd h1 h2 h3 h4 h5 h6 hr form' - _blocks = dict(zip(_blocks.split(), [1] * len(_blocks))) - - def open(self, tag, newline=False, attr=None): - """ Open a tag with optional attributes + def _open(self, tag, newline=False, attr=None, allowed_attrs=None, **kw): + """ Open a tag with optional attributes (INTERNAL USE BY HTML FORMATTER ONLY!) @param tag: html tag, string - @param newline: render tag on a separate line - @parm attr: dict with tag attributes + @param newline: render tag so following data is on a separate line + @param attr: dict with tag attributes + @param allowed_attrs: list of allowed attributes for this element + @param kw: arbitrary attributes and values @rtype: string ? - @return: open tag with attributes + @return: open tag with attributes as a string """ - if tag in self._blocks: + is_self_closing = '' + if tag in _self_closing_tags: + # Don't expect a closing tag later on. + is_self_closing = ' /' + + if tag in _blocks: # Block elements result = [] # Add language attributes, but let caller overide the default - attributes = self.langAttr() + attributes = self._langAttr() if attr: attributes.update(attr) # Format - attributes = self.formatAttributes(attributes) - result.append('<%s%s>' % (tag, attributes)) + attributes = self._formatAttributes(attributes, allowed_attrs=allowed_attrs, **kw) + result.append('<%s%s%s>' % (tag, attributes, is_self_closing)) if newline: - result.append('\n') - return ''.join(result) + result.append(self._newline()) + tagstr = ''.join(result) else: # Inline elements # Add to inlineStack - self._inlineStack.append(tag) + if not is_self_closing: + # Only push on stack if we expect a close-tag later + self._inlineStack.append(tag) # Format - return '<%s%s>' % (tag, self.formatAttributes(attr)) - - def close(self, tag, newline=False): - """ Close tag + tagstr = '<%s%s%s>' % (tag, + self._formatAttributes(attr, allowed_attrs, **kw), + is_self_closing) + # XXX SENSE ??? + #if not self.close: + # self._tag_stack.append(tag) + # if tag in _indenting_tags: + # self._indent_level += 1 + return tagstr + + def _close(self, tag, newline=False): + """ Close tag (INTERNAL USE BY HTML FORMATTER ONLY!) @param tag: html tag, string - @rtype: string ? - @return: closing tag + @param newline: render tag so following data is on a separate line + @rtype: string + @return: closing tag as a string """ - if tag in self._blocks: + if tag in _self_closing_tags: + # This tag was already closed + tagstr = '' + elif tag in _blocks: # Block elements # Close all tags in inline stack # Work on a copy, because close(inline) manipulate the stack @@ -133,56 +381,78 @@ stack = self._inlineStack[:] stack.reverse() for inline in stack: - result.append(self.close(inline)) + result.append(self._close(inline)) # Format with newline if newline: - result.append('\n') - result.append('</%s>\n' % (tag)) - return ''.join(result) + result.append(self._newline()) + result.append('</%s>' % (tag)) + tagstr = ''.join(result) else: # Inline elements # Pull from stack, ignore order, that is not our problem. # The code that calls us should keep correct calling order. if tag in self._inlineStack: self._inlineStack.remove(tag) - return '</%s>' % tag + tagstr = '</%s>' % tag + # XXX see other place marked with "SENSE" + #if tag in _self_closing_tags: + # self._tag_stack.pop() + # if tag in _indenting_tags: + # # decrease indent level + # self._indent_level -= 1 + if newline: + tagstr += self._newline() + return tagstr # Public methods ################################################### - def startContent(self, content_id='content', **kwargs): - """ Start page content div """ + def startContent(self, content_id='content', newline=True, **kw): + """ Start page content div. + + A link anchor is provided at the beginning of the div, with + an id of 'top' or 'top_xxxx' if the content_id argument is + set to 'xxxx'. + """ # Setup id - if content_id!='content': + if content_id != 'content': aid = 'top_%s' % (content_id,) else: aid = 'top' self._content_ids.append(content_id) result = [] # Use the content language - attr = self.langAttr(self.request.content_lang) + attr = self._langAttr(self.request.content_lang) attr['id'] = content_id - result.append(self.open('div', newline=1, attr=attr)) + result.append(self._open('div', newline=False, attr=attr, + allowed_attrs=['align'], **kw)) result.append(self.anchordef(aid)) + if newline: + result.append('\n') return ''.join(result) - def endContent(self): - """ Close page content div """ + def endContent(self, newline=True): + """ Close page content div. + + A link anchor is provided at the end of the div, with + an id of 'bottom' or 'bottom_xxxx' if the content_id argument + to the previus startContent() call was set to 'xxxx'. + """ # Setup id try: cid = self._content_ids.pop() except: cid = 'content' - if cid!='content': + if cid != 'content': aid = 'bottom_%s' % (cid,) else: aid = 'bottom' result = [] result.append(self.anchordef(aid)) - result.append(self.close('div', newline=1)) + result.append(self._close('div', newline=newline)) return ''.join(result) def lang(self, on, lang_name): @@ -195,19 +465,13 @@ if lang_name != self.request.current_lang: # Enclose text in span using lang attributes if on: - attr = self.langAttr(lang=lang_name) - return self.open(tag, attr=attr) - return self.close(tag) + attr = self._langAttr(lang=lang_name) + return self._open(tag, attr=attr) + return self._close(tag) # Direction did not change, no need for span return '' - def sysmsg(self, on, **kw): - tag = 'div' - if on: - return self.open(tag, attr={'class': 'message'}) - return self.close(tag) - # Links ############################################################## def pagelink(self, on, pagename='', page=None, **kw): @@ -237,7 +501,7 @@ @keyword title: override using the interwiki wikiname as title """ if not on: - return '</a>' + return self.url(0) wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename)) wikiurl = wikiutil.mapURL(self.request, wikiurl) if wikitag == 'Self': # for own wiki, do simple links @@ -259,44 +523,106 @@ # unescaped=1 was changed to 0 to make interwiki links with pages with umlauts (or other non-ascii) work def url(self, on, url=None, css=None, **kw): - """ + """ Inserts an <a> element. + + Call once with on=1 to start the link, and again with on=0 + to end it (no other arguments are needed when on==0). + Keyword params: - title - <a> title attribute - attrs - just include those <a> attrs "as is" + url - the URL to link to; will go through Wiki URL mapping. + css - a space-separated list of CSS classes + attrs - just include this string verbatim inside + the <a> element; can be used for arbitrary attrs; + all escaping and quoting is the caller's responsibility. + + Note that the 'attrs' keyword argument is for backwards compatibility + only. It should not be used for new code--instead just pass + any attributes in as separate keyword arguments. """ + if not on: + return self._close('a') + attrs = self._langAttr() + + # Handle the URL mapping + if url is None and kw.has_key('href'): + url = kw['href'] + del kw['href'] if url is not None: url = wikiutil.mapURL(self.request, url) - title = kw.get('title', None) - attrs = kw.get('attrs', None) + attrs['href'] = url + + if css: + attrs['class'] = css + + if kw.has_key('attrs'): + # for backwards compatibility, raw pre-formated attribute string + extra_attrs = kw['attrs'] + del kw['attrs'] + else: + extra_attrs = None + + # create link if on: - str = '<a' - if css: - str = '%s class="%s"' % (str, css) - if title: - str = '%s title="%s"' % (str, title) - if attrs: - str = '%s %s' % (str, attrs) - str = '%s href="%s">' % (str, wikiutil.escape(url, 1)) + str = self._open('a', attr=attrs, **kw) + if extra_attrs: + # insert this into the tag verbatim (messy) + if str[-2:] == '/>': + str = '%s %s />' % (str[:-2], extra_attrs) + else: + str = '%s %s>' % (str[:-1], extra_attrs) else: - str = '</a>' + str = self._close('a') return str def anchordef(self, id): - #return '<a id="%s"></a>' % (id, ) # this breaks PRE sections for IE - # do not add a \n here, it breaks pre sections with line_anchordef - return '<span id="%s" class="anchor"></span>' % (id, ) + """Inserts an invisible element used as a link target. + + Inserts an empty <span> element with an id attribute, used as an anchor + for link references. We use <span></span> rather than <span/> + for browser portability. + """ + # Don't add newlines, \n, as it will break pre and + # line-numbered code sections (from line_achordef() method). + #return '<a id="%s"></a>' % (id, ) # do not use - this breaks PRE sections for IE + return '<span class="anchor" id="%s"></span>' % wikiutil.escape(id, 1) def line_anchordef(self, lineno): - return self.anchordef("line-%d" % lineno) + if line_anchors: + return self.anchordef("line-%d" % lineno) + else: + return '' - def anchorlink(self, on, name='', id=None): - extra = '' - if id: - extra = ' id="%s"' % id - return ['<a href="#%s"%s>' % (name, extra), '</a>'][not on] + def anchorlink(self, on, name='', **kw): + """Insert an <a> link pointing to an anchor on the same page. + + Call once with on=1 to start the link, and a second time with + on=0 to end it. No other arguments are needed on the second + call. + + The name argument should be the same as the id provided to the + anchordef() method, or some other elment. It should NOT start + with '#' as that will be added automatically. + + The id argument, if provided, is instead the id of this link + itself and not of the target element the link references. + """ + + attrs = self._langAttr() + if name: + attrs['href'] = '#%s' % name + if kw.has_key('href'): + del kw['href'] + if on: + str = self._open('a', attr=attrs, **kw) + else: + str = self._close('a') + return str def line_anchorlink(self, on, lineno=0): - return self.anchorlink(on, name="line-%d" % lineno) + if line_anchors: + return self.anchorlink(on, name="line-%d" % lineno) + else: + return '' # Attachments ###################################################### @@ -373,7 +699,7 @@ # we have a image map. inline it and add a map ref # to the img tag try: - map = open(mappath,'r').read() + map = file(mappath, 'r').read() except IOError: pass except OSError: @@ -383,11 +709,11 @@ # replace MAPNAME map = map.replace('%MAPNAME%', mapid) # add alt and title tags to areas - map = re.sub('href\s*=\s*"((?!%TWIKIDRAW%).+?)"',r'href="\1" alt="\1" title="\1"',map) + map = re.sub('href\s*=\s*"((?!%TWIKIDRAW%).+?)"', r'href="\1" alt="\1" title="\1"', map) # add in edit links plus alt and title attributes map = map.replace('%TWIKIDRAW%"', edit_link + '" alt="' + _('Edit drawing %(filename)s') % {'filename': self.text(fname)} + '" title="' + _('Edit drawing %(filename)s') % {'filename': self.text(fname)} + '"') # unxml, because 4.01 concrete will not validate /> - map = map.replace('/>','>') + map = map.replace('/>', '>') return (map + self.image( alt=drawing, src=AttachFile.getAttachUrl( @@ -409,87 +735,148 @@ # Text ############################################################## def _text(self, text): + text = wikiutil.escape(text) if self._in_code: - return wikiutil.escape(text).replace(' ', self.hardspace) - return wikiutil.escape(text) + text = text.replace(' ', self.hardspace) + return text # Inline ########################################################### - def strong(self, on): - tag = 'strong' - if on: - return self.open(tag) - return self.close(tag) + def strong(self, on, **kw): + """Creates an HTML <strong> element. - def emphasis(self, on): - tag = 'em' - if on: - return self.open(tag) - return self.close(tag) - - def underline(self, on): - tag = 'span' - if on: - return self.open(tag, attr={'class': 'u'}) - return self.close(tag) - - def highlight(self, on): + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'strong' if on: - return self.open(tag, attr={'class': 'highlight'}) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) - def sup(self, on): + def emphasis(self, on, **kw): + """Creates an HTML <em> element. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ + tag = 'em' + if on: + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) + + def underline(self, on, **kw): + """Creates a text span for underlining (css class "u"). + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ + tag = 'span' + if on: + return self._open(tag, attr={'class': 'u'}, allowed_attrs=[], **kw) + return self._close(tag) + + def highlight(self, on, **kw): + """Creates a text span for highlighting (css class "highlight"). + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ + tag = 'strong' + if on: + return self._open(tag, attr={'class': 'highlight'}, allowed_attrs=[], **kw) + return self._close(tag) + + def sup(self, on, **kw): + """Creates a <sup> element for superscript text. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'sup' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) - def sub(self, on): + def sub(self, on, **kw): + """Creates a <sub> element for subscript text. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'sub' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) - def strike(self, on): - tag = 'strike' + def strike(self, on, **kw): + """Creates a text span for line-through (strikeout) text (css class 'strike'). + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ + # This does not use <strike> because has been deprecated in standard HTML. + tag = 'span' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, attr={'class': 'strike'}, + allowed_attrs=[], **kw) + return self._close(tag) def code(self, on, **kw): + """Creates a <tt> element for inline code or monospaced text. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + + Any text within this section will have spaces converted to + non-break spaces. + """ tag = 'tt' # Maybe we don't need this, because we have tt will be in inlineStack. self._in_code = on if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) - def small(self, on): + def small(self, on, **kw): + """Creates a <small> element for smaller font. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'small' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) - def big(self, on): + def big(self, on, **kw): + """Creates a <big> element for larger font. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'big' if on: - return self.open(tag) - return self.close(tag) + return self._open(tag, allowed_attrs=[], **kw) + return self._close(tag) # Block elements #################################################### - def preformatted(self, on, attr=None): + def preformatted(self, on, **kw): + """Creates a preformatted text region, with a <pre> element. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ FormatterBase.preformatted(self, on) tag = 'pre' if on: - return self.open(tag, newline=1, attr=attr) - return self.close(tag) + return self._open(tag, newline=1, **kw) + return self._close(tag) # Use by code area _toggleLineNumbersScript = """ -<script type="text/JavaScript"> +<script type="text/javascript"> function isnumbered(obj) { return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber'; } @@ -541,6 +928,19 @@ """ def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): + """Creates a formatted code region, with line numbering. + + This region is formatted as a <div> with a <pre> inside it. The + code_id argument is assigned to the 'id' of the div element, and + must be unique within the document. The show, start, and step are + used for line numbering. + + Note this is not like most formatter methods, it can not take any + extra keyword arguments. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ res = [] ci = self.request.makeUniqueID('CA-%s_%03d' % (code_id, self._code_area_num)) if on: @@ -551,7 +951,7 @@ # Open the code div - using left to right always! attr = {'class': 'codearea', 'lang': 'en', 'dir': 'ltr'} - res.append(self.open('div', attr=attr)) + res.append(self._open('div', attr=attr)) # Add the script only in the first code area on the page if self._code_area_js == 0 and self._code_area_state[1] >= 0: @@ -562,7 +962,7 @@ if self._code_area_state[1] >= 0: toggleLineNumbersLink = r''' <script type="text/javascript"> -document.write('<a href="#" onClick="return togglenumber(\'%s\', %d, %d);" \ +document.write('<a href="#" onclick="return togglenumber(\'%s\', %d, %d);" \ class="codenumbers">Toggle line numbers<\/a>'); </script> ''' % (self._code_area_state[0], self._code_area_state[2], self._code_area_state[3]) @@ -570,14 +970,14 @@ # Open pre - using left to right always! attr = {'id': self._code_area_state[0], 'lang': 'en', 'dir': 'ltr'} - res.append(self.open('pre', newline=True, attr=attr)) + res.append(self._open('pre', newline=True, attr=attr)) else: # Close code area res = [] if self._in_code_line: res.append(self.code_line(0)) - res.append(self.close('pre')) - res.append(self.close('div')) + res.append(self._close('pre')) + res.append(self._close('div')) # Update state self._in_code_area = 0 @@ -602,27 +1002,59 @@ # Paragraphs, Lines, Rules ########################################### + def _indent_spaces(self): + """Returns space(s) for indenting the html source so list nesting is easy to read. + + Note that this mostly works, but because of caching may not always be accurate.""" + if prettyprint: + return self.indentspace * self._indent_level + else: + return '' + + def _newline(self): + """Returns the whitespace for starting a new html source line, properly indented.""" + if prettyprint: + return '\n' + self._indent_spaces() + else: + return '' + def linebreak(self, preformatted=1): + """Creates a line break in the HTML output. + + If preformatted is true a <br> element is inserted, otherwise + the linebreak will only be visible in the HTML source. + """ if self._in_code_area: preformatted = 1 - return ['\n', '<br>\n'][not preformatted] + return ['\n', '<br />\n'][not preformatted] + self._indent_spaces() - def paragraph(self, on): + def paragraph(self, on, **kw): + """Creates a paragraph with a <p> element. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ if self._terse: return '' FormatterBase.paragraph(self, on) - if self._in_li: - self._in_li = self._in_li + 1 tag = 'p' if on: - return self.open(tag) - return self.close(tag) - - def rule(self, size=None): - if size: + tagstr = self._open(tag, **kw) + else: + tagstr = self._close(tag) + return tagstr + + def rule(self, size=None, **kw): + """Creates a horizontal rule with an <hr> element. + + If size is a number in the range [1..6], the CSS class of the rule + is set to 'hr1' through 'hr6'. The intent is that the larger the + size number the thicker or bolder the rule will be. + """ + if size and 1 <= size <= 6: # Add hr class: hr1 - hr6 - return self.open('hr', newline=1, attr={'class': 'hr%d' % size}) - return self.open('hr', newline=1) + return self._open('hr', newline=1, attr={'class': 'hr%d' % size}, **kw) + return self._open('hr', newline=1, **kw) def icon(self, type): return self.request.theme.make_icon(type) @@ -634,9 +1066,29 @@ href = self.request.theme.img_url(img) return self.image(src=href, alt=text, width=str(w), height=str(h)) + def image(self, src=None, **kw): + """Creates an inline image with an <img> element. + + The src argument must be the URL to the image file. + """ + if src: + kw['src'] = src + return self._open('img', **kw) + # Lists ############################################################## - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): + """Creates an HTML ordered list, <ol> element. + + The 'type' if specified can be any legal numbered + list-style-type, such as 'decimal','lower-roman', etc. + + The 'start' argument if specified gives the numeric value of + the first list item (default is 1). + + Call once with on=1 to start the list, and a second time + with on=0 to end it. + """ tag = 'ol' if on: attr = {} @@ -644,49 +1096,81 @@ attr['type'] = type if start is not None: attr['start'] = start - return self.open(tag, newline=1, attr=attr) - return self.close(tag) + tagstr = self._open(tag, newline=1, attr=attr, **kw) + else: + tagstr = self._close(tag, newline=1) + return tagstr - def bullet_list(self, on): + def bullet_list(self, on, **kw): + """Creates an HTML ordered list, <ul> element. + + The 'type' if specified can be any legal unnumbered + list-style-type, such as 'disc','square', etc. + + Call once with on=1 to start the list, and a second time + with on=0 to end it. + """ tag = 'ul' if on: - return self.open(tag, newline=1) - return self.close(tag) - + tagstr = self._open(tag, newline=1, **kw) + else: + tagstr = self._close(tag, newline=1) + return tagstr + def listitem(self, on, **kw): - """ List item inherit its lang from the list. """ + """Adds a list item, <li> element, to a previously opened + bullet or number list. + + Call once with on=1 to start the region, and a second time + with on=0 to end it. + """ tag = 'li' - self._in_li = on != 0 if on: - attr = {} - css_class = kw.get('css_class', None) - if css_class: - attr['class'] = css_class - style = kw.get('style', None) - if style: - attr['style'] = style - return self.open(tag, attr=attr) - return self.close(tag) + tagstr = self._open(tag, newline=1, **kw) + else: + tagstr = self._close(tag, newline=1) + return tagstr - def definition_list(self, on): + def definition_list(self, on, **kw): + """Creates an HTML definition list, <dl> element. + + Call once with on=1 to start the list, and a second time + with on=0 to end it. + """ tag = 'dl' if on: - return self.open(tag, newline=1) - return self.close(tag) + tagstr = self._open(tag, newline=1, **kw) + else: + tagstr = self._close(tag, newline=1) + return tagstr - def definition_term(self, on): + def definition_term(self, on, **kw): + """Adds a new term to a definition list, HTML element <dt>. + + Call once with on=1 to start the term, and a second time + with on=0 to end it. + """ tag = 'dt' if on: - return self.open(tag) - return self.close(tag) - - def definition_desc(self, on): + tagstr = self._open(tag, newline=1, **kw) + else: + tagstr = self._close(tag, newline=0) + return tagstr + + def definition_desc(self, on, **kw): + """Gives the definition to a definition item, HTML element <dd>. + + Call once with on=1 to start the definition, and a second time + with on=0 to end it. + """ tag = 'dd' if on: - return self.open(tag) - return self.close(tag) + tagstr = self._open(tag, newline=1, **kw) + else: + tagstr = self._close(tag, newline=0) + return tagstr - def heading(self, on, depth, id = None, **kw): + def heading(self, on, depth, **kw): # remember depth of first heading, and adapt counting depth accordingly if not self._base_depth: self._base_depth = depth @@ -709,7 +1193,7 @@ # closing tag, with empty line after, to make source more readable if not on: - return self.close('h%d' % heading_depth) + '\n' + return self._close('h%d' % heading_depth) + '\n' # create section number number = '' @@ -722,25 +1206,22 @@ number = '.'.join(map(str, self.request._fmt_hd_counters[self._show_section_numbers-1:])) if number: number += ". " - attr = {} - if id: - attr['id'] = id # Add space before heading, easier to check source code - result = '\n' + self.open('h%d' % heading_depth, attr=attr) + result = '\n' + self._open('h%d' % heading_depth, **kw) # TODO: convert this to readable code if self.request.user.show_topbottom: # TODO change top/bottom refs to content-specific top/bottom refs? result = ("%s%s%s%s%s%s%s%s" % (result, - kw.get('icons',''), + kw.get('icons', ''), self.url(1, "#bottom", unescaped=1), self.icon('bottom'), self.url(0), self.url(1, "#top", unescaped=1), self.icon('top'), self.url(0))) - return "%s%s%s" % (result, kw.get('icons',''), number) + return "%s%s%s" % (result, kw.get('icons', ''), number) # Tables ############################################################# @@ -795,7 +1276,7 @@ return result - def table(self, on, attrs=None): + def table(self, on, attrs=None, **kw): """ Create table @param on: start table @@ -807,44 +1288,80 @@ if on: # Open div to get correct alignment with table width smaller # than 100% - result.append(self.open('div', newline=1)) + result.append(self._open('div', newline=1)) # Open table if not attrs: attrs = {} else: attrs = self._checkTableAttr(attrs, 'table') - result.append(self.open('table', newline=1, attr=attrs)) + result.append(self._open('table', newline=1, attr=attrs, + allowed_attrs=self._allowed_table_attrs['table'], + **kw)) + result.append(self._open('tbody', newline=1)) else: - # Close table then div - result.append(self.close('table')) - result.append(self.close('div')) + # Close tbody, table, and then div + result.append(self._close('tbody')) + result.append(self._close('table')) + result.append(self._close('div')) return ''.join(result) - def table_row(self, on, attrs=None): + def table_row(self, on, attrs=None, **kw): tag = 'tr' if on: if not attrs: attrs = {} else: attrs = self._checkTableAttr(attrs, 'row') - return self.open(tag, newline=1, attr=attrs) - return self.close(tag) + return self._open(tag, newline=1, attr=attrs, + allowed_attrs=self._allowed_table_attrs['row'], + **kw) + return self._close(tag) + '\n' - def table_cell(self, on, attrs=None): + def table_cell(self, on, attrs=None, **kw): tag = 'td' if on: if not attrs: attrs = {} else: attrs = self._checkTableAttr(attrs, '') - return self.open(tag, newline=1, attr=attrs) - return self.close(tag) + return ' ' + self._open(tag, attr=attrs, + allowed_attrs=self._allowed_table_attrs[''], + **kw) + return self._close(tag) + '\n' - def escapedText(self, text): - return wikiutil.escape(text) + def text(self, text, **kw): + txt = FormatterBase.text(self, text, **kw) + if kw: + return self._open('span', **kw) + txt + self._close('span') + return txt + + def escapedText(self, text, **kw): + txt = wikiutil.escape(text) + if kw: + return self._open('span', **kw) + txt + self._close('span') + return txt def rawHTML(self, markup): return markup + def sysmsg(self, on, **kw): + tag = 'div' + if on: + return self._open(tag, attr={'class': 'message'}, **kw) + return self._close(tag) + + def div(self, on, **kw): + tag = 'div' + if on: + return self._open(tag, **kw) + return self._close(tag) + + def span(self, on, **kw): + tag = 'span' + if on: + return self._open(tag, **kw) + return self._close(tag) + +
--- a/MoinMoin/formatter/text_plain.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/text_plain.py Tue Jan 31 21:17:13 2006 +0000 @@ -26,7 +26,7 @@ self._text = None # XXX does not work with links in headings!!!!! def startDocument(self, pagename): - line = u"*" * (len(pagename)+2) + u'\n' + line = u"*" * (len(pagename) + 2) + u'\n' return u"%s %s \n%s" % (line, pagename, line) def endDocument(self): @@ -69,37 +69,40 @@ self._text = None return u' [%s]' % (self._url) - # Attachments ###################################################### - def attachment_link(self, url, text, **kw): return "[%s]" % text + def attachment_image(self, url, **kw): - return "[image:%s]" % url + title = '' + for a in (u'title', u'html__title', u'alt', u'html_alt'): + if kw.has_key(a): + title = ':' + kw[a] + return "[image:%s%s]" % (url, title) def attachment_drawing(self, url, text, **kw): return "[drawing:%s]" % text - def text(self, text): + def text(self, text, **kw): self._did_para = 0 if self._text is not None: self._text.append(text) return text - def rule(self, size=0): + def rule(self, size=0, **kw): size = min(size, 10) ch = u"---~=*+#####"[size] return (ch * 79) + u'\n' - def strong(self, on): + def strong(self, on, **kw): return u'*' - def emphasis(self, on): + def emphasis(self, on, **kw): return u'/' - def highlight(self, on): + def highlight(self, on, **kw): return u'' - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): if on: self._in_list = 1 return [u'\n', u'\n\n'][not self._did_para] @@ -110,7 +113,7 @@ return u'\n' return u'' - def bullet_list(self, on): + def bullet_list(self, on, **kw): if on: self._in_list = -1 return [u'\n', u'\n\n'][not self._did_para] @@ -123,11 +126,11 @@ def listitem(self, on, **kw): if on: - if self._in_list>0: + if self._in_list > 0: self._in_list += 1 self._did_para = 1 return ' %d. ' % (self._in_list-1,) - elif self._in_list<0: + elif self._in_list < 0: self._did_para = 1 return u' * ' else: @@ -136,20 +139,20 @@ self._did_para = 1 return u'\n' - def sup(self, on): + def sup(self, on, **kw): return u'^' - def sub(self, on): + def sub(self, on, **kw): return u'_' - def strike(self, on): + def strike(self, on, **kw): return u'__' def code(self, on, **kw): #return [unichr(0x60), unichr(0xb4)][not on] return u"'" # avoid high-ascii - def preformatted(self, on): + def preformatted(self, on, **kw): FormatterBase.preformatted(self, on) snip = u'---%<' snip = snip + (u'-' * (78 - len(snip))) @@ -158,10 +161,10 @@ else: return snip + u'\n' - def small(self, on): + def small(self, on, **kw): return u'' - def big(self, on): + def big(self, on, **kw): return u'' def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): @@ -182,8 +185,8 @@ if not on or (on and self._in_code_line): res += u'\n' if on: - if self._code_area_state[0]>0: - res += u' %4d ' % ( self._code_area_state[3] ) + if self._code_area_state[0] > 0: + res += u' %4d ' % self._code_area_state[3] self._code_area_state[3] += self._code_area_state[2] self._in_code_line = on != 0 return res @@ -191,7 +194,7 @@ def code_token(self, on, tok_type): return "" - def paragraph(self, on): + def paragraph(self, on, **kw): FormatterBase.paragraph(self, on) if self._did_para: on = 0 @@ -212,34 +215,38 @@ self._text = None return result - def table(self, on, attrs={}): + def table(self, on, attrs={}, **kw): return u'' - def table_row(self, on, attrs={}): + def table_row(self, on, attrs={}, **kw): return u'' - def table_cell(self, on, attrs={}): + def table_cell(self, on, attrs={}, **kw): return u'' - def underline(self, on): + def underline(self, on, **kw): return u'_' - def definition_list(self, on): + def definition_list(self, on, **kw): return u'' - def definition_term(self, on, compact=0): + def definition_term(self, on, compact=0, **kw): result = u'' - if not compact: result = result + u'\n' - if not on: result = result + u':\n' + if not compact: + result = result + u'\n' + if not on: + result = result + u':\n' return result - def definition_desc(self, on): + def definition_desc(self, on, **kw): return [u' ', u'\n'][not on] - def image(self, **kw): - if kw.has_key(u'alt'): - return kw[u'alt'] + def image(self, src=None, **kw): + for a in (u'title', u'html__title', u'alt', u'html_alt'): + if kw.has_key(a): + return kw[a] return u'' def lang(self, on, lang_name): return '' +
--- a/MoinMoin/formatter/text_python.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/text_python.py Tue Jan 31 21:17:13 2006 +0000 @@ -22,7 +22,7 @@ defaultDependencies = ["time"] - def __init__(self, request, static = [], formatter = None, **kw): + def __init__(self, request, static=[], formatter=None, **kw): if formatter: self.formatter = formatter else: @@ -67,7 +67,7 @@ self.code_fragments[i], self.text_cmd_begin, repr(text[i+1])]) - i = i + 1 + i += 1 source.append(self.text_cmd_end) source.append(self.__adjust_formatter_state()) @@ -88,10 +88,11 @@ def __is_static(self, dependencies): for dep in dependencies: - if dep not in self.static: return False + if dep not in self.static: + return False return True - def __adjust_languge_state(self): + def __adjust_language_state(self): """ Add current language state changing code to the cache """ if self.__lang != self.request.current_lang: self.__lang = self.request.current_lang @@ -99,7 +100,7 @@ return '' def __adjust_formatter_state(self): - result = self.__adjust_languge_state() + result = self.__adjust_language_state() if self.__in_p != self.formatter.in_p: result = "%s%s.in_p = %r\n" % (result, self.__formatter, self.formatter.in_p) @@ -110,8 +111,8 @@ self.__in_pre = self.formatter.in_pre return result - def dynamic_content(self, parser, callback, arg_list = [], arg_dict = {}, - returns_content = 1): + def dynamic_content(self, parser, callback, arg_list=[], arg_dict={}, + returns_content=1): adjust = self.__adjust_formatter_state() if returns_content: return self.__insert_code('%srequest.write(%s.%s(*%r,**%r))' % @@ -136,6 +137,7 @@ return self.__insert_code( 'request.write(%s.attachment_link(%r, %r, **%r))' % (self.__formatter, url, text, kw)) + def attachment_image(self, url, **kw): return self.__insert_code( 'request.write(%s.attachment_image(%r, **%r))' % @@ -154,7 +156,7 @@ def heading(self, on, depth, **kw): if on: code = [ - self.__adjust_languge_state(), + self.__adjust_language_state(), 'request.write(%s.heading(%r, %r, **%r))' % (self.__formatter, on, depth, kw), ]
--- a/MoinMoin/formatter/text_xml.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/text_xml.py Tue Jan 31 21:17:13 2006 +0000 @@ -36,7 +36,7 @@ result = "" while self._current_depth > 1: result += "</s%d>" % self._current_depth - self._current_depth = self._current_depth - 1 + self._current_depth -= 1 return result + '</s1>' def lang(self, on, lang_name): @@ -60,30 +60,29 @@ else: return '</interwiki>' - def url(self, on, url='', css=None, **kw): if css: str = ' class="%s"' % css - else: str = '' - + else: + str = '' return ('<jump href="%s"%s>' % (self._escape(url), str), '</jump>') [not on] - # Attachments ###################################################### def attachment_link(self, url, text, **kw): return '<attachment href="%s">%s</attachment>' % (url, text) + def attachment_image(self, url, **kw): return '<attachmentimage href="%s"></attachmentimage>' % (url,) + def attachment_drawing(self, url, text, **kw): - return '<attachmentdrawing href="%s">%s</attachmentdrawing>' % ( - url, text) + return '<attachmentdrawing href="%s">%s</attachmentdrawing>' % (url, text) - def text(self, text): + def text(self, text, **kw): if self.in_pre: return text.replace(']]>', ']]>]]><![CDATA[') return self._escape(text) - def rule(self, size=0): - return "\n<br/>%s<br/>\n" % ("-"*78,) # <hr/> not supported in stylebook + def rule(self, size=0, **kw): + return "\n<br/>%s<br/>\n" % ("-" * 78,) # <hr/> not supported in stylebook if size: return '<hr size="%d"/>\n' % (size,) else: @@ -92,23 +91,25 @@ def icon(self, type): return '<icon type="%s" />' % type - def strong(self, on): + def strong(self, on, **kw): return ['<strong>', '</strong>'][not on] - def emphasis(self, on): + def emphasis(self, on, **kw): return ['<em>', '</em>'][not on] - def highlight(self, on): + def highlight(self, on, **kw): return ['<strong>', '</strong>'][not on] - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): result = '' - if self.in_p: result = self.paragraph(0) + if self.in_p: + result = self.paragraph(0) return result + ['<ol>', '</ol>\n'][not on] - def bullet_list(self, on): + def bullet_list(self, on, **kw): result = '' - if self.in_p: result = self.paragraph(0) + if self.in_p: + result = self.paragraph(0) return result + ['<ul>', '</ul>\n'][not on] def listitem(self, on, **kw): @@ -117,29 +118,30 @@ def code(self, on, **kw): return ['<code>', '</code>'][not on] - def sup(self, on): + def sup(self, on, **kw): return ['<sup>', '</sup>'][not on] - def sub(self, on): + def sub(self, on, **kw): return ['<sub>', '</sub>'][not on] - def strike(self, on): + def strike(self, on, **kw): return ['<strike>', '</strike>'][not on] - def preformatted(self, on): + def preformatted(self, on, **kw): FormatterBase.preformatted(self, on) result = '' - if self.in_p: result = self.paragraph(0) + if self.in_p: + result = self.paragraph(0) return result + ['<source><![CDATA[', ']]></source>'][not on] - def paragraph(self, on): + def paragraph(self, on, **kw): FormatterBase.paragraph(self, on) return ['<p>', '</p>\n'][not on] def linebreak(self, preformatted=1): return ['\n', '<br/>\n'][not preformatted] - def heading(self, on, depth, id = None, **kw): + def heading(self, on, depth, id=None, **kw): if not on: return '">\n' # remember depth of first heading, and adapt current depth accordingly @@ -151,7 +153,7 @@ result = "" while self._current_depth >= depth: result = result + "</s%d>\n" % self._current_depth - self._current_depth = self._current_depth - 1 + self._current_depth -= 1 self._current_depth = depth id_text = '' @@ -160,41 +162,43 @@ return result + '<s%d%s title="' % (depth, id_text) - def table(self, on, attrs={}): + def table(self, on, attrs={}, **kw): return ['<table>', '</table>'][not on] - def table_row(self, on, attrs={}): + def table_row(self, on, attrs={}, **kw): return ['<tr>', '</tr>'][not on] - def table_cell(self, on, attrs={}): + def table_cell(self, on, attrs={}, **kw): return ['<td>', '</td>'][not on] def anchordef(self, id): return '<anchor id="%s"/>' % id - def anchorlink(self, on, name='', id=None): + def anchorlink(self, on, name='', **kw): + id = kw.get('id',None) extra = '' if id: extra = ' id="%s"' % id return ('<link anchor="%s"%s>' % (name, extra) ,'</link>') [not on] - def underline(self, on): + def underline(self, on, **kw): return self.strong(on) # no underline in StyleBook - def definition_list(self, on): + def definition_list(self, on, **kw): result = '' - if self.in_p: result = self.paragraph(0) + if self.in_p: + result = self.paragraph(0) return result + ['<gloss>', '</gloss>'][not on] - def definition_term(self, on, compact=0): + def definition_term(self, on, compact=0, **kw): return ['<label>', '</label>'][not on] - def definition_desc(self, on): + def definition_desc(self, on, **kw): return ['<item>', '</item>'][not on] - def image(self, **kw): - valid_attrs = ['src', 'width', 'height', 'alt'] - attrs = {} + def image(self, src=None, **kw): + valid_attrs = ['src', 'width', 'height', 'alt', 'title'] + attrs = {'src': src} for key, value in kw.items(): if key in valid_attrs: attrs[key] = value
--- a/MoinMoin/formatter/xml_docbook.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/formatter/xml_docbook.py Tue Jan 31 21:17:13 2006 +0000 @@ -66,7 +66,7 @@ def getBody(self): body = [] - # print all nodes inside dom behid heading + # print all nodes inside dom behind heading firstNode = self.doc.documentElement.firstChild while firstNode: if firstNode != self.domHeadNode: @@ -116,7 +116,7 @@ return self.outputFormatter.getHeading() - def startContent(self, content_id="content", **kwargs): + def startContent(self, content_id="content", **kw): self.cur = self.root return "" @@ -132,7 +132,7 @@ def endDocument(self): return self.outputFormatter.getFooter() - def text(self, text): + def text(self, text, **kw): if text == "\\n": srcText = "\n" else: @@ -162,13 +162,13 @@ while (self.cur.nodeName != "section" and self.cur.nodeName != "article"): self.cur = self.cur.parentNode -# Do not understant this code - looks like unneccesery -- maybe it is used to gain some vertical space for large headings? +# I don't understand this code - looks like unnecessary -- maybe it is used to gain some vertical space for large headings? # if len(self.cur.childNodes) < 3: # self._addEmptyNode("para") # check if not top-level if self.cur.nodeName != "article": - self.cur=self.cur.parentNode + self.cur = self.cur.parentNode section = self.doc.createElement("section") self.cur.appendChild(section) @@ -179,18 +179,18 @@ self.cur = title self.curdepth = depth else: - self.cur=self.cur.parentNode + self.cur = self.cur.parentNode return "" - def paragraph(self, on): + def paragraph(self, on, **kw): FormatterBase.paragraph(self, on) if on: para = self.doc.createElement("para") self.cur.appendChild(para) self.cur = para else: - self.cur=self.cur.parentNode + self.cur = self.cur.parentNode return "" def linebreak(self, preformatted=1): @@ -224,7 +224,7 @@ def _getTableCellCount(self, attrs=()): cols = 1 if attrs and attrs.has_key('colspan'): - s1 = (attrs['colspan']) + s1 = attrs['colspan'] s1 = str(s1).replace('"','') cols = int(s1) return cols @@ -263,46 +263,46 @@ ### Inline ########################################################## def _handleFormatting(self, name, on, attributes=()): - #We add all the elements we create to the list of elements that should not contain a section + # We add all the elements we create to the list of elements that should not contain a section if name not in self.section_should_break: self.section_should_break.append(name) return self._handleNode(name, on, attributes) - def strong(self, on): + def strong(self, on, **kw): return self._handleFormatting("emphasis", on, (('role','strong'), )) - def emphasis(self, on): + def emphasis(self, on, **kw): return self._handleFormatting("emphasis", on) - def underline(self, on): + def underline(self, on, **kw): return self._handleFormatting("emphasis", on, (('role','underline'), )) - def highlight(self, on): + def highlight(self, on, **kw): return self._handleFormatting("emphasis", on, (('role','highlight'), )) - def sup(self, on): + def sup(self, on, **kw): return self._handleFormatting("superscript", on) - def sub(self, on): + def sub(self, on, **kw): return self._handleFormatting("subscript", on) - def strike(self, on): + def strike(self, on, **kw): # does not yield <strike> using the HTML XSLT files here ... # but seems to be correct return self._handleFormatting("emphasis", on, (('role','strikethrough'), )) - def code(self, on, **kwargs): + def code(self, on, **kw): return self._handleFormatting("code", on) - def preformatted(self, on): + def preformatted(self, on, **kw): return self._handleFormatting("screen", on) ### Lists ########################################################### - def number_list(self, on, type=None, start=None): + def number_list(self, on, type=None, start=None, **kw): docbook_ol_types = {'1': "arabic", 'a': "loweralpha", 'A': "upperalpha", @@ -310,22 +310,22 @@ 'I': "upperroman"} if type and docbook_ol_types.has_key(type): - attrs=[("numeration", docbook_ol_types[type])] + attrs = [("numeration", docbook_ol_types[type])] else: - attrs=[] + attrs = [] return self._handleNode('orderedlist', on, attrs) - def bullet_list(self, on): + def bullet_list(self, on, **kw): return self._handleNode("itemizedlist", on) - def definition_list(self, on): + def definition_list(self, on, **kw): return self._handleNode("glosslist", on) - '''When on is false, we back out just on level. This is - ok because we know definition_desc gets called, and we - back out two levels there''' - def definition_term(self, on, compact=0): + def definition_term(self, on, compact=0, **kw): + # When on is false, we back out just on level. This is + # ok because we know definition_desc gets called, and we + # back out two levels there. if on: entry=self.doc.createElement('glossentry') term=self.doc.createElement('glossterm') @@ -336,8 +336,8 @@ self.cur = self.cur.parentNode return "" - '''We backout two levels when 'on' is false, to leave the glossentry stuff''' - def definition_desc(self, on): + def definition_desc(self, on, **kw): + # We backout two levels when 'on' is false, to leave the glossentry stuff if on: return self._handleNode("glossdef", on) else: @@ -356,13 +356,13 @@ ### Links ########################################################### - #FIXME: This is quite crappy + # FIXME: This is quite crappy def pagelink(self, on, pagename='', page=None, **kw): FormatterBase.pagelink(self, on, pagename, page, **kw) - return self.interwikilink(on, 'Self', pagename) #FIXME + return self.interwikilink(on, 'Self', pagename) # FIXME - #FIXME: This is even more crappy + # FIXME: This is even more crappy def interwikilink(self, on, interwiki='', pagename='', **kw): if not on: return self.url(on,kw) @@ -381,7 +381,8 @@ self._handleNode("ulink", False) return "" - def anchorlink(self, on, name='', id=None): + def anchorlink(self, on, name='', **kw): + id = kw.get('id',None) attrs = [] if name != '': attrs.append(('endterm', name)) @@ -392,7 +393,7 @@ return self._handleNode("link", on, attrs) -# Attachments ###################################################### +### Attachments ###################################################### def attachment_link(self, url, text, **kw): _ = self.request.getText @@ -436,9 +437,11 @@ addts=1), html_class="drawing") +### Images and Smileys ############################################## -### Images and Smileys ############################################## - def image(self, **kw): + def image(self, src=None, **kw): + if src: + kw['src'] = src media = self.doc.createElement('inlinemediaobject') imagewrap = self.doc.createElement('imageobject') @@ -452,12 +455,17 @@ if kw.has_key('height'): image.setAttribute('depth', kw['height']) imagewrap.appendChild(image) - - if kw.has_key('alt'): + + title = '' + for a in ('title', 'html_title', 'alt', 'html_alt'): + if kw.has_key(titleattr): + title = kw[a] + break + if title: txtcontainer = self.doc.createElement('textobject') media.appendChild(txtcontainer) txtphrase = self.doc.createElement('phrase') - txtphrase.appendChild(self.doc.createTextNode(kw['alt'])) + txtphrase.appendChild(self.doc.createTextNode(title)) txtcontainer.appendChild(txtphrase) self.cur.appendChild(media) @@ -471,13 +479,13 @@ return self.image(src=href, alt=text, width=str(w), height=str(h)) def icon(self, type): - return ''#self.request.theme.make_icon(type) + return '' # self.request.theme.make_icon(type) ### Tables ########################################################## #FIXME: We should copy code from text_html.py for attr handling - def table(self, on, attrs=None): + def table(self, on, attrs=None, **kw): sanitized_attrs = [] if attrs and attrs.has_key('id'): sanitized_attrs[id] = attrs['id'] @@ -489,14 +497,14 @@ self._handleNode("tbody", on) return "" - def table_row(self, on, attrs=None): + def table_row(self, on, attrs=None, **kw): self.table_current_row_cells = 0 sanitized_attrs = [] if attrs and attrs.has_key('id'): sanitized_attrs[id] = attrs['id'] return self._handleNode("row", on, sanitized_attrs) - def table_cell(self, on, attrs=None): + def table_cell(self, on, attrs=None, **kw): # Finish row definition sanitized_attrs = [] if attrs and attrs.has_key('id'): @@ -517,6 +525,7 @@ return ret ### Code ############################################################ + def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1): show = show and 'numbered' or 'unnumbered' if start < 1: @@ -531,7 +540,7 @@ return self._handleFormatting("screen", on, attrs) def code_line(self, on): - return '' #No clue why something should be done here + return '' # No clue why something should be done here def code_token(self, on, tok_type): toks_map = {'ID':'methodname', @@ -561,10 +570,10 @@ # At the begining text mode contain some string which is later # exchange for real value. There is problem that data inserted # as text mode are encoded to xml, e.g. < is encoded in the output as < - text=FormatterBase.macro(self, macro_obj, name, args) + text = FormatterBase.macro(self, macro_obj, name, args) if len(text) > 0: # prepare identificator - sKey="EXCHANGESTRINGMACRO-" + str(len(self.exchangeKeys)) + "-EXCHANGESTRINGMACRO" + sKey = "EXCHANGESTRINGMACRO-" + str(len(self.exchangeKeys)) + "-EXCHANGESTRINGMACRO" self.exchangeKeys.append(sKey) self.exchangeValues.append(text) # append data to lists @@ -572,11 +581,13 @@ return u"" ### Not supported ################################################### - def rule(self, size = 0): + + def rule(self, size = 0, **kw): return "" - def small(self, on): + def small(self, on, **kw): return "" - def big(self, on): + def big(self, on, **kw): return "" +
--- a/MoinMoin/macro/FootNote.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/macro/FootNote.py Tue Jan 31 21:17:13 2006 +0000 @@ -43,12 +43,7 @@ if request.footnotes: result = [] - # Start footnotes div. It is important to use formatter so open - # inline tags will be closed, and we get correct direction. - attr = formatter.langAttr() - attr['class'] = 'footnotes' - attr = [' %s="%s"' % (k, v) for k, v in attr.items()] - result.append(formatter.rawHTML('<div%s>' % ''.join(attr))) + result.append(formatter.div(1, css_class='footnotes')) # Add footnotes list result.append(formatter.bullet_list(1)) @@ -60,7 +55,7 @@ fn_id = request.footnotes[idx][1] result.append(formatter.anchorlink(1, 'fnref' + fn_id, id='fndef' + fn_id)) - result.append(formatter.text(str(idx+1))) + result.append(formatter.text(str(idx + 1))) result.append(formatter.anchorlink(0)) result.append(formatter.text(" ")) @@ -78,7 +73,7 @@ result.append(formatter.bullet_list(0)) # Finish div - result.append(formatter.rawHTML('</div>')) + result.append(formatter.div(0)) request.footnotes = [] return ''.join(result)
--- a/MoinMoin/macro/Include.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/macro/Include.py Tue Jan 31 21:17:13 2006 +0000 @@ -234,10 +234,10 @@ # if no heading and not in print mode, then output a helper link if editlink and not (level or print_mode): result.extend([ - '<div class="include-link">', + macro.formatter.div(1, css_class="include-link"), inc_page.link_to(request, '[%s]' % (inc_name,), css_class="include-page-link"), inc_page.link_to(request, '[%s]' % (_('edit'),), css_class="include-edit-link", querystr={'action': 'edit', 'backto': request._Include_backto}), - '</div>', + macro.formatter.div(0), ]) # XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text
--- a/MoinMoin/parser/python.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/parser/python.py Tue Jan 31 21:17:13 2006 +0000 @@ -70,8 +70,11 @@ except tokenize.TokenError, ex: msg = ex[0] line = ex[1][0] - self.request.write(self.formatter.rawHTML("<b>ERROR: %s</b><br>%s\n" % ( - msg, wikiutil.escape(self.raw[self.lines[line]:])))) + errmsg = (self.formatter.linebreak() + + self.formatter.strong(1) + "ERROR: %s" % msg + self.formatter.strong(0) + + self.formatter.linebreak() + + wikiutil.escape(self.raw[self.lines[line]:])) + self.request.write(errmsg) self.request.write(self.formatter.code_line(0)) self.request.write(formatter.code_area(0, self._code_id))
--- a/MoinMoin/parser/rst.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/parser/rst.py Tue Jan 31 21:17:13 2006 +0000 @@ -194,12 +194,12 @@ html = [] if parts['title']: - html.append(formatter.rawHTML('<h2>' + parts['title'] + '</h2>')) + html.append(formatter.rawHTML('<h1>%s</h1>' % parts['title'])) # If there is only one subtitle then it is held in parts['subtitle']. # However, if there is more than one subtitle then this is empty and # fragment contains all of the subtitles. if parts['subtitle']: - html.append(formatter.rawHTML('<h3>' + parts['subtitle'] + '</h3>')) + html.append(formatter.rawHTML('<h2>%s</h2>' % parts['subtitle'])) if parts['docinfo']: html.append(parts['docinfo']) html.append(parts['fragment'])
--- a/MoinMoin/parser/wiki.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/parser/wiki.py Tue Jan 31 21:17:13 2006 +0000 @@ -53,7 +53,7 @@ dl_rule = ur"^\s+.*?::\s" # the big, fat, ugly one ;) - formatting_rules = ur"""(?P<ent_numeric>&#\d{1,5};) + formatting_rules = ur"""(?P<ent_numeric>&#(\d{1,5}|x[0-9a-fA-F]+);) (?:(?P<emph_ibb>'''''(?=[^']+''')) (?P<emph_ibi>'''''(?=[^']+'')) (?P<emph_ib_or_bi>'{5}(?=[^'])) @@ -72,7 +72,9 @@ (?P<macro>\[\[(%%(macronames)s)(?:\(.*?\))?\]\])) (?P<ol>%(ol_rule)s) (?P<dl>%(dl_rule)s) -(?P<li>^\s+\*?\s*) +(?P<li>^\s+\*\s*) +(?P<li_none>^\s+\.\s*) +(?P<indent>^\s+) (?P<tableZ>\|\| $) (?P<table>(?:\|\|)+(?:<[^>]*?>)?(?!\|? $)) (?P<heading>^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $) @@ -83,6 +85,7 @@ (?P<email>[-\w._+]+\@[\w-]+(\.[\w-]+)+) (?P<smiley>(?<=\s)(%(smiley)s)(?=\s)) (?P<smileyA>^(%(smiley)s)(?=\s)) +(?P<ent_symbolic>&[a-zA-Z]+;) (?P<ent>[<>&]) (?P<wikiname_bracket>\[".*?"\]) (?P<tt_bt>`.*?`)""" % { @@ -96,9 +99,11 @@ 'smiley': u'|'.join(map(re.escape, config.smileys.keys()))} # Don't start p before these - no_new_p_before = ("heading rule table tableZ tr td ul ol dl dt dd li " - "processor macro pre") - no_new_p_before = dict(zip(no_new_p_before.split(), [1] * len(no_new_p_before))) + no_new_p_before = ("heading rule table tableZ tr td " + "ul ol dl dt dd li li_none indent " + "macro processor pre") + no_new_p_before = no_new_p_before.split() + no_new_p_before = dict(zip(no_new_p_before, [1] * len(no_new_p_before))) def __init__(self, raw, request, **kw): self.raw = raw @@ -446,35 +451,48 @@ # '<': '<', # '>': '>'}[word] - def _ent_numeric_repl(self, word): - """Handle numeric SGML entities.""" + """Handle numeric (decimal and hexadecimal) SGML entities.""" return self.formatter.rawHTML(word) + def _ent_symbolic_repl(self, word): + """Handle symbolic SGML entities.""" + return self.formatter.rawHTML(word) + + def _indent_repl(self, match): + """Handle pure indentation (no - * 1. markup).""" + result = [] + if not self.in_li: + self._close_item(result) + self.in_li = 1 + css_class = None + if self.line_was_empty and not self.first_list_item: + css_class = 'gap' + result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none")) + return ''.join(result) + + def _li_none_repl(self, match): + """Handle type=none (" .") lists.""" + result = [] + self._close_item(result) + self.in_li = 1 + css_class = None + if self.line_was_empty and not self.first_list_item: + css_class = 'gap' + result.append(self.formatter.listitem(1, css_class=css_class, style="list-style-type:none")) + return ''.join(result) def _li_repl(self, match): - """Handle bullet lists.""" + """Handle bullet (" *") lists.""" result = [] - indented_only = (match == (" " * len(match))) - if indented_only and self.in_li: - return '' - self._close_item(result) - #self.inhibit_p = 1 self.in_li = 1 - css_class = '' + css_class = None if self.line_was_empty and not self.first_list_item: css_class = 'gap' - if indented_only: - result.append(self.formatter.listitem(1, css_class=css_class, - style="list-style-type:none")) - else: - result.append(self.formatter.listitem(1, css_class=css_class)) - # Suspected p! - ## result.append(self.formatter.paragraph(1)) + result.append(self.formatter.listitem(1, css_class=css_class)) return ''.join(result) - def _ol_repl(self, match): """Handle numbered lists.""" return self._li_repl(match) @@ -516,10 +534,11 @@ # self.inhibit_p = 1 # Close lists while char-wise indent is greater than the current one - while ((self._indent_level() > new_level) or - ( new_level and - (self._indent_level() == new_level) and - (self.list_types[-1]) != list_type)): + #while ((self._indent_level() > new_level) or + # ( new_level and + # (self._indent_level() == new_level) and + # (self.list_types[-1]) != list_type)): + while self._indent_level() > new_level: self._close_item(close) if self.list_types[-1] == 'ol': tag = self.formatter.number_list(0) @@ -564,6 +583,7 @@ ##self.inhibit_p = 1 self.in_li = 0 self.in_dd = 0 + # If list level changes, close an open table if self.in_table and (open or close): close[0:0] = [self.formatter.table(0)] @@ -580,7 +600,7 @@ result = [] #result.append("<!-- _undent start -->\n") self._close_item(result) - for type in self.list_types: + for type in self.list_types[::-1]: if type == 'ol': result.append(self.formatter.number_list(0)) elif type == 'dl': @@ -821,7 +841,7 @@ def _macro_repl(self, word): """Handle macros ([[macroname]]).""" macro_name = word[2:-2] - #self.inhibit_p = 1 # fixes UserPreferences, but makes new trouble! + self.inhibit_p = 1 # 0 fixes UserPreferences, but makes new trouble! # check for arguments args = None @@ -852,7 +872,7 @@ ###result.append(u'<span class="info">[add text before match: <tt>"%s"</tt>]</span>' % line[lastpos:match.start()]) if not (self.inhibit_p or self.in_pre or self.formatter.in_p): - result.append(self.formatter.paragraph(1)) + result.append(self.formatter.paragraph(1, css_class="line879")) result.append(self.formatter.text(line[lastpos:match.start()])) # Replace match with markup @@ -864,7 +884,7 @@ # No match: Add paragraph with the text of the line if not (self.in_pre or self.inhibit_p or self.formatter.in_p) and lastpos < len(line): - result.append(self.formatter.paragraph(1)) + result.append(self.formatter.paragraph(1, css_class="line886")) result.append(self.formatter.text(line[lastpos:])) return u''.join(result) @@ -881,7 +901,7 @@ # Open p for certain types if not (self.inhibit_p or self.formatter.in_p or self.in_pre or (type in self.no_new_p_before)): - result.append(self.formatter.paragraph(1)) + result.append(self.formatter.paragraph(1, css_class="line903")) # Get replace method and replece hit replace = getattr(self, '_' + type + '_repl') @@ -994,7 +1014,9 @@ self.processor = None # send rest of line through regex machinery - line = line[endpos+3:] + line = line[endpos+3:] + if not line.strip(): # just in the case "}}} " when we only have blanks left... + continue else: # we don't have \n as whitespace any more # This is the space between lines we join to one paragraph @@ -1007,7 +1029,7 @@ self.in_table = 0 # CHANGE: removed check for not self.list_types # p should close on every empty line - if (self.formatter.in_p): + if self.formatter.in_p: self.request.write(self.formatter.paragraph(0)) self.line_is_empty = 1 continue @@ -1036,8 +1058,7 @@ indtype = "dl" # output proper indentation tags - self.request.write(self._indent_to(indlen, indtype, numtype, - numstart)) + self.request.write(self._indent_to(indlen, indtype, numtype, numstart)) # Table mode # TODO: move into function? @@ -1045,8 +1066,7 @@ and line[-3:] == "|| " and len(line) >= 5 + indlen): # Start table if self.list_types and not self.in_li: - self.request.write(self.formatter.listitem - (1, style="list-style-type:none")) + self.request.write(self.formatter.listitem(1, style="list-style-type:none")) ## CHANGE: no automatic p on li ##self.request.write(self.formatter.paragraph(1)) self.in_li = 1 @@ -1073,7 +1093,7 @@ formatted_line = self.scan(scan_re, line) self.request.write(formatted_line) - if self.in_pre: + if self.in_pre == 3: self.request.write(self.formatter.linebreak()) # Close code displays, paragraphs, tables and open lists @@ -1099,3 +1119,5 @@ self.processor_is_parser = 1 except wikiutil.PluginMissingError: self.processor = None + +
--- a/MoinMoin/search.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/search.py Tue Jan 31 21:17:13 2006 +0000 @@ -809,7 +809,7 @@ for page in self.hits: matchInfo = '' if info: - matchInfo = self.formatInfo(page) + matchInfo = self.formatInfo(f, page) item = [ f.listitem(1), f.pagelink(1, page.page_name, querystr=querystr), @@ -852,7 +852,7 @@ for page in self.hits: matchInfo = '' if info: - matchInfo = self.formatInfo(page) + matchInfo = self.formatInfo(f, page) item = [ f.definition_term(1), f.pagelink(1, page.page_name, querystr=querystr), @@ -1072,22 +1072,24 @@ querystr = wikiutil.escape(querystr) return querystr - def formatInfo(self, page): + def formatInfo(self, formatter, page): """ Return formatted match info """ - # TODO: this will not work with non-html formats - template = u'<span class="info"> . . . %s %s</span>' + template = u' . . . %s %s' + template = u"%s%s%s" % (formatter.span(1, css_class="info"), + template, + formatter.span(0)) # Count number of unique matches in text of all types count = len(page.get_matches(unique=1)) info = template % (count, self.matchLabel[count != 1]) - return self.formatter.rawHTML(info) + return info def getvalue(self): """ Return output in div with CSS class """ write = self.request.write value = [ - self.formatter.rawHTML('<div class="searchresults">'), + self.formatter.div(1, css_class='searchresults'), self.buffer.getvalue(), - self.formatter.rawHTML('</div>'), + self.formatter.div(0), ] return '\n'.join(value)
--- a/MoinMoin/version.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/version.py Tue Jan 31 21:17:13 2006 +0000 @@ -13,7 +13,7 @@ patchlevel = 'release' project = "MoinMoin" -release = '1.5.1' +release = '1.5.refactor' revision = patchlevel if __name__ == '__main__':
--- a/MoinMoin/wikimacro.py Tue Jan 31 21:09:45 2006 +0000 +++ b/MoinMoin/wikimacro.py Tue Jan 31 21:17:13 2006 +0000 @@ -432,7 +432,9 @@ except KeyError: # Wrong argument, return inline error message arg = self.formatter.text(args) - return '<span class="error">Wrong argument: %s</span>' % arg + return (self.formatter.span(1, css_class="error") + + 'Wrong argument: %s' % arg + + self.formatter.span(0)) count = self.request.rootpage.getPageCount(exists=exists) return self.formatter.text("%d" % count)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/CHANGES.refactor Tue Jan 31 21:17:13 2006 +0000 @@ -0,0 +1,50 @@ +MoinMoin Version History +======================== + +Version moin--refactor--1.5: + +This was branched from moin--main--1.5--patch-399 (== release 1.5.1) to +separately work on the following goals: + + 1. Make html output better (more valid). + Reduce problems the GUI editor converter has in 1.5.1. + 2. Cleanup the formatter API + +While we are working on that goal, changes to moin--main--1.5 should be reduced +to a minimum (security, critical bugs), due to following reasons: + * concentrate on goal (see above), + thus do not spend time on other features, neither here nor in "main" branch + * finish as soon as possible, + thus make merging "refactor" branch back to "main" branch easier + +Also please keep changes here as small as possible to reach the goal. +Do not extend the goal without discussion and good reason. + +Please use THIS file for "refactor" branch CHANGES entries only, so we can +easily integrate it when we merge back to "main". + + Fixes: + * the new "." markup makes it possible to have a bulletless list with + elements on the same level. Before this change and only using indentation + with blanks, that would get merged into a single paragraph. + * it is possible now to have multiple paragraphs in the same list element + * fixed GAP processing for ordered lists + * fix text_gedit formatter's invalid list nesting + * fixed hr crash in blockquote (but needs more work) + * fixed FootNote's formatter usage + * fixed rst's headline levels + * fixed MoinMoinBugs/WikiParserThinksItIsInsidePreWhenItIsNot + * fixed MoinMoinBugs/ListItemGeneratedOutsideList + * fixed that macros were followed by a wrong <p> + * added <blockquote> to the block elements in the text_html formatter, + so it does not close it erratically when you close a inner <p>. + * GUI editor converter now also accept http: urls without // (relative or + same server urls) + + Other changes: + * add new markup for bulletless lists: just use a "." instead of "*". + * deron meranda's formatter API cleanup + * added div and span to formatter API + * allow hex and symbolic entities + +
--- a/wiki/htdocs/classic/css/common.css Tue Jan 31 21:09:45 2006 +0000 +++ b/wiki/htdocs/classic/css/common.css Tue Jan 31 21:17:13 2006 +0000 @@ -122,8 +122,9 @@ .hr5 {height: 7px;} .hr6 {height: 8px;} -/* Replacement for html 3 u tag */ +/* Replacement for deprecated html 3 <u> element and html 4 <strike> */ .u {text-decoration: underline;} +.strike {text-decoration: line-through;} .footnotes ul { padding: 0 2em;
--- a/wiki/htdocs/modern/css/common.css Tue Jan 31 21:09:45 2006 +0000 +++ b/wiki/htdocs/modern/css/common.css Tue Jan 31 21:17:13 2006 +0000 @@ -188,8 +188,9 @@ .hr5 {height: 6pt;} .hr6 {height: 7pt;} -/* Replacement for html 3 u tag */ +/* Replacement for deprecated html 3 <u> element and html 4 <strike> */ .u {text-decoration: underline;} +.strike {text-decoration: line-through;} /* eye catchers */ .warning
--- a/wiki/htdocs/rightsidebar/css/common.css Tue Jan 31 21:09:45 2006 +0000 +++ b/wiki/htdocs/rightsidebar/css/common.css Tue Jan 31 21:17:13 2006 +0000 @@ -123,8 +123,9 @@ .hr5 {height: 6px;} .hr6 {height: 7px;} -/* Replacement for html 3 u tag */ +/* Replacement for deprecated html 3 <u> element and html 4 <strike> */ .u {text-decoration: underline;} +.strike {text-decoration: line-through;} .footnotes ul { padding: 0 2em;