Ejemplo n.º 1
0
    def visit_moinpage_h(self, element):
        """
        There is not really heading in DocBook, but rather section with
        title. The section is a root tag for all the elements which in
        the dom tree will be between two heading tags.

        So we need to process child manually to determine correctly the
        children of each section.

        A section is closed when we have a new heading with an equal or
        higher level.
        """
        depth = element.get(moin_page('outline-level'))
        # We will have a new section
        # under another section
        if depth > self.current_section:
            self.parent_section = self.current_section
            self.current_section = int(depth)
            self.section_children[self.current_section] = []
            # NB : Error with docbook.title
            title = ET.Element(docbook('title'), attrib={}, children=element[0])
            self.section_children[self.current_section].append(title)

        # We will close a section before starting a new one
        # Need more test
        elif depth < self.current_section:
            if self.parent_section != 0:
                section_tag = 'sect{0}'.format(self.parent_section)
                section = ET.Element(docbook(section_tag), attrib={},
                                     children=self.section_children[self.current_section])
                self.section_children[self.parent_section].append(section)
                self.current_section = int(depth)
Ejemplo n.º 2
0
    def visit_qandaentry_number(self, element, depth):
        """
        Convert::

            <question>Q</question><answer>A</answer>

        to::

            <list-item>
                <list-item-body><p>Q</p><p>A</p></list-item-body>
            </list-item>
        """
        items = []
        for child in element:
            if isinstance(child, ET.Element):
                if child.tag.name == 'question' or child.tag.name == 'answer':
                    r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    items.extend(r)
            else:
                items.append(child)

        item_body = ET.Element(moin_page('list-item-body'), attrib={}, children=items)
        return ET.Element(moin_page('list-item'), attrib={}, children=[item_body])
Ejemplo n.º 3
0
    def visit_simple_list(self, moin_page_tag, attrib, element, depth):
        """
        There is different list element in DocBook with different
        semantic meaning, but with an unique result in the DOM Tree.

        Here we handle the conversion of such of list.
        """
        list_item_tags = set(['listitem', 'step', 'stepalternatives', 'member'])
        items = []
        for child in element:
            if isinstance(child, ET.Element):
                if child.tag.name in list_item_tags:
                    children = self.visit(child, depth)
                    list_item_body = ET.Element(moin_page('list-item-body'), attrib={}, children=children)
                    tag = ET.Element(moin_page('list-item'), attrib={},
                                     children=[list_item_body])
                    tag = (tag, )
                    items.extend(tag)
                else:
                    r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    items.extend(r)
            else:
                items.append(child)
        return ET.Element(moin_page.list, attrib=attrib, children=items)
Ejemplo n.º 4
0
    def visit_docbook_seglistitem(self, element, labels, depth):
        """
        A seglistitem is a list-item for a segmented list. It is quite
        special because it act list definition with label, but the labels
        are predetermined in the labels list.

        So we generate label/body couple according to the content in
        labels
        """
        new = []
        counter = 0
        for child in element:
            if isinstance(child, ET.Element):
                if child.tag.name == 'seg':
                    label_tag = ET.Element(moin_page('list-item-label'),
                                           attrib={}, children=labels[counter % len(labels)])
                    body_tag = ET.Element(moin_page('list-item-body'),
                                          attrib={}, children=self.visit(child, depth))
                    item_tag = ET.Element(moin_page('list-item'),
                                          attrib={}, children=[label_tag, body_tag])
                    item_tag = (item_tag, )
                    new.extend(item_tag)
                    counter += 1
                else:
                    r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    new.extend(r)
            else:
                new.append(child)
        return new
Ejemplo n.º 5
0
    def visit_xhtml_dl(self, element):
        """
        Convert a list of definition. The starting structure::

            <dl>
                <dt>Label 1</dt><dd>Text 1</dd>
                <dt>Label 2</dt><dd>Text 2</dd>
            </dl>

        will be converted to::

            <list>
                <list-item>
                    <list-item-label>Label 1</list-item-label>
                    <list-item-body>Text 1</list-item-body>
                </list-item>
                <list-item>
                    <list-item-label>Label 2</list-item-label>
                    <list-item-body>Text 2</list-item-body>
                </list-item>
            </list>
        """
        list_item = []
        pair = []
        number_pair = 0
        # We will browse the child, and try to catch all the pair
        # of <dt><dd>
        for child in element:
            # We need one dt tag, and one dd tag, a have a pair
            if child.tag.name == 'dt' or child.tag.name == 'dd':
                number_pair += 1

            # The following code is similar to do_children method
            if isinstance(child, ET.Element):
                r = self.visit(child)
                if r is None:
                    r = ()
                elif not isinstance(r, (list, tuple)):
                    r = (r, )
                pair.extend(r)
            else:
                pair.append(r)

            if number_pair == 2:
                # We have two elements of the pair
                # So we can put it into a <list-item> element
                list_item_element = ET.Element(moin_page.list_item,
                                               attrib={},
                                               children=pair)
                list_item.append(list_item_element)
                pair = []
                number_pair = 0

        # we return the <list> with all the list item element
        return ET.Element(moin_page.list, attrib={}, children=list_item)
Ejemplo n.º 6
0
 def new(self, tag, attrib, children):
     """
     Return a new element in the DocBook tree.
     """
     if self.standard_attribute:
         attrib.update(self.standard_attribute)
         self.standard_attribute = {}
     if self.current_section > 0:
         self.section_children[self.current_section].append(
             ET.Element(tag, attrib=attrib, children=children))
     else:
         return ET.Element(tag, attrib=attrib, children=children)
Ejemplo n.º 7
0
    def visit_xhtml_li(self, element):
        """
        NB : A list item (<li>) is like the following snippet::

            <list-item>
                <list-item-label>label</list-item-label>
                <list-item-body>Body</list-item-body>
            </list-item>

        For <li> element, there is no label
        """
        list_item_body = ET.Element(moin_page.list_item_body,
                                    attrib={}, children=self.do_children(element))
        return ET.Element(moin_page.list_item, attrib={}, children=[list_item_body])
Ejemplo n.º 8
0
 def visit_moinpage_list_item_body(self, element):
     items = []
     for child in element:
         if isinstance(child, ET.Element):
             r = self.visit(child)
             if r is None:
                 r = ()
             elif not isinstance(r, (list, tuple)):
                 r = (r, )
             items.extend(r)
         else:
             an_item = ET.Element(docbook.simpara, attrib={}, children=child)
             items.append(an_item)
     return ET.Element(docbook.listitem, attrib={}, children=items)
Ejemplo n.º 9
0
    def visit_qandaentry_qanda(self, element, depth):
        """
        Convert::

            <question>Q body</question><answer>A Body</answer>

        to::

            <list-item>
                <list-item-label>Q:</list-item-label>
                <list-item-body>Q Body</list-item-body>
            </list-item>
            <list-item>
                <list-item-label>A:</list-item-label>
                <list-item-body>A Body</list-item-body>
            </list-item>
        """
        items = []
        for child in element:
            if isinstance(child, ET.Element):
                r = ()
                item_label = None
                if child.tag.name == 'question':
                    item_label = ET.Element(moin_page('list-item-label'),
                                            attrib={},
                                            children="Q:")
                elif child.tag.name == 'answer':
                    item_label = ET.Element(moin_page('list-item-label'),
                                            attrib={},
                                            children="A:")
                else:
                    r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    items.extend(r)
                if item_label is not None:
                    item_body = ET.Element(moin_page('list-item-body'),
                                           attrib={},
                                           children=self.visit(child, depth))
                    r = (item_label, item_body)
                    list_item = ET.Element(moin_page('list-item'),
                                           attrib={},
                                           children=r)
                    items.append(list_item)
            else:
                items.append(child)
        return items
Ejemplo n.º 10
0
    def visit_list(self, element):
        """
        Convert a list of item (whatever the type : ordered or unordered)
        So we have html code like::

            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
            </ul>

        Which will be converted to::

            <list>
                <list-item>
                    <list-item-body>Item 1</list-item-body>
                </list-item>
                <list-item>
                    <list-item-body>Item 2</list-item-body>
                </list-item>
            </list>
        """
        # We will define the appropriate attribute
        # according to the type of the list
        attrib = {}
        if element.tag == "ul" or element.tag == "dir":
            attrib[moin_page('item-label-generate')] = 'unordered'
        elif element.tag == "ol":
            attrib[moin_page('item-label-generate')] = 'ordered'

        return ET.Element(moin_page.list, attrib=attrib, children=self.do_children(element))
Ejemplo n.º 11
0
    def visit_docbook_segmentedlist(self, element, depth):
        """
        A segmented list is a like a list of definition, but the label
        are defined at the start with <segtitle> tag and then for each
        definition, we repeat the label.

        So to convert such list, we will first determine and save the
        labels. Then we will iterate over the object to get the
        definition.
        """
        labels = []
        new = []
        for child in element:
            if isinstance(child, ET.Element):
                r = None
                if child.tag.name == 'segtitle':
                    r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    labels.extend(r)
                else:
                    if child.tag.name == 'seglistitem':
                        r = self.visit_docbook_seglistitem(child, labels, depth)
                    else:
                        r = self.visit(child, depth)
                    if r is None:
                        r = ()
                    elif not isinstance(r, (list, tuple)):
                        r = (r, )
                    new.extend(r)
            else:
                new.append(child)
        return ET.Element(moin_page.list, attrib={}, children=new)
Ejemplo n.º 12
0
    def visit_data_element(self, element, depth, object_data, text_object, caption):
        """
        We will try to return an object element based on the
        object_data. If it is not possible, we return a paragraph
        with the content of text_object.
        """
        attrib = {}
        preferred_format, data_tag, mimetype = self.media_tags[element.tag.name]
        if not object_data:
            if not text_object:
                return
            else:
                children = self.do_children(element, depth + 1)
                return self.new(moin_page.p, attrib={}, children=children)
        # We try to determine the best object to show
        for obj in object_data:
            format = obj.get('format')  # format is optional: <imagedata format="jpeg" fileref="jpeg.jpg"/>
            if format:
                format = format.lower()
                if format in preferred_format:
                    object_to_show = obj
                    break
                else:
                    # unsupported format
                    object_to_show = None
            else:
                # XXX: Maybe we could add some verification over the extension of the file
                object_to_show = obj

        if object_to_show is None:
            # we could not find any suitable object, return the text_object replacement.
            children = self.do_children(text_object, depth + 1)
            return self.new(moin_page.p, attrib={}, children=children)

        href = object_to_show.get('fileref')
        if not href:
            # We could probably try to use entityref,
            # but at this time we won't support it.
            return
        attrib[html.alt] = href
        attrib[xlink.href] = '+get/' + href
        format = object_to_show.get('format')
        if format:
            format = format.lower()
            attrib[moin_page('type')] = ''.join([mimetype, format])
        else:
            attrib[moin_page('type')] = mimetype
        align = object_to_show.get('align')
        if align and align in set(['left', 'center', 'right', 'top', 'middle', 'bottom']):
            attrib[html.class_] = align

        # return object tag, html_out.py will convert to img, audio, or video based on type attr
        ret = ET.Element(moin_page.object, attrib=attrib)
        ret = mark_item_as_transclusion(ret, href)
        if caption:
            caption = self.new(moin_page.span, attrib={moin_page.class_: 'db-caption'}, children=[caption])
            return self.new(moin_page.span, attrib={}, children=[ret, caption])
        else:
            return ret
Ejemplo n.º 13
0
 def new(self, tag, attrib, children):
     """
     Return a new element for the DocBook Tree.
     """
     if self.standard_attribute:
         attrib.update(self.standard_attribute)
         self.standard_attribute = {}
     return ET.Element(tag, attrib=attrib, children=children)
Ejemplo n.º 14
0
 def visit_moinpage_table(self, element):
     # TODO: Attributes conversion
     title = element.get(html('title'))
     if not title:
         # TODO: Translation
         title = "Table {0}".format(self.table_counter)
     self.table_counter += 1
     caption = ET.Element(docbook('caption'), attrib={}, children=[title])
     children = [caption]
     children.extend(self.do_children(element))
     return self.new(docbook.table, attrib={}, children=children)
Ejemplo n.º 15
0
    def visit_moinpage_page(self, element):
        title = ET.Element(docbook('title'), attrib={}, children=[self.title])
        info = ET.Element(docbook.info, attrib={}, children=[title])
        for item in element:
            if item.tag.uri == moin_page and item.tag.name == 'body':
                c = self.do_children(item)
                if not c:
                    self.section_children = sorted(self.section_children.items(),
                                                   reverse=True)
                    section = None
                    for k, v in self.section_children:
                        if section:
                            section_tag = 'sect{0}'.format(k)
                            v.append(section)
                            section = ET.Element(docbook(section_tag),
                                                 attrib={}, children=v)
                        else:
                            section_tag = 'sect{0}'.format(k)
                            section = ET.Element(docbook(section_tag),
                                                 attrib={}, children=v)
                    return ET.Element(docbook.article,
                                      attrib={}, children=[info, section])
                else:
                    c.insert(0, info)
                    return ET.Element(docbook.article, attrib={}, children=c)

        raise RuntimeError('page:page need to contain exactly one page body tag, got {0!r}'.format(element[:]))
Ejemplo n.º 16
0
 def visit_xhtml_table(self, element):
     attrib = self.convert_attributes(element)
     # we should not have any strings in the child
     list_table_elements = []
     for child in element:
         if isinstance(child, ET.Element):
             r = self.visit(child)
             if r is None:
                 r = ()
             elif not isinstance(r, (list, tuple)):
                 r = (r, )
             list_table_elements.extend(r)
     return ET.Element(moin_page.table, attrib=attrib, children=list_table_elements)
Ejemplo n.º 17
0
    def visit_xhtml_list(self, element):
        """
        Convert a list of items (whatever the type : ordered or unordered)
        So we have html code like::

            <ul>
                <li>Item 1</li>
                <li>Item 2</li>
            </ul>

        Which will be converted to::

            <list>
                <list-item>
                    <list-item-body>Item 1</list-item-body>
                </list-item>
                <list-item>
                    <list-item-body>Item 2</list-item-body>
                </list-item>
            </list>
        """
        # We will define the appropriate attribute
        # according to the type of the list
        attrib = self.convert_attributes(element)
        if element.tag.name == "ul" or element.tag.name == "dir":
            attrib[moin_page('item-label-generate')] = 'unordered'
        elif element.tag.name == "ol":
            attrib[moin_page('item-label-generate')] = 'ordered'

            # We check which kind of style we have
            style = element.get(html.type)
            if 'A' == style:
                attrib[moin_page('list-style-type')] = 'upper-alpha'
            elif 'I' == style:
                attrib[moin_page('list-style-type')] = 'upper-roman'
            elif 'a' == style:
                attrib[moin_page('list-style-type')] = 'lower-alpha'
            elif 'i' == style:
                attrib[moin_page('list-style-type')] = 'lower-roman'

        # we should not have any strings in the child
        list_items = []
        for child in element:
            if isinstance(child, ET.Element):
                r = self.visit(child)
                if r is None:
                    r = ()
                elif not isinstance(r, (list, tuple)):
                    r = (r, )
                list_items.extend(r)
        return ET.Element(moin_page.list, attrib=attrib, children=list_items)
Ejemplo n.º 18
0
    def visit_data_element(self, element, depth, object_data,
                           text_object, caption):
        """
        We will try to return an object element based on the
        object_data. If it is not possible, we return a paragraph
        with the content of text_object.
        """
        attrib = {}
        prefered_format, data_tag, mimetype = self.media_tags[element.tag.name]
        if not object_data:
            if not text_object:
                return
            else:
                children = self.do_children(child, depth+1)[0]
                return self.new(moin_page.p, attrib={},
                                children=children)
        # We try to determine the best object to show
        object_to_show = None
        for obj in object_data:
            format = obj.get('format')
            if format:
                format = format.lower()
                if format in prefered_format:
                    object_to_show = obj
                    break
            else:
                #XXX: Maybe we could add some verification over the
                #     extension of the file
                object_to_show = obj

        # If we could not find any suitable object, we return
        # the text replacement.
        if not object_to_show:
            children = self.do_children(child, depth+1)[0]
            return self.new(moin_page.p, attrib={},
                            children=children)

        href = object_to_show.get('fileref')
        if not href:
            # We could probably try to use entityref,
            # but at this time we won't support it.
            return
        attrib[xlink.href] = href
        format = object_to_show.get('format')
        if format:
            format = format.lower()
            attrib[moin_page('type')] = ''.join([mimetype, format])
        else:
            attrib[moin_page('type')] = mimetype
        return ET.Element(moin_page.object, attrib=attrib)
Ejemplo n.º 19
0
 def visit_docbook_table(self, element, depth):
     """
     <table> --> <table>
     """
     # we should not have any strings in the child
     list_table_elements = []
     for child in element:
         if isinstance(child, ET.Element):
             r = self.visit(child, depth)
             if r is None:
                 r = ()
             elif not isinstance(r, (list, tuple)):
                 r = (r, )
             list_table_elements.extend(r)
     return ET.Element(moin_page.table, attrib={}, children=list_table_elements)
Ejemplo n.º 20
0
    def replace_smiley(self, text):
        """
        Replace a given string by the appropriate
        element if the string is exactly a smiley.
        Otherwise return the string without any change.
        """
        # Remove the space of the smiley_text if any
        smiley_markup = text.strip()

        if smiley_markup in self.smileys:
            smiley_name = self.smileys[smiley_markup]
            attrib = {moin_page('class'): 'moin-text-icon moin-' + smiley_name}
            return ET.Element(moin_page.span, attrib=attrib, children=[smiley_markup])
        else:
            # if the text was not a smiley, just return the markup without any transformations
            return text
Ejemplo n.º 21
0
    def handle_simple_list(self, docbook_tag, element, attrib):
        list_items = []
        for child in element:
            if isinstance(child, ET.Element):
                # We do not care about <list-item>
                if child.tag.name != 'list-item':
                    r = self.visit(child)
                else:
                    r = self.do_children(child)

                if r is None:
                    r = ()
                elif not isinstance(r, (list, tuple)):
                    r = (r, )
                list_items.extend(r)
        return ET.Element(docbook_tag, attrib=attrib, children=list_items)
Ejemplo n.º 22
0
 def visit_qandaset_qanda(self, element, depth):
     """
     <qandaset defaultlabel="qanda"> --> <list>
     """
     items = []
     for child in element:
         if isinstance(child, ET.Element):
             r = ()
             if child.tag.name == 'qandaentry':
                 r = self.visit_qandaentry_qanda(child, depth)
             else:
                 r = self.visit(child, depth)
             if r is None:
                 r = ()
             elif not isinstance(r, (list, tuple)):
                 r = (r, )
             items.extend(r)
         else:
             items.append(child)
     return ET.Element(moin_page('list'), attrib={}, children=items)
Ejemplo n.º 23
0
 def visit_qandaset_number(self, element, depth):
     """
     <qandaset defaultlabel="number">
       --> <list item-label-generate='ordered'>
     """
     attrib = {}
     key = moin_page('item-label-generate')
     attrib[key] = 'ordered'
     items = []
     for child in element:
         if isinstance(child, ET.Element):
             if child.tag.name == 'qandaentry':
                 r = self.visit_qandaentry_number(child, depth)
             else:
                 r = self.visit(child, depth)
             if r is None:
                 r = ()
             elif not isinstance(r, (list, tuple)):
                 r = (r, )
             items.extend(r, )
         else:
             items.append(child)
     return ET.Element(moin_page('list'), attrib=attrib, children=items)
Ejemplo n.º 24
0
def test_wikiexternal(conv, input_, output):
    elem = ET.Element(None)
    conv.handle_external_links(elem, Iri(input_))
    href = elem.get(xlink.href)
    assert href == output
Ejemplo n.º 25
0
 def __call__(self, attrib=None, children=(), **extra):
     return ET.Element(self, attrib=attrib, children=children, **extra)
Ejemplo n.º 26
0
 def new(self, tag, attrib, children):
     """
     Return a new element for the DOM Tree
     """
     return ET.Element(tag, attrib=attrib, children=children)
Ejemplo n.º 27
0
 def new(self, tag, attrib={}, children=[]):
     return ET.Element(tag, attrib=attrib, children=children)
Ejemplo n.º 28
0
def test_wikilocal(conv, input_, page, output):
    elem = ET.Element(None)
    conv.handle_wikilocal_links(elem, Iri(input_), Iri(page))
    assert elem.get(xlink.href) == output
Ejemplo n.º 29
0
    def recurse(self, elem, page_href):
        # on first call, elem.tag.name=='page'.
        # Descendants (body, div, p, include, page, etc.) are processed by recursing through DOM

        # stack is used to detect transclusion loops
        page_href_new = elem.get(moin_page.page_href)
        if page_href_new:
            page_href_new = Iri(page_href_new)
            if page_href_new != page_href:
                page_href = page_href_new
                self.stack.append(page_href)
            else:
                self.stack.append(None)
        else:
            self.stack.append(None)

        try:
            if elem.tag == xinclude.include:
                # we have already recursed several levels and found a transclusion: "{{SomePage}}" or <<Include(...)>>
                # process the transclusion and add it to the DOM.  Subsequent recursions will traverse through
                # the transclusion's elements.
                href = elem.get(xinclude.href)
                xpointer = elem.get(xinclude.xpointer)

                xp_include_pages = None
                xp_include_sort = None
                xp_include_items = None
                xp_include_skipitems = None
                xp_include_heading = None
                xp_include_level = None

                if xpointer:
                    # we are working on an <<Include(abc)>> macro, not a {{transclusion}}
                    xp = XPointer(xpointer)
                    xp_include = None
                    xp_namespaces = {}
                    for entry in xp:
                        uri = None
                        name = entry.name.split(':', 1)
                        if len(name) > 1:
                            prefix, name = name
                            uri = xp_namespaces.get(prefix, False)
                        else:
                            name = name[0]

                        if uri is None and name == 'xmlns':
                            d_prefix, d_uri = entry.data.split('=', 1)
                            xp_namespaces[d_prefix] = d_uri
                        elif uri == moin_page.namespace and name == 'include':
                            xp_include = XPointer(entry.data)

                    if xp_include:
                        for entry in xp_include:
                            name, data = entry.name, entry.data_unescape
                            # TODO: These do not include all parameters in moin 1.9 Include macro docs:
                            # <<Include(pagename, heading, level, from="regex", to="regex", sort=ascending|descending, items=n, skipitems=n, titlesonly, editlink)>>
                            # these are currently unsupported in moin 2.0: from, to, titlesonly, editlink
                            if name == 'pages':  # pages == pagename in moin 1.9
                                xp_include_pages = data
                            elif name == 'sort':
                                xp_include_sort = data
                            elif name == 'items':
                                xp_include_items = int(data)
                            elif name == 'skipitems':
                                xp_include_skipitems = int(data)
                            elif name == 'heading':
                                xp_include_heading = data
                            elif name == 'level':
                                xp_include_level = data

                included_elements = []
                if href:
                    # We have a single page to transclude or include
                    href = Iri(href)
                    link = Iri(scheme='wiki', authority='')
                    if href.scheme == 'wiki':
                        if href.authority:
                            raise ValueError(
                                "can't handle xinclude for non-local authority"
                            )
                        else:
                            path = href.path[1:]
                    elif href.scheme == 'wiki.local':
                        page = page_href
                        path = href.path
                        if path[0] == '':
                            # /subitem
                            tmp = page.path[1:]
                            tmp.extend(path[1:])
                            path = tmp
                        elif path[0] == '..':
                            # ../sisteritem
                            path = page.path[1:] + path[1:]
                    else:
                        raise ValueError(
                            "can't handle xinclude for schemes other than wiki or wiki.local"
                        )

                    link.path = path

                    if flaskg.user.may.read(unicode(path)):
                        page = Item.create(unicode(path))
                        pages = ((page, link), )
                    else:
                        # ACLs prevent user from viewing a transclusion - show message
                        message = moin_page.p(children=(_(
                            'Access Denied, transcluded content suppressed.')))
                        attrib = {html.class_: 'warning'}
                        div = ET.Element(moin_page.div,
                                         attrib,
                                         children=(message, ))
                        container = ET.Element(moin_page.body,
                                               children=(div, ))
                        return [
                            container, 0
                        ]  # replace transclusion with container's child

                elif xp_include_pages:
                    # we have regex of pages to include:  <<Include(^qqq)>>
                    query = And([
                        Term(WIKINAME, app.cfg.interwikiname),
                        Regex(NAME_EXACT, xp_include_pages)
                    ])
                    reverse = xp_include_sort == 'descending'
                    results = flaskg.storage.search(query,
                                                    sortedby=NAME_EXACT,
                                                    reverse=reverse,
                                                    limit=None)
                    pagelist = [result.name for result in results]
                    if xp_include_skipitems is not None:
                        pagelist = pagelist[xp_include_skipitems:]
                    if xp_include_items is not None:
                        pagelist = pagelist[xp_include_items + 1:]
                    pages = ((Item.create(p),
                              Iri(scheme='wiki', authority='', path='/' + p))
                             for p in pagelist)
                    if not pagelist:
                        msg = _(
                            'Error: no items found matching "<<Include({0})>>"'
                        ).format(xp_include_pages)
                        attrib = {html.class_: 'moin-error'}
                        strong = ET.Element(moin_page.strong, attrib, (msg, ))
                        included_elements.append(strong)

                for page, p_href in pages:
                    if p_href.path[0] != '/':
                        p_href.path = IriPath('/' + '/'.join(p_href.path))
                    if p_href in self.stack:
                        # we have a transclusion loop, create an error message showing list of pages forming loop
                        loop = self.stack[self.stack.index(p_href):]
                        loop = [
                            u'{0}'.format(ref.path[1:])
                            for ref in loop if ref is not None
                        ] + [page.name]
                        msg = u'Error: Transclusion loop via: ' + u', '.join(
                            loop)
                        attrib = {html.class_: 'moin-error'}
                        strong = ET.Element(moin_page.strong, attrib, (msg, ))
                        included_elements.append(strong)
                        continue

                    if xp_include_heading is not None:
                        attrib = {xlink.href: p_href}
                        children = (xp_include_heading or page.name, )
                        elem_a = ET.Element(moin_page.a,
                                            attrib,
                                            children=children)
                        attrib = {
                            moin_page.outline_level: xp_include_level or '1'
                        }
                        elem_h = ET.Element(moin_page.h,
                                            attrib,
                                            children=(elem_a, ))
                        included_elements.append(elem_h)

                    page_doc = page.content.internal_representation(
                        attributes=Arguments(keyword=elem.attrib))
                    if isinstance(page.rev.data, file):
                        page.rev.data.close()

                    self.recurse(page_doc, page_href)

                    # The href needs to be an absolute URI, without the prefix "wiki://"
                    page_doc = mark_item_as_transclusion(page_doc, p_href.path)
                    included_elements.append(page_doc)

                if len(included_elements) > 1:
                    # use a div as container
                    result = ET.Element(moin_page.div)
                    result.extend(included_elements)
                elif included_elements:
                    result = included_elements[0]
                else:
                    result = None
                #  end of processing for transclusion; the "result" will get inserted into the DOM below
                return result

            # 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):

                    ret = self.recurse(child, page_href)

                    if ret:
                        # Either child or a descendant of child is a transclusion.
                        # See top of this script for notes on why these DOM adjustments are required.
                        if isinstance(ret, ET.Node
                                      ) and elem.tag.name in NO_BLOCK_CHILDREN:
                            body = ret[0]
                            if len(body) == 0:
                                # the transcluded item is empty, insert an empty span into DOM
                                attrib = Attributes(ret).convert()
                                elem[i] = ET.Element(moin_page.span,
                                                     attrib=attrib)
                            elif (isinstance(body[0], ET.Node)
                                  and (len(body) > 1 or body[0].tag.name
                                       not in ('p', 'object', 'a'))):
                                # Complex case: "some text {{BlockItem}} more text" or "\n{{BlockItem}}\n" where
                                # the BlockItem body contains multiple p's, a table, preformatted text, etc.
                                # These block elements cannot be made a child of the current elem, so we create
                                # a container to replace elem.
                                # Create nodes to hold any siblings before and after current child (elem[i])
                                before = copy.deepcopy(elem)
                                after = copy.deepcopy(elem)
                                before[:] = elem[0:i]
                                after[:] = elem[i + 1:]
                                if len(before):
                                    # there are siblings before transclude, save them in container
                                    container.append(before)
                                new_trans_ptr = len(container)
                                # get attributes from page node;
                                # we expect {class: "moin-transclusion"; data-href: "http://some.org/somepage"}
                                attrib = Attributes(ret).convert()
                                # current elem will likely be replaced by container so we need to copy data-lineno attr
                                if html.data_lineno in elem.attrib:
                                    attrib[html.data_lineno] = elem.attrib[
                                        html.data_lineno]
                                # make new div node to hold transclusion, copy children, and save in container
                                div = ET.Element(moin_page.div,
                                                 attrib=attrib,
                                                 children=body[:])
                                container.append(
                                    div)  # new_trans_ptr is index to this
                                if len(after):
                                    container.append(after)
                                if elem.tag.name == 'a':
                                    # invalid input [[MyPage|{{BlockItem}}]],
                                    # best option is to retain A-tag and fail html validation
                                    # TODO: error may not be obvious to user - add error message
                                    elem[i] = div
                                else:
                                    # move up 1 level in recursion where elem becomes the child and
                                    # is usually replaced by container
                                    return [container, new_trans_ptr]
                            else:
                                # default action for inline transclusions or odd things like circular transclusion error messages
                                classes = child.attrib.get(html.class_,
                                                           '').split()
                                classes += ret.attrib.get(html.class_,
                                                          '').split()
                                ret.attrib[html.class_] = ' '.join(classes)
                                elem[i] = ret
                        elif isinstance(ret, types.ListType):
                            # a container has been returned.
                            # Note: there are multiple places where a container may be constructed
                            ret_container, trans_ptr = ret
                            # trans_ptr points to the transclusion within ret_container.
                            # Here the transclusion will always contain a block level element
                            if elem.tag.name in NO_BLOCK_CHILDREN:
                                # Complex case, transclusion effects grand-parent, great-grand-parent, e.g.:
                                # "/* comment {{BlockItem}} */" or  "text ''italic {{BlockItem}} italic'' text"
                                # elem is an inline element, build a bigger container to replace elem's parent,
                                before = copy.deepcopy(elem)
                                after = copy.deepcopy(elem)
                                before[:] = elem[0:i] + ret_container[
                                    0:trans_ptr]
                                after[:] = ret_container[trans_ptr +
                                                         1:] + elem[i + 1:]
                                if len(before):
                                    container.append(before)
                                new_trans_ptr = len(container)
                                # child may have classes like "comment" that must be added to transcluded element
                                classes = child.attrib.get(
                                    moin_page.class_, '').split()
                                # must use moin_page.class_ above, but use html.class below per html_out.py code
                                classes += ret_container[trans_ptr].attrib.get(
                                    html.class_, '').split()
                                ret_container[trans_ptr].attrib[
                                    html.class_] = ' '.join(classes)
                                container.append(ret_container[trans_ptr]
                                                 )  # the transclusion
                                if len(after):
                                    container.append(after)
                                return [container, new_trans_ptr]
                            else:
                                # elem is a block element
                                for grandchild in child:
                                    if isinstance(
                                            grandchild, ET.Node
                                    ) and grandchild.tag.name == u'include':
                                        # the include may have classes that must be added to transcluded element
                                        classes = grandchild.attrib.get(
                                            html.class_, '').split()
                                        classes += ret_container[
                                            trans_ptr].attrib.get(
                                                html.class_, '').split()
                                        ret_container[trans_ptr].attrib[
                                            html.class_] = ' '.join(classes)
                                # replace child element with the container generated in lower recursion
                                elem[i:i +
                                     1] = ret_container  # elem[i] is the child
                        else:
                            # default action for any ret not fitting special cases above,
                            # e.g. tranclusion is within a table cell
                            elem[i] = ret
                # we are finished with this child, advance to next sibling
                i += 1

        finally:
            self.stack.pop()
Ejemplo n.º 30
0
def test_wiki(app, conv, input_, output):
    assert 'MoinMoin' in app.cfg.interwiki_map

    elem = ET.Element(None)
    conv.handle_wiki_links(elem, Iri(input_))
    assert elem.get(xlink.href) == output