Commits

Thomas Waldmann committed 1a3f0d0 Merge

merged

  • Participants
  • Parent commits 8f93193, 270cef5

Comments (0)

Files changed (9)

MoinMoin/converter/docbook_in.py

 logging = log.getLogger(__name__)
 
 from MoinMoin.util.tree import moin_page, xlink, docbook, xml, html
+from MoinMoin.converter.html_out import mark_item_as_transclusion
 
 from ._wiki_macro import ConverterMacro
 from ._util import allowed_uri_scheme, decode_data, normalize_split_text
     # admonitions in this list, into the admonition element of the DOM Tree.
     admonition_tags = set(['attention', 'caution', 'danger', 'error', 'hint', 'important', 'note', 'tip', 'warning'])
 
-    # DocBook can handle three kind of media: audio, image, video. Here
-    # is an helper dictionary to process such of element.
+    # DocBook can handle three kinds of media: audio, image, video.
+    # TODO: a media format attribute is optional, e.g.: <imagedata format="jpeg" fileref="jpeg.jpg"/>
+    #     XXX: quality of supported formats list is suspect, see below
     media_tags = {
+        # <tagname>: (<formats list>, <child tagname>, <mime type>)
         'audioobject': (
-            ['wav', 'mp3', 'ogg'],
+            ['x-wav', 'mpeg', 'ogg', 'webm'],  # XXX: none of these are in http://docbook.org/tdg/en/html/audiodata.html
             'audiodata',
             'audio/',
         ),
         'imageobject': (
-            ['gif', 'png', 'jpg', 'png'],
+            ['gif', 'png', 'jpeg', 'jpg', 'svg'],  # selected from http://docbook.org/tdg/en/html/imagedata.html
             'imagedata',
             'image/',
         ),
         'videoobject': (
-            ['ogg', 'avi', 'mp4'],
+            ['ogg', 'webm', 'mp4'],  # XXX: none of these are in http://docbook.org/tdg/en/html/videodata.html
             'videodata',
             'video/',
         )
         if element.tag.name in self.simple_tags:
             return self.visit_simple_tag(element, depth)
 
-        # We have a media element
-        # if element.tag.name in self.media_tags:
-        #    return self.visit_data_object(element, depth)
-
         # We should ignore this element
         if element.tag.name in self.ignored_tags:
             logging.warning("Ignored tag:{0}".format(element.tag.name))
 
     def visit_data_object(self, element, depth):
         """
-        We need to determine which object we can display.
-        If we are not able to display an object,
-        we will try to display a text.
-        TODO: See for a preference list between image, data, audio
+        Process a mediaobject element. Possible child tags are videoobject, audioobject, imageobject,
+        caption, objectinfo, and textobject.
+
+        <mediaobject><videoobject><videodata fileref="video.mp4"/></videoobject></mediaobject>
         """
-        prefered_format, data_tag, mimetype = ('', '', '')
         object_data = []
         text_object = []
         caption = []
         object_element = ''
         for child in element:
             if isinstance(child, ET.Element):
-                if child.tag.name in self.media_tags:
-                    # XXX: Check the spec to be sure that object tag have only one child.
-                    # TODO: Better way to do it
-                    prefered_format, data_tag, mimetype = self.media_tags[child.tag.name]
+                if child.tag.name in self.media_tags:  # audioobject, imageobject, videoobject
+                    preferred_format, data_tag, mimetype = self.media_tags[child.tag.name]
                     object_element = child
                     for grand_child in child:
-                        if isinstance(grand_child, ET.Element):
+                        if isinstance(grand_child, ET.Element) and grand_child.tag.name == data_tag:
+                            # capture audiodata, imagedata, or videodata tags
                             object_data.append(grand_child)
                 if child.tag.name == 'caption':
                     caption = self.do_children(child, depth + 1)[0]
                 if child.tag.name == 'textobject':
                     text_object = child
+                # we ignore objectinfo tags
         return self.visit_data_element(object_element, depth, object_data, text_object, caption)
 
     def visit_data_element(self, element, depth, object_data, text_object, caption):
         with the content of text_object.
         """
         attrib = {}
-        prefered_format, data_tag, mimetype = self.media_tags[element.tag.name]
+        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(child, depth + 1)[0]
-                return self.new(moin_page.p, attrib={},
-                                children=children)
+                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
-        object_to_show = None
         for obj in object_data:
-            format = obj.get('format')
+            format = obj.get('format')  # format is optional: <imagedata format="jpeg" fileref="jpeg.jpg"/>
             if format:
                 format = format.lower()
-                if format in prefered_format:
+                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
+                # 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)
+        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[xlink.href] = href
+        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
-        return ET.Element(moin_page.object, attrib=attrib)
+        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
 
     def visit_docbook_admonition(self, element, depth):
         """
         <tag.name> --> <div html:class="db-tag.name">
         """
         attrib = {}
-        key = html('class')
+        key = html.class_
         attrib[key] = ''.join(['db-', element.tag.name])
         return self.new_copy(moin_page.div, element,
                              depth, attrib=attrib)
         However, it is still semantic, so we call it emphasis and strong.
         """
         for key, value in element.attrib.iteritems():
-            if key.name == 'role' and value == 'strong':
+            if key.name == 'role' and value == 'bold':
                 return self.new_copy(moin_page.strong, element,
                                      depth, attrib={})
         return self.new_copy(moin_page.emphasis, element,
         <informalequation> --> <div html:class="equation">
         """
         attrib = {}
-        attrib[html('class')] = 'db-equation'
+        attrib[html.class_] = 'db-equation'
         return self.new_copy(moin_page('div'), element,
                              depth, attrib=attrib)
 
         <informalexample> --> <div html:class="example">
         """
         attrib = {}
-        attrib[html('class')] = 'db-example'
+        attrib[html.class_] = 'db-example'
         return self.new_copy(moin_page('div'), element,
                              depth, attrib=attrib)
 
         <informalfigure> --> <div html:class="figure">
         """
         attrib = {}
-        attrib[html('class')] = 'db-figure'
+        attrib[html.class_] = 'db-figure'
         return self.new_copy(moin_page('div'), element,
                              depth, attrib=attrib)
 
         For some specific tags (defined in inline_tags)
         We just return <span element="tag.name">
         """
-        key = html('class')
+        key = html.class_
         attrib = {}
         attrib[key] = ''.join(['db-', element.tag.name])
         return self.new_copy(moin_page.span, element,
 
     def visit_docbook_inlinemediaobject(self, element, depth):
         data_element = self.visit_data_object(element, depth)
-        attrib = {html('class'): 'db-inlinemediaobject'}
+        attrib = {html.class_: 'db-inlinemediaobject'}
         return self.new(moin_page.span, attrib=attrib,
                         children=[data_element])
 
         """
         <literallayout> --> <blockcode html:class="db-literallayout">
         """
-        attrib = {html('class'): 'db-literallayout'}
+        attrib = {html.class_: 'db-literallayout'}
         return self.new_copy(moin_page.blockcode, element,
                              depth, attrib=attrib)
 
     def visit_docbook_mediaobject(self, element, depth):
         data_element = self.visit_data_object(element, depth)
-        attrib = {html('class'): 'db-mediaobject'}
+        attrib = {html.class_: 'db-mediaobject'}
         return self.new(moin_page.div, attrib=attrib,
                         children=[data_element])
 
         attrib = {}
         children = []
         if class_attribute:
-            attrib[html('class')] = ''.join(['db-tag-', class_attribute])
+            attrib[html.class_] = ''.join(['db-tag-', class_attribute])
         else:
-            attrib[html('class')] = 'db-tag'
+            attrib[html.class_] = 'db-tag'
         if namespace_attribute:
             namespace_str = ''.join(['{', namespace_attribute, '}'])
             children.append(namespace_str)
 
     def visit_docbook_trademark(self, element, depth):
         """
-        Depending of the trademark class, a specific entities is added
-        at the end of the string.
-        <trademark> --> <span element="trademark">
+        Depending of the trademark class, a specific entities is added to the string.
+
+        Docbook supports 4 types of trademark: copyright, registered, trade (mark), and service (mark).
+        <trademark> --> <span class="db-trademark">
         """
-        trademark_entities = {'copyright': '&copy;',
-                              'registred': '&reg;',
-                              'trade': '&trade;',
+        trademark_entities = {'copyright': u'\u00a9 ',
+                              'registered': u'\u00ae',
+                              'trade': u'\u2122',
         }
         trademark_class = element.get('class')
         children = self.do_children(element, depth)
         if trademark_class in trademark_entities:
-            children.append(trademark_entities[trademark_class])
+            if trademark_class == 'copyright':
+                children.insert(0, trademark_entities[trademark_class])
+            else:
+                children.append(trademark_entities[trademark_class])
         elif trademark_class == 'service':
             sup_attrib = {moin_page('baseline-shift'): 'super'}
             service_mark = self.new(moin_page.span, attrib=sup_attrib,
                                     children=['SM'])
             children.append(service_mark)
-        attrib = {html('class'): 'db-trademark'}
+        attrib = {html.class_: 'db-trademark'}
         return self.new(moin_page.span, attrib=attrib, children=children)
 
     def visit_docbook_td(self, element, depth):

MoinMoin/converter/html_out.py

         """
         href = elem.get(xlink.href, None)
         attrib = {}
-        whitelist = ['width', 'height', 'alt', 'class']
+        whitelist = ['width', 'height', 'alt', 'class', 'data-href']
         for key in elem.attrib:
             if key.name in whitelist:
                 attrib[key] = elem.attrib[key]
             else:
                 # is an object
                 new_elem = html.object(attrib=attrib)
-                if new_elem.attrib.get(html.alt):
-                    new_elem.append(new_elem.attrib.get(html.alt))
-                    del new_elem.attrib[html.alt]
-                else:
-                    new_elem.append(alt)
+            # alt attr is invalid within object, audio, and video tags , append alt text as a child
+            if new_elem.attrib.get(html.alt):
+                new_elem.append(new_elem.attrib.get(html.alt))
+                del new_elem.attrib[html.alt]
+            else:
+                new_elem.append(alt)
 
         if obj_type == "object" and getattr(href, 'scheme', None):
             # items similar to {{http://moinmo.in}} are marked here, other objects are marked in include.py

MoinMoin/static/js/common.js

 MoinMoin.prototype.initTransclusionOverlays = function () {
     "use strict";
     var elem, overlayUL, overlayLR, wrapper, wrappers, transclusions, classes,
-        rightArrow = '\u2192';
+        rightArrow = '\u2192',
+        mediaTags = ['OBJECT', 'IMG', 'AUDIO', 'VIDEO' ]
     // get list of elements to be wrapped; must work in reverse order in case there are nested transclusions
     transclusions = $($('.moin-transclusion').get().reverse());
     transclusions.each(function (index) {
                 elem = $(elem).parent()[0];
             }
             // copy user specified classes from img/object tag to wrapper
-            if (elem.tagName === 'OBJECT') {
+            if ($.inArray(elem.tagName, mediaTags) > -1) {
                 // do not copy classes starting with moin-
                 classes = $(elem).attr('class');
                 classes = classes.split(" ").filter(function(c) {
                 });
                 $(wrapper).addClass(classes.join(' '));
             } else {
+                // TODO: try to eliminate above else by changing include.py to
+                //    do: <img class="moin-transclusion"...
+                //    not: <span class="moin-transclusion"... <img...
                 // copy all classes from img tags
                 $(wrapper).addClass($(elem).find(">:first-child").attr('class'));
             }

MoinMoin/themes/basic/static/css/basic.css

   position: relative;
   display: inline-block;
 }
-.moin-item-wrapper > a:hover {
-  color: link_color;
-  text-decoration: none;
-}
 div.moin-item-wrapper {
   width: 100%;
 }
 .moin-item-overlay-ul:hover,
 .moin-item-overlay-lr:hover {
   opacity: .8;
-  background-color: #555555;
+  background-color: #e1edf7;
   color: #428bca;
+  text-decoration: none;
 }
 .comment {
   color: #333333;

MoinMoin/themes/basic/static/custom-less/basic.less

 .moin-item-wrapper {
     position: relative;
     display: inline-block;
-    > a:hover {
-      color: link_color;
-      text-decoration: none;
-    }
 }
 
 div.moin-item-wrapper {
 .moin-item-overlay-ul:hover,
 .moin-item-overlay-lr:hover {
     opacity: .8;
-    background-color: @gray;
+    background-color: lighten(@link-color, 40%);
     color: @link-color;
+    text-decoration: none;
 }
 
 .comment {

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

 .moin-transclusion{max-width:100%}
 .moin-item-wrapper{position:relative;display:inline-block}
 div.moin-item-wrapper{width:100%}
-.moin-item-wrapper > a:hover{color:#1e90ff;text-decoration:none}
 .moin-item-overlay-ul,.moin-item-overlay-lr{display:none;position:absolute;font-size:1.2em;font-weight:bold;margin:0;opacity:.5;padding:1px;border-color:#1e90ff;border-style:double}
 .moin-item-overlay-ul{top:-4px;left:-4px;border-width:3px 0 0 3px}
 .moin-item-overlay-lr{bottom:-4px;right:-4px;border-width:0 3px 3px 0}
-.moin-item-overlay-ul:hover,.moin-item-overlay-lr:hover{opacity:.8;background-color:#d6d5d0;color:#1e90ff}
+.moin-item-overlay-ul:hover,.moin-item-overlay-lr:hover{opacity:.8;background-color:#d6d5d0;color:#1e90ff;text-decoration:none}
 .moin-table-of-contents{border:1px solid #ccc;background:#f4f4f4;font-size:.8em;margin:.5em 0 .5em .5em;padding:.5em;text-indent:-1em;max-width:35%;text-align:left;float:right;clear:both;box-shadow:3px 3px 6px #9d9d9b;border-radius:15px}
 .moin-table-of-contents ol{margin:0;padding:0 0 0 .92em}
 .moin-table-of-contents li{margin:.12em 0 0 0;padding:0;list-style:none}

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

 div.moin-item-wrapper
     width 100% // force bottom border of transcluded headings to extend across entire page
 
-.moin-item-wrapper > a:hover
-    color link_color
-    text-decoration none
-
 .moin-item-overlay-ul,
 .moin-item-overlay-lr
     display none
     opacity .8
     background-color base_color
     color link_color
+    text-decoration none
 
 // table of content
 .moin-table-of-contents

MoinMoin/themes/modernized/static/css/common.css

 #moin-creditlogos li{display:inline-block;*display:inline;zoom:1;margin:10px 0 10px 10px}
 .moin-item-wrapper{position:relative;display:inline-block}
 div.moin-item-wrapper{width:100%}
-.moin-item-wrapper > a:hover{color:#1f9ae0;text-decoration:none}
 a.moin-item-overlay-ul,a.moin-item-overlay-lr{display:none;position:absolute;color:transparent;background-color:transparent;font-size:120%;font-weight:bold;margin:0;opacity:.5;padding:1px;border-color:#00f;border-style:double}
 .moin-item-overlay-ul{top:-4px;left:-4px;border-width:3px 0 0 3px}
 .moin-item-overlay-lr{bottom:-4px;right:-4px;border-width:0 3px 3px 0}
-.moin-item-overlay-ul:hover,.moin-item-overlay-lr:hover{opacity:.8;background-color:#eef1f6;color:#1f9ae0}
+.moin-item-overlay-ul:hover,.moin-item-overlay-lr:hover{opacity:.8;background-color:#eef1f6;color:#1f9ae0;text-decoration:none}
 div.moin-item-wrapper,div.moin-item-wrapper > div,div.moin-item-wrapper > div > p:first-child,div.moin-item-wrapper > div > p:last-child{margin:0}
 div.moin-item-wrapper > div > p:first-child ~ p:last-child{margin-top:1em}
 a.moin-permalink{display:none;cursor:pointer;margin-left:.1em;color:#939393;}

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

 div.moin-item-wrapper
     width 100% // force bottom border of transcluded headings to extend across entire page
 
-.moin-item-wrapper > a:hover
-    color hover_color
-    text-decoration none
-
 a.moin-item-overlay-ul,
 a.moin-item-overlay-lr
     display none
     opacity .8
     background-color table_bg_color
     color hover_color
+    text-decoration none
 
 div.moin-item-wrapper,
 div.moin-item-wrapper > div,