Thomas Waldmann avatar Thomas Waldmann committed 7657798 Merge

merged default branch into namespaces branch

Comments (0)

Files changed (99)

 recursive-include   MoinMoin/apps/misc/templates *
 
 recursive-include   MoinMoin/themes/modernized *
+recursive-include   MoinMoin/themes/foobar *
 
 global-include */_tests/*
 

MoinMoin/apps/feed/views.py

 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import wikiutil
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.apps.feed import feed
 from MoinMoin.config import (NAME, NAME_EXACT, WIKINAME, ACL, ACTION, ADDRESS,

MoinMoin/apps/frontend/views.py

 from MoinMoin.apps.frontend import frontend
 from MoinMoin.items import Item, NonExistent
 from MoinMoin.items import ROWS_META, COLS, ROWS_DATA
-from MoinMoin import config, user, util, wikiutil
+from MoinMoin import config, user, util
 from MoinMoin.config import CONTENTTYPE_GROUPS
 from MoinMoin.constants.keys import *
 from MoinMoin.util import crypto
                 'username': form['username'].value,
                 'password': form['password1'].value,
                 'email': form['email'].value,
-                #'openid': form['openid'].value,
+                'openid': form['openid'].value,
             }
             if app.cfg.user_email_verification:
                 user_kwargs['is_disabled'] = True
                     response['flash'].append((_("Your password has been changed."), "info"))
                 else:
                     if part == 'personal':
-                        if form['openid'].value != flaskg.user.openid and user.search_users(openid=form['openid'].value):
+                        if form['openid'].value and form['openid'].value != flaskg.user.openid and user.search_users(openid=form['openid'].value):
                             # duplicate openid
                             response['flash'].append((_("This openid is already in use."), "error"))
                             success = False

MoinMoin/auth/__init__.py

 from flask import current_app as app
 from jinja2 import Markup
 
-from MoinMoin import user, wikiutil
+from MoinMoin import user
 from MoinMoin.i18n import _, L_, N_
 
 

MoinMoin/config/default.py

         ('frontend.modify_item', L_('Modify'), L_('Edit or Upload'), True, ),
         ('special.supplementation', None, None, False, ),
         ('frontend.index', L_('Index'), L_('List sub-items'), False, ),
-        ('special.comments', L_('Comments'), L_('Switch showing comments on or off'), True, ),
+        # The | character in the comments and transclusions lines below separate the off/on title (tooltip) values used by javascript
+        ('special.comments', L_('Comments'), L_('Show comments|Hide comments'), True, ),
+        ('special.transclusions', L_('Transclusions'), L_('Show transclusions|Hide transclusions'), True, ),
         ('frontend.highlight_item', L_('Highlight'), L_('Show with Syntax-Highlighting'), True, ),
         ('frontend.show_item_meta', L_('Meta'), L_('Display Metadata'), True, ),
         ('frontend.quicklink_item', None, L_('Create or remove a navigation link to this item'), False, ),

MoinMoin/conftest.py

     app = create_app_ext(flask_config_dict=dict(SECRET_KEY='foobarfoobar'),
                          moin_config_class=given_config,
                          **more_config)
-    ctx = app.test_request_context('/')
+    ctx = app.test_request_context('/', base_url="http://localhost:8080/")
     ctx.push()
     before_wiki()
     return app, ctx

MoinMoin/constants/misc.py

     re.UNICODE | re.VERBOSE
     )
 
-# used for wikiutil.clean_input
 clean_input_translation_map = {
     # these chars will be replaced by blanks
     ord(u'\t'): u' ',

MoinMoin/converter/_tests/test_include.py

         update_item(u'page4', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{page2}}')
 
         page1 = MoinWiki.create(u'page1')
+        rendered = page1._render_data()
+        # an error message will follow strong tag
+        assert '<strong class="moin-error">' in rendered
 
-        page1._render_data()
+    def test_ExternalInclude(self):
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{http://moinmo.in}}')
+        rendered = MoinWiki.create(u'page1')._render_data()
+        assert '<object class="moin-http moin-transclusion" data="http://moinmo.in" data-href="http://moinmo.in">http://moinmo.in</object>' in rendered
 
     def test_InlineInclude(self):
         # issue #28
-        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Content of page2 is "{{page2}}"')
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Content of page2 is "{{page2}}".')
 
         update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Single line')
         rendered = MoinWiki.create(u'page1')._render_data()
-        assert 'Content of page2 is "Single line"' in rendered
+        assert '<p>Content of page2 is "<span class="moin-transclusion" data-href="/page2">Single line</span>".</p>' in rendered
 
         update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Two\n\nParagraphs')
         rendered = MoinWiki.create(u'page1')._render_data()
-        assert '<p>Two</p>' in rendered
-        assert '<p>Paragraphs</p>' in rendered
+        assert '<p>Content of page2 is "</p><div class="moin-transclusion" data-href="/page2"><p>Two</p><p>Paragraphs</p></div><p>".</p></div>' in rendered
 
         update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"this text contains ''italic'' string")
         rendered = MoinWiki.create(u'page1')._render_data()
-        assert 'Content of page2 is "this text contains' in rendered
-        assert '<em>italic</em>' in rendered
+        assert 'Content of page2 is "<span class="moin-transclusion" data-href="/page2">this text contains <em>italic</em>' in rendered
 
         update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Content of page2 is\n\n{{page2}}')
         update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"Single Line")
         rendered = MoinWiki.create(u'page1')._render_data()
-        assert 'Content of page2 is</p>' in rendered
-        assert '<p>Single Line</p>' in rendered
+        assert '<p>Content of page2 is</p><p><span class="moin-transclusion" data-href="/page2">Single Line</span></p>' in rendered
+        #           '<p>Content of page2 is</p><p><span class="moin-transclusion" data-href="http://127.0.0.1:8080/page2">Single Line</span></p>'
 
         update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Content of page2 is "{{page2}}"')
         update_item(u'page2', {CONTENTTYPE: u'text/x.moin.wiki'}, u"|| table || cell ||")
         assert 'Content of page2 is "</p>' in rendered
         assert '<table>' in rendered
         assert rendered.count('<table>') == 1
+
+    def test_InlineIncludeLogo(self):
+        # the 3rd parameter, u'',  should be a binary string defining a png image, but it is not needed for this simple test
+        update_item(u'logo', {CONTENTTYPE: u'image/png'}, u'')
+
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{logo}}')
+        rendered = MoinWiki.create(u'page1')._render_data()
+        assert '<img alt="logo" class="moin-transclusion"' in rendered
+
+        # <p /> is not valid html5; should be <p></p>. to be valid.  Even better, there should be no empty p's.
+        update_item(u'page1', {CONTENTTYPE: u'text/x.moin.wiki'}, u'{{logo}}{{logo}}')
+        rendered = MoinWiki.create(u'page1')._render_data()
+        assert '<p />' not in rendered
+        assert '<p></p>' not in rendered

MoinMoin/converter/creole_in.py

 
 import re
 
-from MoinMoin import config, wikiutil
+from MoinMoin import config
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import moin_page, xlink, xinclude
 

MoinMoin/converter/docbook_in.py

 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import wikiutil
 from MoinMoin.util.tree import moin_page, xlink, docbook, xml, html
 
 from ._wiki_macro import ConverterMacro

MoinMoin/converter/docbook_out.py

 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import wikiutil
 from MoinMoin.util.tree import html, moin_page, xlink, docbook, xml
 
 

MoinMoin/converter/html_in.py

 from MoinMoin import log
 logging = log.getLogger(__name__)
 
-from MoinMoin import wikiutil
 from MoinMoin.util.tree import html, moin_page, xlink, xml
 
 from ._wiki_macro import ConverterMacro

MoinMoin/converter/html_out.py

 
 from __future__ import absolute_import, division
 
+import re
+
+from flask import request
 from emeraldtree import ElementTree as ET
 
 from MoinMoin import wikiutil
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.util.tree import html, moin_page, xlink, xml, Name
 
+from MoinMoin import log
+logging = log.getLogger(__name__)
 
-def remove_overlay_prefixes(url):
+
+def convert_getlink_to_showlink(href):
     """
-    Returns url without the prefixes, like +get or +modify
+    If the incoming transclusion reference is within this domain, then remove "+get/<revision number>/".
+    """
+    if href.startswith('/'):
+        return re.sub(r'\+get/\+[0-9a-fA-F]+/', '', href)
+    return href
 
-    TODO: Find a way to limit the removal to internal links only
-    This could remove +get or +modify for external links,
-        when they shouldn't really be removed.
+def mark_item_as_transclusion(elem, href):
     """
-    return unicode(url).replace("/+get/", "/+show/").replace("/+modify/", "/+show/")
+    Return elem after adding a "moin-transclusion" class and a "data-href" attribute with
+    a link to the transcluded item.
 
-
-def wrap_object_with_overlay(elem, href):
+    On the client side, a Javascript function will wrap the element (or a parent element)
+    in a span or div and 2 overlay siblings will be created.
     """
-    Given both an element and either an href or text, wraps an object with the appropriate div,
-    and attaches the overlay element.
-    """
-    txt = u"→"
-
-    href = remove_overlay_prefixes(href)
-
-    child = html.a(attrib={
-        html.href: href
-    }, children=(txt, ))
-
-    overlay = html.div(attrib={
-        html.class_: "object-overlay"
-    }, children=(child, ))
-
-    owrapper = html.div(attrib={
-        html.class_: "object-overlay-wrapper"
-    }, children=(overlay, ))
-
-    return html.div(attrib={
-        html.class_: "page-object"
-    }, children=(elem, owrapper))
+    href = unicode(href)
+    # href will be "/wikiroot/SomeObject" or "/SomePage" for internal wiki items
+    # or "http://Some.Org/SomeThing" for external link
+    if elem.tag.name == 'page':
+        # if wiki is not running at server root, prefix href with wiki root
+        wiki_root = request.url_root[len(request.host_url):-1]
+        if wiki_root:
+            href = '/' + wiki_root + href
+    href = convert_getlink_to_showlink(href)
+    # data_href will create an attribute named data-href: any attribute beginning with "data-" passes html5 validation
+    elem.attrib[html.data_href] = href
+    classes = elem.attrib.get(html.class_, '').split()
+    classes.append('moin-transclusion')
+    elem.attrib[html.class_] = ' '.join(classes)
+    return elem
 
 
 class ElementException(RuntimeError):
                 attrib[html.controls] = 'controls'
             new_elem = self.new_copy(getattr(html, obj_type), elem, attrib)
 
-        return wrap_object_with_overlay(new_elem, href=href)
+        return mark_item_as_transclusion(new_elem, href)
 
     def visit_moinpage_p(self, elem):
         return self.new_copy(html.p, elem)
     def visit_moinpage_page(self, elem):
         for item in elem:
             if item.tag.uri == moin_page and item.tag.name == 'body':
-                return self.new_copy(html.div, item)
+                # if this is a transcluded page, we must pass the class and data-href attribs
+                attribs = elem.attrib.copy()
+                if moin_page.page_href in attribs:
+                    del attribs[moin_page.page_href]
+                return self.new_copy(html.div, item, attribs)
 
         raise RuntimeError('page:page need to contain exactly one page:body tag, got {0!r}'.format(elem[:]))
 

MoinMoin/converter/include.py

 MoinMoin - Include handling
 
 Expands include elements in an internal Moin document.
+
+Although this module is named include.py, many comments within and the moin docs
+use the word transclude as defined by http://www.linfo.org/transclusion.html, etc.
 """
 
 
 from whoosh.query import Term, And, Wildcard
 
 from MoinMoin.config import NAME, NAME_EXACT, WIKINAME
-from MoinMoin import wikiutil
 from MoinMoin.items import Item
 from MoinMoin.util.mime import type_moin_document
 from MoinMoin.util.iri import Iri, IriPath
 from MoinMoin.util.tree import html, moin_page, xinclude, xlink
 
-from MoinMoin.converter.html_out import wrap_object_with_overlay
+from MoinMoin.converter.html_out import mark_item_as_transclusion, Attributes
 
 
 class XPointer(list):
             return cls()
 
     def recurse(self, elem, page_href):
-        # Check if we reached a new page
+        # on first call, elem.tag.name=='page'. Decendants (body, div, p, include, page, etc.) are processed by recursing through DOM
+
+        # stack is used to detect transclusion loops
         page_href_new = elem.get(self.tag_page_href)
         if page_href_new:
             page_href_new = Iri(page_href_new)
 
         try:
             if elem.tag == self.tag_xi_include:
+                # we have already recursed several levels and found a transclusion: "{{SomePage}}" or similar
+                # process the transclusion and add it to the DOM.  Subsequent recursions will traverse through the transclusion's elements.
                 href = elem.get(self.tag_xi_href)
                 xpointer = elem.get(self.tag_xi_xpointer)
 
                                 xp_include_level = data
 
                 if href:
-                    # We have a single page to include
+                    # We have a single page to transclude
                     href = Iri(href)
                     link = Iri(scheme='wiki', authority='')
                     if href.scheme == 'wiki':
 
                     page_doc = page.internal_representation()
                     # page_doc.tag = self.tag_div # XXX why did we have this?
+
                     self.recurse(page_doc, page_href)
-                    # Wrap the page with the overlay, but only if it's a "page", or "a".
+
+                    # if this is an existing item, mark it as a transclusion.  non-existent items are not marked (page_doc.tag.name == u'a')
                     # The href needs to be an absolute URI, without the prefix "wiki://"
-                    if page_doc.tag.endswith("page") or page_doc.tag.endswith("a"):
-                        page_doc = wrap_object_with_overlay(page_doc, href=unicode(p_href.path))
-
+                    if page_doc.tag.name == u'page':
+                        page_doc = mark_item_as_transclusion(page_doc, p_href.path)
                     included_elements.append(page_doc)
 
                 if len(included_elements) > 1:
                     result = included_elements[0]
                 else:
                     result = None
-
+                #  end of processing for transclusion; the "result" will get inserted into the DOM below
                 return result
 
-            container = [elem]
 
+            # Traverse the DOM by calling self.recurse with each child of the current elem.  Starting elem.tag.name=='page'.
+            container = []
             i = 0
             while i < len(elem):
                 child = elem[i]
                 if isinstance(child, ET.Node):
+                    # almost everything in the DOM will be an ET.Node, exceptions are unicode nodes under p nodes
+
                     ret = self.recurse(child, page_href)
+
                     if ret:
-                        if type(ret) == types.ListType:
+                        # "Normally" we are here because child.tag.name==include and ret is a transcluded item (ret.tag.name=page, image, or object, etc.)
+                        # that must be inserted into the DOM replacing elem[i].
+                        # This is complicated by the DOM having many inclusions, such as "\n{{SomePage}}\n" that are a child of a "p".
+                        # To prevent generation of invalid HTML5 (e.g. "<p>text<p>text</p></p>"), the DOM must be adjusted.
+                        if isinstance(ret, types.ListType):
+                            # the transclusion may be a return of the container variable from below, add to DOM replacing the current node
                             elem[i:i+1] = ret
                         elif elem.tag.name == 'p':
-                            try:
-                                body = ret[0][0]
-                                if len(body) == 1 and body[0].tag.name == 'p':
-                                    single = True
-                                else:
-                                    single = False
-                            except AttributeError:
-                                single = False
-
-                            if single:
-                                # content inside P is inserted directly into this P
-                                p = ret[0][0][0]
-                                elem[i:i+1] = [p[k] for k in xrange(len(p))]
+                            # ancestor P nodes with tranclusions  have special case issues, we may need to mangle the ret
+                            body = ret[0]
+                            # check for instance where ret is a page, ret[0] a body, ret[0][0] a P
+                            if not isinstance(body, unicode) and ret.tag.name == 'page' and body.tag.name == 'body' and \
+                                len(body) == 1 and body[0].tag.name == 'p':
+                                # special case:  "some text {{SomePage}} more text" or "\n{{SomePage}}\n" where SomePage contains a single p.
+                                # the content of the transcluded P will be inserted directly into ancestor P.
+                                p = body[0]
+                                # get attributes from page node; we expect {class: "moin-transclusion"; data-href: "http://some.org/somepage"}
+                                attrib = Attributes(ret).convert()
+                                # make new span node and "convert" p to span by copying all of p's children
+                                span = ET.Element(html.span, attrib=attrib, children=p[:])
+                                # insert the new span into the DOM replacing old include, page, body, and p elements
+                                elem[i] = span
+                            elif not isinstance(body, unicode) and ret.tag.name == 'page' and body.tag.name == 'body':
+                                # special case: "some text {{SomePage}} more text" or "\n{{SomePage}}\n" and SomePage body contains multiple p's, a table, preformatted text, etc.
+                                # note: ancestor P may have text before or after include
+                                if i > 0:
+                                    # there is text before transclude, make new p node to hold text before include and save in container
+                                    pa = ET.Element(html.p)
+                                    pa[:] = elem[0:i]
+                                    container.append(pa)
+                                # get attributes from page node; we expect {class: "moin-transclusion"; data-href: "http://some.org/somepage"}
+                                attrib = Attributes(ret).convert()
+                                # make new div node, copy all of body's children, and save in container
+                                div = ET.Element(html.div, attrib=attrib, children=body[:])
+                                container.append(div)
+                                 # empty elem of siblings that were just placed in container
+                                elem[0:i+1] = []
+                                if len(elem) > 0:
+                                    # there is text after transclude, make new p node to hold text, copy siblings, save in container
+                                    pa = ET.Element(html.p)
+                                    pa[:] = elem[:]
+                                    container.append(pa)
+                                    elem[:] = []
+                                # elem is now empty so while loop will terminate and container will be returned up one level in recursion
                             else:
-                                # P is closed and element is inserted after
-                                pa = ET.Element(html.p)
-                                pa[0:i] = elem[0:i]
-                                ret[0:1] = elem[i:i+1]
-                                elem[0:i+1] = []
-                                container[0:0] = [pa, ret]
-                                i = 0
+                                # ret may be a unicode string: take default action
+                                elem[i] = ret
                         else:
+                            # default action for any ret not fitting special cases above
                             elem[i] = ret
                 i += 1
-            if len(container) > 1:
+            if len(container) > 0:
                 return container
 
         finally:
 
     def __call__(self, tree):
         self.stack = []
-
         self.recurse(tree, None)
 
         return tree

MoinMoin/converter/rst_in.py

 
 from flask import g as flaskg
 
-from MoinMoin import config, wikiutil
+from MoinMoin import config
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import html, moin_page, xlink
 

MoinMoin/static/js/common.js

     }
 }
 
-// for long documents with many comments this is expensive to calculate,
-// thus we keep it here:
-comments = null;
-
-function toggleComments() {
-    // Toggle visibility of every tag with class "comment"
-    for (i = 0; i < comments.length; i++){
-        el = comments[i];
-        if ( el.style.display != 'none' ) {
-            el.style.display = 'none';
-        } else {
-            el.style.display = '';
-        }
-    }
-}
-
-function show_toggleComments() {
-    // Show edit bar item for toggling inline comments on/off only if inline comments exist on the page
-    comments = getElementsByClassName('comment', null, document);
-    if (comments.length > 0) {
-        var buttons = getElementsByClassName('toggleCommentsButton', null, document);
-        for (i = 0; i < buttons.length; i++){
-            el = buttons[i];
-            el.style.display = '';
-        }
-    }
-}
-
-
 function load() {
     // Do not name this "onload", it does not work with IE :-)
     // TODO: create separate onload for each type of view and set the
     // Editor stuff
     show_switch2gui();
 
-    // Enable menu item "ToggleComments" if inline comments exist
-    show_toggleComments();
-
     // data browser widget
     dbw_hide_buttons();
 }
 }
 jQuery(moinFirefoxWordBreak);
 
-/* For the overlays on transcluded objects */
-function removeURLPrefixes(url) {
-    return url.replace("+get/", "").replace("+modify/", "")
-}
-function attachHoverToObjects() {
-    $(".page-object").mouseenter(function(e) {
-        elements = $(".object-overlay", this)
-        elements.each(function(i) {
-            if (location.href == removeURLPrefixes(this.firstChild.href)) {
-                var elem = $(this)
-                setTimeout(function() {
-                    elem.hide()
-                }, 10)
-            }
-        })
+// globals used to save translated show/hide titles (tooltips) for Comments buttons
+var pageComments = null;
+var commentsShowTitle = ''; // "Show comments"
+var commentsHideTitle = ''; // "Hide comments"
 
-        $(elements.slice(1)).hide()
-    })
+// This is executed when user clicks a Comments button and conditionally on dom ready
+function toggleComments() {
+    // Toggle visibility of every tag with class "comment"
+    var buttons = jQuery('.moin-toggle-comments-button > a');
+    if (pageComments.is(':hidden')) {
+        pageComments.show();
+        buttons.attr('title', commentsHideTitle);
+    } else {
+        pageComments.hide();
+        buttons.attr('title', commentsShowTitle);
+    }
 }
 
-$(document).ready(attachHoverToObjects)
+// Comments initialization is executed once after document ready
+function initToggleComments() {
+    var titles;
+    var show_comments = '0';
+    pageComments = jQuery('.comment');
+    if (pageComments.length > 0) {
+        // There are comments, so show itemview Comments button
+        jQuery('.moin-toggle-comments-button').css('display', '');
+        // read translated show|hide Comments button title, split into show and hide parts, and save
+        titles = jQuery('.moin-toggle-comments-button > a').attr('title').split('|');
+        if (titles.length === 2) {
+            commentsShowTitle = titles[0];
+            commentsHideTitle = titles[1];
+            jQuery('.moin-toggle-comments-button > a').attr('title', commentsHideTitle);
+        }
+        // show or hide comments based on user option or default option:
+        //     show comments if  there is a <meta name="moin-show-comments" content="1" />
+        if (document.getElementsByName('moin-show-comments').length > 0) {
+            show_comments = document.getElementsByName('moin-show-comments')[0].content;
+        }
+        if (show_comments !== '1') {
+            // user option is to hide comments
+            toggleComments();
+        }
+    }
+}
+jQuery(document).ready(initToggleComments);
+
+// globals used to save translated show/hide titles (tooltips) for Transclusions buttons
+var transclusionShowTitle = ''; // "Show Transclusions"
+var transclusionHideTitle = ''; // "Hide Transclusions"
+
+// This is executed when user clicks a Transclusions button
+function toggleTransclusionOverlays() {
+    var overlays = jQuery('.moin-item-overlay-ul, .moin-item-overlay-lr');
+    if (overlays.length > 0) {
+        var buttons = jQuery('.moin-transclusions-button > a');
+        if (overlays.is(':visible')) {
+            overlays.hide();
+            buttons.attr('title', transclusionShowTitle);
+        } else {
+            overlays.show();
+            buttons.attr('title', transclusionHideTitle);
+}
+            }
+}
+
+// Transclusion initialization is executed once after document ready
+function initTransclusionOverlays() {
+    var elem, overlayUL, overlayLR, wrapper, wrappers;
+    var rightArrow = '\u2192';
+    // get list of elements to be wrapped;  must work in reverse order in case there are nested transclusions
+    var transclusions = jQuery(jQuery('.moin-transclusion').get().reverse());
+    transclusions.each(function (index) {
+        elem = transclusions[index];
+        // if this is the transcluded item page, do not wrap (avoid creating useless overlay links to same page)
+        if (location.href !== elem.getAttribute('data-href')) {
+            if (elem.tagName === 'DIV') {
+                wrapper = jQuery('<div class="moin-item-wrapper"></div>');
+            } else {
+                wrapper = jQuery('<span class="moin-item-wrapper"></span>');
+            }
+            overlayUL = jQuery('<a class="moin-item-overlay-ul"></a>');
+            jQuery(overlayUL).attr('href', elem.getAttribute('data-href'));
+            jQuery(overlayUL).append(rightArrow);
+            overlayLR = jQuery(overlayUL).clone(true);
+            jQuery(overlayLR).attr('class', 'moin-item-overlay-lr');
+            // if the parent of this element is an A, then wrap parent (avoid A's within A's)
+            if (jQuery(elem).parent()[0].tagName === 'A') {
+                elem = jQuery(elem).parent()[0];
+            }
+            // wrap element, add UL and LR overlay siblings, and replace old elem with wrapped elem
+            jQuery(wrapper).append(jQuery(elem).clone(true));
+            jQuery(wrapper).append(overlayUL);
+            jQuery(wrapper).append(overlayLR);
+            jQuery(elem).replaceWith(wrapper);
+        }
+    });
+    // if an element was wrapped above, then make the Transclusions buttons visible
+    wrappers = jQuery('.moin-item-wrapper');
+    if (wrappers.length > 0) {
+        jQuery('.moin-transclusions-button').css('display', '');
+        // read translated show|hide Transclusions button title, split into show and hide parts, and save
+        var titles = jQuery('.moin-transclusions-button > a').attr('title').split('|');
+        if (titles.length === 2) {
+            transclusionShowTitle = titles[0];
+            transclusionHideTitle = titles[1];
+            jQuery('.moin-transclusions-button > a').attr('title', transclusionShowTitle);
+        }
+    }
+}
+jQuery(document).ready(initTransclusionOverlays);
 
 /*
     For the quicklinks patch that

MoinMoin/storage/backends/fileserver.py

 
 from MoinMoin.util.mimetype import MimeType
 
+NAME_SEP = '/'
+
 
 class Backend(BackendBase):
     """
 
     def _mkpath(self, key):
         """
-        key -> rel path, absolute path (strip mtime)
+        key -> itemname, absolute path (strip mtime)
         """
         # XXX unsafe keys?
         try:
-            relpath, mtime = key.rsplit('.', 1)
+            itemname, mtime = key.rsplit('.', 1)
         except ValueError:
             # we only generate revids that look like path.mtime,
             # so if the split does not work, the revid is invalid
             # and we raise KeyError like if the rev is not there
             raise KeyError(key)
-        return relpath, os.path.join(self.path, relpath)
+        # we get NAME_SEP and need to replace them by os.sep to make valid pathes:
+        if os.sep == NAME_SEP:
+            relpath = itemname
+        else:
+            relpath = itemname.replace(NAME_SEP, os.sep)
+        return itemname, os.path.join(self.path, relpath)
 
     def _mkkey(self, path):
         """
-        absolute path -> relpath, mtime
+        absolute path -> itemname, mtime
         """
         st = os.stat(path)
         root = self.path
         assert path.startswith(root)
-        return path[len(root)+1:], int(st.st_mtime)
+        relpath = path[len(root)+1:]
+        # we always want to give NAME_SEP-separated names (not backslash):
+        if os.sep == NAME_SEP:
+            itemname = relpath
+        else:
+            itemname = relpath.replace(os.sep, NAME_SEP)
+        mtime = int(st.st_mtime)
+        return itemname, mtime
 
     def _encode(self, key):
         """
     def _decode(self, qkey):
         return url_unquote(qkey)
 
-    def _get_meta(self, fn, path):
+    def _get_meta(self, itemname, path):
         try:
             st = os.stat(path)
         except OSError as e:
             if e.errno == errno.ENOENT:
-                raise KeyError(fn)
+                raise KeyError(itemname)
             raise
         meta = {}
-        meta[NAME] = fn
+        meta[NAME] = itemname
         meta[MTIME] = int(st.st_mtime) # use int, not float
         meta[REVID] = unicode(self._encode('%s.%d' % (meta[NAME], meta[MTIME])))
         meta[ITEMID] = meta[REVID]
             size = 0
         elif stat.S_ISREG(st.st_mode):
             # normal file
-            ct = unicode(MimeType(filename=fn).content_type())
+            ct = unicode(MimeType(filename=itemname).content_type())
             size = int(st.st_size) # use int instead of long
         else:
             # symlink, device file, etc.
             content = unicode(err)
         return content
 
-    def _get_data(self, fn, path):
+    def _get_data(self, itemname, path):
         try:
             st = os.stat(path)
             if stat.S_ISDIR(st.st_mode):
                 return StringIO('')
         except (OSError, IOError) as e:
             if e.errno == errno.ENOENT:
-                raise KeyError(fn)
+                raise KeyError(itemname)
             raise
 
     def __iter__(self):
 
     def retrieve(self, key):
         key = self._decode(key)
-        fn, path = self._mkpath(key)
-        meta = self._get_meta(fn, path)
-        data = self._get_data(fn, path)
+        itemname, path = self._mkpath(key)
+        meta = self._get_meta(itemname, path)
+        data = self._get_data(itemname, path)
         return meta, data
 

MoinMoin/storage/stores/_tests/test_sqla.py

 
 @pytest.mark.multi(Store=[BytesStore, FileStore])
 def test_from_uri(tmpdir, Store):
-    store = Store.from_uri("sqlite://%s/test_base" % tmpdir)
-    assert store.db_uri == "sqlite://%s/test_base" % tmpdir
+    store = Store.from_uri("sqlite://%s::test_base" % tmpdir)
+    assert store.db_uri == "sqlite://%s" % tmpdir
     assert store.table_name == "test_base"

MoinMoin/storage/stores/_tests/test_sqlite.py

 
 @pytest.mark.multi(Store=[BytesStore, FileStore])
 def test_from_uri(tmpdir, Store):
-    store = Store.from_uri("%s:test_table:0" % tmpdir)
+    store = Store.from_uri("%s::test_table::0" % tmpdir)
     assert store.db_name == tmpdir
     assert store.table_name == 'test_table'
     assert store.compression_level == 0
 
-    store = Store.from_uri("%s:test_table:2" % tmpdir)
+    store = Store.from_uri("%s::test_table::2" % tmpdir)
     assert store.db_name == tmpdir
     assert store.table_name == 'test_table'
     assert store.compression_level == 2
+

MoinMoin/storage/stores/sqla.py

         :param cls: Class to create
         :param uri: The database uri that we pass on to SQLAlchemy.
         """
-
-        params = [uri]
-        if '/' in uri.rsplit("//")[-1]:
-            table_name = uri.rsplit("/")[-1]
-            params.append(table_name)
+        params = uri.split("::") # using "::" to support windows pathnames that
+                                 # may include ":" after the drive letter.
         return cls(*params)
 
     def __init__(self, db_uri=None, table_name='store', verbose=False):

MoinMoin/storage/stores/sqlite.py

 
         :param cls: Class to create
         :param uri: The URI should follow the following template
-                    db_name:table_name:compression_level
+                    db_name::table_name::compression_level
                     where table_name and compression level are optional
         """
-        params = uri.split(":")
+        params = uri.split("::") # using "::" to support windows pathnames that
+                                 # may include ":" after the drive letter.
         if len(params) == 3:
             params[2] = int(params[2])
         return cls(*params)

MoinMoin/templates/base.html

         user.edit_on_doubleclick and user.may.write(item_name) -%}
             <meta name="edit_on_doubleclick" content="1" />
     {%- endif %}
+    {%- if user.show_comments -%}
+            <meta name="moin-show-comments" content="1" />
+    {%- endif %}
     {% for name, content in theme_supp.meta_items -%}
         <meta name="{{ name }}" content="{{ content }}" />
     {% endfor %}

MoinMoin/templates/itemviews.html

             {%- endif %}
 
             {%- if endpoint == 'special.comments' %}
-                <li class="toggleCommentsButton" style="display:none;">
+                <li class="moin-toggle-comments-button" style="display:none;">
                     <a href="#" onClick="toggleComments();return false;" title="{{ title }}">{{ label }}</a>
                 </li>
             {%- endif %}
 
+        {% if endpoint == 'special.transclusions' -%}
+            <li class="moin-transclusions-button" style="display:none;">
+            <a href="#" onClick="toggleTransclusionOverlays();return false;" title="{{ title }}">{{ label }}</a>
+            </li>
+        {%- endif %}
+
             {%- if endpoint == 'special.supplementation' %}
                 {%- for sub_item_name in cfg.supplementation_item_names %}
                     {%- set current_sub = item_name.rsplit('/', 1)[-1] %}

MoinMoin/themes/foobar/info.json

+{
+    "identifier":   "foobar",
+    "application":  "MoinMoin",
+    "name":         "FooBar Theme",
+    "description":  "moin2's builtin sidebar theme",
+    "author":       "MoinMoin developers",
+    "website":      "http://moinmo.in/",
+    "license":      "see MoinMoin license",
+    "doctype":      "html5"
+}

MoinMoin/themes/foobar/static/css/common.css

+/* Important note: DO NOT EDIT THIS FILE!
+ *
+ * The CSS seen below is automatically generated using the "stylus" tool.
+ * To modify it, edit the files in the "stylus" directory and re-generate
+ * this file from them:
+ *
+ * stylus --include-css --compress < main.styl > ../common.css
+ */
+/*
+Copied from:  http://code.google.com/p/html5resetcss/
+
+html5doctor.com Reset Stylesheet
+v1.6.1
+Last Updated: 2010-09-17
+Author: Richard Clark - http: //richclarkdesign.com
+Twitter: @rich_clark
+*/
+html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p,
+blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins,
+kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure, footer, header, hgroup,
+menu, nav, section, summary, time, mark, audio,
+video { margin: 0; padding: 0; border: 0; outline: 0;
+          font-size: 100%; vertical-align: baseline; background: transparent; }
+body { line-height: 1; }
+article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
+section { display: block; }
+nav ul { list-style: none; }
+blockquote, q { quotes: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
+ins { background-color: #ff9; color: #000; text-decoration: none; }
+mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
+del { text-decoration: line-through; }
+abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
+table { border-collapse: collapse; border-spacing: 0; }
+hr { display: block; height: 1px; border: 0; border-top: 1px solid #cccccc; margin: 1em 0; padding: 0; }
+input, select { vertical-align: middle; }
+/* end HTML5 reset */
+.hll { background-color: #ffffcc }
+.c { color: #408080; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #008000; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.cp { color: #BC7A00 } /* Comment.Preproc */
+.c1 { color: #408080; font-style: italic } /* Comment.Single */
+.cs { color: #408080; font-style: italic } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #008000 } /* Keyword.Pseudo */
+.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #B00040 } /* Keyword.Type */
+.m { color: #666666 } /* Literal.Number */
+.s { color: #BA2121 } /* Literal.String */
+.na { color: #7D9029 } /* Name.Attribute */
+.nb { color: #008000 } /* Name.Builtin */
+.nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.no { color: #880000 } /* Name.Constant */
+.nd { color: #AA22FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.nf { color: #0000FF } /* Name.Function */
+.nl { color: #A0A000 } /* Name.Label */
+.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.nt { color: #008000; font-weight: bold } /* Name.Tag */
+.nv { color: #19177C } /* Name.Variable */
+.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #666666 } /* Literal.Number.Float */
+.mh { color: #666666 } /* Literal.Number.Hex */
+.mi { color: #666666 } /* Literal.Number.Integer */
+.mo { color: #666666 } /* Literal.Number.Oct */
+.sb { color: #BA2121 } /* Literal.String.Backtick */
+.sc { color: #BA2121 } /* Literal.String.Char */
+.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #BA2121 } /* Literal.String.Double */
+.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #BA2121 } /* Literal.String.Heredoc */
+.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.sx { color: #008000 } /* Literal.String.Other */
+.sr { color: #BB6688 } /* Literal.String.Regex */
+.s1 { color: #BA2121 } /* Literal.String.Single */
+.ss { color: #19177C } /* Literal.String.Symbol */
+.bp { color: #008000 } /* Name.Builtin.Pseudo */
+.vc { color: #19177C } /* Name.Variable.Class */
+.vg { color: #19177C } /* Name.Variable.Global */
+.vi { color: #19177C } /* Name.Variable.Instance */
+.il { color: #666666 } /* Literal.Number.Integer.Long */
+/* smileys -- <span class="moin-text-icon moin-smile">:-)</span> */
+.moin-text-icon { font-size: 0; color: transparent; }
+.moin-alert:before { content: url('../img/smileys/alert.png'); }
+.moin-angry:before { content: url('../img/smileys/angry.png'); }
+.moin-attention:before { content: url('../img/smileys/attention.png'); }
+.moin-biggrin:before { content: url('../img/smileys/biggrin.png'); }
+.moin-checkmark:before { content: url('../img/smileys/checkmark.png'); }
+.moin-devil:before { content: url('../img/smileys/devil.png'); }
+.moin-frown:before { content: url('../img/smileys/frown.png'); }
+.moin-icon-error:before { content: url('../img/smileys/icon-error.png'); }
+.moin-icon-info:before { content: url('../img/smileys/icon-info.png'); }
+.moin-idea:before { content: url('../img/smileys/idea.png'); }
+.moin-ohwell:before { content: url('../img/smileys/ohwell.png'); }
+.moin-prio1:before { content: url('../img/smileys/prio1.png'); }
+.moin-prio2:before { content: url('../img/smileys/prio2.png'); }
+.moin-prio3:before { content: url('../img/smileys/prio3.png'); }
+.moin-redface:before { content: url('../img/smileys/redface.png'); }
+.moin-sad:before { content: url('../img/smileys/sad.png'); }
+.moin-smile:before { content: url('../img/smileys/smile.png'); }
+.moin-smile2:before { content: url('../img/smileys/smile2.png'); }
+.moin-smile3:before { content: url('../img/smileys/smile3.png'); }
+.moin-smile4:before { content: url('../img/smileys/smile4.png'); }
+.moin-star_off:before { content: url('../img/smileys/star_off.png'); }
+.moin-star_on:before { content: url('../img/smileys/star_on.png'); }
+.moin-thumbs-up:before { content: url('../img/smileys/thumbs-up.png'); }
+.moin-tired:before { content: url('../img/smileys/tired.png'); }
+.moin-tongue:before { content: url('../img/smileys/tongue.png'); }
+#moin-content div.caution{background-image:url("../img/admonitions/caution.png")}
+#moin-content div.important{background-image:url("../img/admonitions/important.png")}
+#moin-content div.note{background-image:url("../img/admonitions/note.png")}
+#moin-content div.tip{background-image:url("../img/admonitions/tip.png")}
+#moin-content div.warning{background-image:url("../img/admonitions/warning.png")}
+#moin-content div.caution,#moin-content div.important,#moin-content div.note,#moin-content div.tip,#moin-content div.warning{color:#000;background-color:#f9f9ff;background-repeat:no-repeat;background-position:8px 8px;border:1px solid #e5e5e5;margin:10px 30px 10px 30px;min-height:64px;padding-left:64px;clear:both;}
+#moin-content div.caution p,#moin-content div.important p,#moin-content div.note p,#moin-content div.tip p,#moin-content div.warning p{margin-top:8px}
+/* wiki parser  - no moin- prefix added here, these classes are used within pages: {{{#!wiki solid  */
+.comment { color: #555; background-color: #DDF; }
+.red { background-color: #FCC; }
+.green { background-color: #CFC; }
+.blue { background-color: #CCF; }
+.yellow { background-color: #FFF29F; }
+.orange { background-color: #FFD59B; }
+.solid { border: 2px solid #000; padding: 2px; clear: both; }
+.dashed { border: 2px dashed #AEBDCC; padding: 2px; clear: both; }
+.dotted { border: 2px dotted #AEBDCC; padding: 2px; clear: both; }
+.left { text-align: left; }
+.center { text-align: center; }
+.right { text-align: right; }
+.justify { text-align: justify; }
+body{color:#444;background-color:#eee;font-family:sans-serif}
+#moin-global-tray{float:left;width:16.666666666666668%;padding:.5%;overflow:hidden}
+#moin-main-container{float:left;width:81.13333333333333%;padding:.5%}
+#moin-main-box{background-color:#fff;border:1px solid #ccc;border-radius:6px;box-shadow:2px 2px 4px #444;overflow:hidden}
+#moin-header{background-color:#efe;border-bottom:1px solid #ccc;padding:.2% .5%;overflow:auto}
+#moin-content-no-panel{float:left;width:98.56746096959736%;padding:.6162695152013148%;border-right:1px solid #ccc}
+#moin-content-with-panel{float:left;width:76.79260476581759%;padding:.6162695152013148%;border-right:1px solid #ccc}
+#moin-local-panel{float:left;width:20.54231717337716%;padding:.6162695152013148%;margin-left:-1px;border-left:1px solid #ccc}
+#moin-footer{clear:both;font-size:.8em;color:#888;padding:.5% .5%;overflow:auto}
+#moin-breadcrumbs-location{float:left;padding:.3em .5em .2em .5em;font-weight:bold}
+#moin-search{float:right;padding:.3em .5em .2em .5em}
+#moin-logo{width:100%;padding:0 0 1em 0;}
+#moin-logo a{display:block;width:100%;height:70px;background-repeat:no-repeat;background-position:center center}
+#moin-global-panel ul,#moin-local-panel ul{list-style-type:none;margin:0;}
+#moin-global-panel ul li,#moin-local-panel ul li{font-size:1em;color:#008;font-weight:bold;padding:.5em;border:1px solid #ccc;border-radius:4px;box-shadow:1px 1px 2px #444;margin-left:.5em;margin-bottom:.5em;overflow:hidden;word-wrap:break-word;}
+#moin-global-panel ul li ul,#moin-local-panel ul li ul{padding:.2em .1em;}
+#moin-global-panel ul li ul li,#moin-local-panel ul li ul li{font-size:.8em;color:#000;font-weight:normal;padding:.1em .1em .1em .1em;border:none;box-shadow:none;margin:0}
+#moin-footer ul,#moin-credits{float:left;list-style-type:none;}
+#moin-footer ul li,#moin-credits li{padding:.1em}
+#moin-footer-logos{float:right;}
+#moin-footer-logos ul li{display:inline}
+a{text-decoration:none;}
+a:link{color:#47f}
+a:visited{color:#04a}
+a:hover{color:#f00;text-decoration:underline}
+a:active{color:#008000;text-decoration:underline}
+a.moin-nonexistent:link{color:#666}
+a.moin-nonexistent:visited{color:#808080}
+a.moin-nonexistent:hover{color:#000}
+a.moin-nonexistent:active{color:#000}
+ul,dl{margin-left:1.5em}
+ol{margin-left:3em;}
+ol ol{margin-left:1.5em}
+li,dt{padding:.1em}
+dt{font-weight:bold}
+dd{margin-left:1.5em}
+ul.moin-nobullet-list{list-style-type:none}
+ol.moin-upperalpha-list{list-style-type:upper-alpha}
+ol.moin-loweralpha-list{list-style-type:lower-alpha}
+ol.moin-upperroman-list{list-style-type:upper-roman}
+ol.moin-lowerroman-list{list-style-type:lower-roman}
+ul.moin-tags{list-style:none;}
+ul.moin-tags li{display:inline;}
+ul.moin-tags li.weight0{font-size:48.22530864197532%}
+ul.moin-tags li.weight1{font-size:57.870370370370374%}
+ul.moin-tags li.weight2{font-size:69.44444444444446%}
+ul.moin-tags li.weight3{font-size:83.33333333333334%}
+ul.moin-tags li.weight4{font-size:100%}
+ul.moin-tags li.weight5{font-size:120%}
+ul.moin-tags li.weight6{font-size:144%}
+ul.moin-tags li.weight7{font-size:172.79999999999998%}
+ul.moin-tags li.weight8{font-size:207.35999999999999%}
+ul.moin-tags li.weight9{font-size:248.83199999999994%}
+h1{font-size:1.7279999999999998em;margin:.5787037037037038em 0;border-bottom:3px solid #4d7da9;padding-bottom:3px}
+h2{font-size:1.44em;margin:.6944444444444444em 0;border-bottom:3px solid #4d7da9;padding-bottom:3px}
+h3{font-size:1.2em;margin:.8333333333333334em 0;border-bottom:2px solid #4d7da9;padding-bottom:2px}
+h4{font-size:1em;margin:1em 0;border-bottom:2px solid #4d7da9;padding-bottom:2px}
+h5{font-size:.8333333333333334em;margin:1.2em 0;border-bottom:1px solid #4d7da9;padding-bottom:1px}
+h6{font-size:.6944444444444445em;margin:1.4399999999999997em 0;border-bottom:1px solid #4d7da9;padding-bottom:1px}
+a.permalink{display:none;cursor:pointer;margin-left:.1em;color:#888;}
+a.permalink:hover{color:#444}
+h1:hover .permalink,h2:hover .permalink,h3:hover .permalink,h4:hover .permalink,h5:hover .permalink,h6:hover .permalink{display:inline;text-decoration:none}
+hr{background-color:#444;border:0;margin:.9em 0;height:1px;}
+hr.moin-hr1{height:2px}
+hr.moin-hr2{height:3px}
+hr.moin-hr3{height:5px}
+hr.moin-hr4{height:7px}
+hr.moin-hr5{height:9px}
+hr.moin-hr6{height:12px}
+table{margin:.5em;border-collapse:collapse;}
+table th,table td{padding:.3em .4em;vertical-align:middle;text-align:left}
+table th{border:1px solid #4d7da9;background-color:#81bbf2}
+table td{border:1px solid #adb9cc}
+table.zebra{border:none;border-collapse:separate;border-spacing:1px;}
+table.zebra thead{background-color:#81bbf2}
+table.zebra tfoot{background-color:#c4d9ff}
+table.zebra tbody tr,table.zebra > tr{background-color:#eef1f5}
+table.zebra tbody tr:nth-child(odd),table.zebra > tr:nth-child(odd){background-color:#d9dfe8}
+table.zebra th,table.zebra td{border:none}
+pre{font-family:monospace;white-space:pre-wrap;word-wrap:break-word;border:1px solid #aebdcc;background-color:#f3f5f7;margin:.33em 0;padding:5px;clear:both;}
+pre.comment{background-color:#ccc;color:#f00;margin:0;padding:0;border:0;}
+pre.comment:before{content:url("../img/attention.png")}
+textarea{font-family:monospace;width:100%;border:1px solid #ccc}
+input#f_comment{width:100%;border:1px solid #ccc;margin:.3em 0}
+sub{vertical-align:sub}
+sup{vertical-align:super}
+.moin-big{font-size:1.17em}
+.moin-small{font-size:.83em}
+@media print{#moin-global-tray,#moin-local-panel,#moin-footer,#moin-search{display:none}
+}

MoinMoin/themes/foobar/static/css/msie.css

+/* for now, don't add special workarounds for Internet Explorer */
+

MoinMoin/themes/foobar/static/css/stylus/admonitions.styl

+// admonitions  - no moin- prefix added  here, these classes are used within pages: {{{#!wiki caution
+
+#moin-content
+    div.caution
+        background-image url("../img/admonitions/caution.png")
+    div.important
+        background-image url("../img/admonitions/important.png")
+    div.note
+        background-image url("../img/admonitions/note.png")
+    div.tip
+        background-image url("../img/admonitions/tip.png")
+    div.warning
+        background-image url("../img/admonitions/warning.png")
+
+    div.caution, div.important, div.note, div.tip, div.warning
+        color black
+        background-color #F9F9FF
+        background-repeat no-repeat
+        background-position 8px 8px
+        border 1px solid #E5E5E5
+        margin 10px 30px 10px 30px
+        min-height 64px
+        padding-left 64px
+        clear both
+        p
+            margin-top 8px  // to align text with big graphic
+

MoinMoin/themes/foobar/static/css/stylus/main.styl

+// moin2 foobar theme css
+
+// include a comment with a notice that the css file is automatically generated:
+@import "stylus_notice.css"
+
+// reset all browser-specific default to have common defaults everywhere:
+@import "reset.css"
+
+// auto-generated by pygmentize -S default -f html >pygments_default.css
+@import "pygments_default.css"
+
+// smileys used by moin wiki parser (and maybe others)
+@import "smileys.css"
+
+// admonitions used by moin wiki parser (and maybe others)
+@import "admonitions"
+
+// user styles used by moin wiki parser (and maybe others) like red/green/solid/dashed/comment...
+@import "userstyles.css"
+
+body_color = #444444
+body_bg_color = #eeeeee
+main_bg_color = #ffffff
+border_style = 1px solid #cccccc
+header_bg_color = #eeffee
+footer_color = #888888
+panel_titles_color = #000088
+panel_items_color = #000000
+heading_underline_color = #4D7DA9
+shadow_color = #444444
+
+font_family = sans-serif
+main_font_size = 1em
+small_font_size = main_font_size * 0.8
+heading_scale = 1.2  // font size factor for h1 .. h6
+
+dir = left  // 'left' means left-to-right (ltr), 'right' means right-to-left (rtl)
+
+scale = 1  // we have the whole screen width as base
+global_tray_width = 100% / 6 * scale
+global_padding_width = 0.5% * scale
+main_container_width = 99.8% - global_tray_width - (4 * global_padding_width)
+
+scale = 100% / main_container_width  // we have the main container width as base
+local_panel_width = 100% / 6 * scale
+local_padding_width = 0.5% * scale
+content_width_with_panel = 99.8% - local_panel_width - (4 * local_padding_width)
+content_width_no_panel = 99.8% - (2 * local_padding_width)
+
+body
+    color body_color
+    background-color body_bg_color
+    font-family font_family
+
+// the main elements - just the big picture first: panels, header, content, footer
+
+#moin-global-tray
+    float dir
+    width global_tray_width
+    padding global_padding_width
+    overflow hidden
+
+#moin-main-container
+    float dir
+    width main_container_width
+    padding global_padding_width
+
+// contains header and content, but not footer
+#moin-main-box
+    background-color main_bg_color
+    border border_style
+    border-radius 6px
+    box-shadow 2px 2px 4px shadow_color
+    overflow hidden
+
+#moin-header
+    background-color header_bg_color
+    border-bottom border_style
+    padding 0.2% 0.5%
+    overflow auto
+
+#moin-content-no-panel
+    float dir
+    width content_width_no_panel
+    padding local_padding_width
+    {'border-' + opposite-position(dir)} border_style
+
+#moin-content-with-panel
+    float dir
+    width content_width_with_panel
+    padding local_padding_width
+    {'border-' + opposite-position(dir)} border_style
+
+#moin-local-panel
+    float dir
+    width local_panel_width
+    padding local_padding_width
+    {'margin-' + dir} -1px  // make it overlap with content border, see border_style
+    {'border-' + dir} border_style
+
+#moin-footer
+    clear both
+    font-size small_font_size
+    color footer_color
+    padding 0.5% 0.5%
+    overflow auto
+
+// now the stuff inside the main elements
+
+// header elements
+#moin-breadcrumbs-location
+    float dir
+    padding 0.3em 0.5em 0.2em 0.5em
+    font-weight bold
+
+#moin-search
+    float opposite-position(dir)
+    padding 0.3em 0.5em 0.2em 0.5em
+
+// panels, footer
+#moin-logo
+    width 100%
+    padding 0 0 1em 0
+    a
+        display block
+        width 100%
+        height 70px
+        background-repeat no-repeat
+        background-position center center
+
+#moin-global-panel ul,
+#moin-local-panel ul
+    list-style-type none 
+    margin 0
+    li
+        font-size main_font_size
+        color panel_titles_color
+        font-weight bold
+        padding 0.5em
+        border border_style
+        border-radius 4px
+        box-shadow 1px 1px 2px shadow_color
+        margin-left 0.5em
+        margin-bottom 0.5em
+        overflow hidden
+        word-wrap break-word
+        ul
+            padding 0.2em 0.1em
+            li
+                font-size small_font_size
+                color panel_items_color
+                font-weight normal
+                padding 0.1em 0.1em 0.1em 0.1em
+                border none
+                box-shadow none
+                margin 0
+
+#moin-footer ul,
+#moin-credits
+    float dir
+    list-style-type none 
+    li
+        padding 0.1em
+
+#moin-footer-logos
+    float opposite-position(dir)
+    ul li
+        display inline
+
+
+// links
+a
+    text-decoration none
+    // order must be: link, visited, hover, active
+    &:link
+        color #47F
+    &:visited
+        color #04A
+    &:hover
+        color red
+        text-decoration underline
+    &:active
+        color green
+        text-decoration underline
+    &.moin-nonexistent:link
+        color #666
+    &.moin-nonexistent:visited
+        color grey
+    &.moin-nonexistent:hover
+        color black
+    &.moin-nonexistent:active
+        color black
+
+
+// lists
+ul, dl
+    margin-left 1.5em
+ol
+    // ordered list, first level needs big margin that will contain the number
+    margin-left 3em
+    ol
+        // for >= second level we need less
+        margin-left 1.5em
+
+li, dt
+    padding 0.1em
+
+dt
+    font-weight bold
+dd
+    margin-left 1.5em
+
+ul
+    &.moin-nobullet-list
+        list-style-type none
+
+ol
+    &.moin-upperalpha-list
+        list-style-type upper-alpha
+    &.moin-loweralpha-list
+        list-style-type lower-alpha
+    &.moin-upperroman-list
+        list-style-type upper-roman
+    &.moin-lowerroman-list
+        list-style-type lower-roman
+
+// tags list / tag cloud
+tag_scale = 1.2
+tag_font_size = 100%
+
+ul.moin-tags
+    list-style none
+    li
+        display inline
+        for n in 0 1 2 3 4 5 6 7 8 9
+            { '&.weight' + n }
+                scale_tag = tag_scale ** (n - 4)
+                font-size tag_font_size * scale_tag
+
+// headings
+for n in 1 2 3 4 5 6
+    {'h' + n}
+        scale_font = heading_scale ** (4 - n)
+        font-size main_font_size * scale_font
+        margin (1em / scale_font) 0
+        heading_underline_thickness = floor(4px - n / 2)
+        border-bottom heading_underline_thickness solid heading_underline_color
+        padding-bottom heading_underline_thickness
+
+// special style for heading with mouseover permalinks
+a.permalink
+    display none
+    cursor pointer
+    margin-left 0.1em
+    color footer_color
+    &:hover
+        color body_color
+
+h1:hover .permalink,
+h2:hover .permalink,
+h3:hover .permalink,
+h4:hover .permalink,
+h5:hover .permalink,
+h6:hover .permalink
+    display inline
+    text-decoration none
+
+// horizontal rule ---- and custom rules ----- to ----------
+hr
+    background-color body_color
+    border 0
+    margin .9em 0
+    height 1px
+    &.moin-hr1
+        height 2px
+    &.moin-hr2
+        height 3px
+    &.moin-hr3
+        height 5px
+    &.moin-hr4
+        height 7px
+    &.moin-hr5
+         height 9px
+    &.moin-hr6
+        height 12px
+
+// tables
+table
+    margin 0.5em
+    border-collapse collapse
+    th, td
+        padding 0.3em 0.4em
+        vertical-align middle
+        text-align left
+    th
+        border 1px solid #4D7DA9
+        background-color #81BBF2
+    td
+        border 1px solid #ADB9CC
+
+table.zebra
+    border none
+    border-collapse separate
+    border-spacing 1px
+    thead
+        background-color #81BBF2
+    tfoot
+        background-color #C4D9FF
+    tbody tr,
+    > tr
+        background-color #EEF1F5
+    tbody tr:nth-child(odd),
+    > tr:nth-child(odd)
+        background-color #D9DFE8
+    th,
+    td
+        border none
+
+pre
+    font-family monospace
+    white-space pre-wrap
+    word-wrap break-word
+    border 1px solid #AEBDCC
+    background-color #F3F5F7
+    margin .33em 0
+    padding 5px
+    clear both
+    &.comment
+        background-color #CCC
+        color red
+        margin 0
+        padding 0
+        border 0
+        &:before
+            content url(../img/attention.png)
+
+textarea
+    font-family monospace
+    width 100%
+    border border_style
+
+input#f_comment
+    width 100%
+    border border_style
+    margin .3em 0
+
+// text styles
+sub
+    vertical-align sub
+sup
+    vertical-align super
+.moin-big
+    font-size 1.17em
+.moin-small
+    font-size .83em
+
+/* fix tests -- currently checking <big> and <small> */
+@media print
+    #moin-global-tray
+    #moin-local-panel
+    #moin-footer
+    #moin-search
+        display none
+

MoinMoin/themes/foobar/static/css/stylus/pygments_default.css

+.hll { background-color: #ffffcc }
+.c { color: #408080; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #008000; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.cp { color: #BC7A00 } /* Comment.Preproc */
+.c1 { color: #408080; font-style: italic } /* Comment.Single */
+.cs { color: #408080; font-style: italic } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #808080 } /* Generic.Output */
+.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #008000 } /* Keyword.Pseudo */
+.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #B00040 } /* Keyword.Type */
+.m { color: #666666 } /* Literal.Number */
+.s { color: #BA2121 } /* Literal.String */
+.na { color: #7D9029 } /* Name.Attribute */
+.nb { color: #008000 } /* Name.Builtin */
+.nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.no { color: #880000 } /* Name.Constant */
+.nd { color: #AA22FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.nf { color: #0000FF } /* Name.Function */
+.nl { color: #A0A000 } /* Name.Label */
+.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.nt { color: #008000; font-weight: bold } /* Name.Tag */
+.nv { color: #19177C } /* Name.Variable */
+.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #666666 } /* Literal.Number.Float */
+.mh { color: #666666 } /* Literal.Number.Hex */
+.mi { color: #666666 } /* Literal.Number.Integer */
+.mo { color: #666666 } /* Literal.Number.Oct */
+.sb { color: #BA2121 } /* Literal.String.Backtick */
+.sc { color: #BA2121 } /* Literal.String.Char */
+.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #BA2121 } /* Literal.String.Double */
+.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #BA2121 } /* Literal.String.Heredoc */
+.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.sx { color: #008000 } /* Literal.String.Other */
+.sr { color: #BB6688 } /* Literal.String.Regex */
+.s1 { color: #BA2121 } /* Literal.String.Single */
+.ss { color: #19177C } /* Literal.String.Symbol */
+.bp { color: #008000 } /* Name.Builtin.Pseudo */
+.vc { color: #19177C } /* Name.Variable.Class */
+.vg { color: #19177C } /* Name.Variable.Global */
+.vi { color: #19177C } /* Name.Variable.Instance */
+.il { color: #666666 } /* Literal.Number.Integer.Long */

MoinMoin/themes/foobar/static/css/stylus/reset.css

+/*
+Copied from:  http://code.google.com/p/html5resetcss/
+
+html5doctor.com Reset Stylesheet
+v1.6.1
+Last Updated: 2010-09-17
+Author: Richard Clark - http: //richclarkdesign.com
+Twitter: @rich_clark
+*/
+html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p,
+blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins,
+kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure, footer, header, hgroup,
+menu, nav, section, summary, time, mark, audio,
+video { margin: 0; padding: 0; border: 0; outline: 0;
+            font-size: 100%; vertical-align: baseline; background: transparent; }
+body { line-height: 1; }
+article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
+section { display: block; }
+nav ul { list-style: none; }
+blockquote, q { quotes: none; }
+blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
+a { margin: 0; padding: 0; font-size: 100%; vertical-align: baseline; background: transparent; }
+ins { background-color: #ff9; color: #000; text-decoration: none; }
+mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
+del { text-decoration: line-through; }
+abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
+table { border-collapse: collapse; border-spacing: 0; }
+hr { display: block; height: 1px; border: 0; border-top: 1px solid #cccccc; margin: 1em 0; padding: 0; }
+input, select { vertical-align: middle; }
+/* end HTML5 reset */
+

MoinMoin/themes/foobar/static/css/stylus/smileys.css

+/* smileys -- <span class="moin-text-icon moin-smile">:-)</span> */
+.moin-text-icon { font-size: 0; color: transparent; }
+.moin-alert:before { content: url('../img/smileys/alert.png'); }
+.moin-angry:before { content: url('../img/smileys/angry.png'); }
+.moin-attention:before { content: url('../img/smileys/attention.png'); }
+.moin-biggrin:before { content: url('../img/smileys/biggrin.png'); }
+.moin-checkmark:before { content: url('../img/smileys/checkmark.png'); }
+.moin-devil:before { content: url('../img/smileys/devil.png'); }
+.moin-frown:before { content: url('../img/smileys/frown.png'); }
+.moin-icon-error:before { content: url('../img/smileys/icon-error.png'); }
+.moin-icon-info:before { content: url('../img/smileys/icon-info.png'); }
+.moin-idea:before { content: url('../img/smileys/idea.png'); }
+.moin-ohwell:before { content: url('../img/smileys/ohwell.png'); }
+.moin-prio1:before { content: url('../img/smileys/prio1.png'); }
+.moin-prio2:before { content: url('../img/smileys/prio2.png'); }
+.moin-prio3:before { content: url('../img/smileys/prio3.png'); }
+.moin-redface:before { content: url('../img/smileys/redface.png'); }
+.moin-sad:before { content: url('../img/smileys/sad.png'); }
+.moin-smile:before { content: url('../img/smileys/smile.png'); }
+.moin-smile2:before { content: url('../img/smileys/smile2.png'); }
+.moin-smile3:before { content: url('../img/smileys/smile3.png'); }
+.moin-smile4:before { content: url('../img/smileys/smile4.png'); }
+.moin-star_off:before { content: url('../img/smileys/star_off.png'); }
+.moin-star_on:before { content: url('../img/smileys/star_on.png'); }
+.moin-thumbs-up:before { content: url('../img/smileys/thumbs-up.png'); }
+.moin-tired:before { content: url('../img/smileys/tired.png'); }
+.moin-tongue:before { content: url('../img/smileys/tongue.png'); }
+

MoinMoin/themes/foobar/static/css/stylus/stylus_notice.css

+/* Important note: DO NOT EDIT THIS FILE!
+ *
+ * The CSS seen below is automatically generated using the "stylus" tool.
+ * To modify it, edit the files in the "stylus" directory and re-generate
+ * this file from them:
+ *
+ * stylus --include-css --compress < main.styl > ../common.css
+ */
+
+

MoinMoin/themes/foobar/static/css/stylus/userstyles.css

+/* wiki parser  - no moin- prefix added here, these classes are used within pages: {{{#!wiki solid  */
+.comment { color: #555; background-color: #DDF; }
+.red { background-color: #FCC; }
+.green { background-color: #CFC; }
+.blue { background-color: #CCF; }
+.yellow { background-color: #FFF29F; }
+.orange { background-color: #FFD59B; }
+.solid { border: 2px solid #000; padding: 2px; clear: both; }
+.dashed { border: 2px dashed #AEBDCC; padding: 2px; clear: both; }
+.dotted { border: 2px dotted #AEBDCC; padding: 2px; clear: both; }
+.left { text-align: left; }
+.center { text-align: center; }
+.right { text-align: right; }
+.justify { text-align: justify; }
+
Add a comment to this file

MoinMoin/themes/foobar/static/img/admonitions/caution.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/admonitions/important.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/admonitions/note.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/admonitions/tip.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/admonitions/warning.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/alert.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/angry.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/attention.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/biggrin.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/checkmark.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/devil.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/frown.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/icon-error.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/icon-info.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/idea.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/ohwell.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/prio1.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/prio2.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/prio3.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/redface.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/sad.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/smile.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/smile2.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/smile3.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/smile4.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/star_off.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/star_on.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/thumbs-up.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/tired.png

Added
New image
Add a comment to this file

MoinMoin/themes/foobar/static/img/smileys/tongue.png

Added
New image

MoinMoin/themes/foobar/templates/delete.html