view MoinMoin/converter/smiley.py @ 26:4cd8edde9e94

automatically transform module docstrings, moving legal stuff to comments a script was used to extract all copyright and license strings from the docstring and put them into comment lines above the docstring. this was done to not have the legal stuff in autogenerated docs repeated over and over again.
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sun, 27 Feb 2011 18:11:54 +0100
parents 335d7489a074
children 57078169052b
line wrap: on
line source
# Copyright: 2010 MoinMoin:ValentinJaniaut
# Copyright: 2010 MoinMoin:ThomasWaldmann
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
MoinMoin - Smiley converter

Replace all the text corresponding to a smiley, by the corresponding
element for the DOM Tree.
"""


import re

from emeraldtree import ElementTree as ET

from MoinMoin.util.tree import moin_page

class Converter(object):
    """
    Replace each smiley by the corresponding element in the DOM Tree
    """
    smileys = {
        # markup: smiley name
        'X-(': 'angry',
        ':D': 'biggrin',
        '<:(': 'frown',
        ':o': 'redface',
        ':(': 'sad',
        ':)': 'smile',
        'B)': 'smile2',
        ':))': 'smile3',
        ';)': 'smile4',
        '/!\\': 'alert',
        '<!>': 'attention',
        '(!)': 'idea',
        ':-?': 'tongue',
        ':\\': 'ohwell',
        '>:>': 'devil',
        '|)': 'tired',
        ':-(': 'sad',
        ':-)': 'smile',
        'B-)': 'smile2',
        ':-))': 'smile3',
        ';-)': 'smile4',
        '|-)': 'tired',
        '(./)': 'checkmark',
        '{OK}': 'thumbs-up',
        '{X}': 'icon-error',
        '{i}': 'icon-info',
        '{1}': 'prio1',
        '{2}': 'prio2',
        '{3}': 'prio3',
        '{*}': 'star_on',
        '{o}': 'star_off',
    }

    smiley_rule = ur"""
    (^|(?<=\s))  # we require either beginning of line or some space before a smiley
    (%(smiley)s)  # one of the smileys
    ($|(?=\s))  # we require either ending of line or some space after a smiley
""" % {'smiley': u'|'.join([re.escape(s) for s in smileys])}

    smiley_re = re.compile(smiley_rule, re.UNICODE|re.VERBOSE)

    # We do not process any smiley conversion within these elements.
    tags_to_ignore = set(['code', 'blockcode', ])

    @classmethod
    def _factory(cls, input, output, icon=None, **kw):
        if icon == 'smiley':
            return cls()

    def __call__(self, content):
        self.do_children(content)
        return content

    def do_children(self, element):
        # We store the new children of the element in this list
        new_children = []

        # If we do not want smiley conversion for the children of
        # a specific element, we do not process the conversion.
        if element.tag.name in self.tags_to_ignore:
            return element
        for child in element:
            if isinstance(child, ET.Element):
                # We have an ET.Element, so we continue the recursion
                children = self.do_children(child)
                if children is None:
                    children = ()
                elif not isinstance(children, (list, tuple)):
                    children = (children, )
                new_children.extend(children)
            else:
                # Otherwise, we have a text node, so we convert the smileys
                new_children.extend(self.do_smiley(child))

        if new_children:
            # We remove all the old children of the element
            element.remove_all()
            # And we replace it by the new one
            element.extend(new_children)
        return element

    def do_smiley(self, element):
        """
        From a text, return a list with smileys replaced
        by the appropriate elements, and the former text for the
        other elements of the list.
        """
        # We split our string into different items arround
        # the matched smiley.
        splitted_string = re.split(self.smiley_re, element)
        # And then for each item of the list,
        # if it is a smiley, we replace it by the appropriate element
        return [self.replace_smiley(item) for item in splitted_string]

    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

from . import default_registry
from MoinMoin.util.mime import type_moin_document
default_registry.register(Converter._factory, type_moin_document, type_moin_document)