[RichString] Add markdown support
authorChristophe de Vienne <christophe@unlish.com>
Wed, 30 Apr 2014 21:04:14 +0200
changeset 10012 8c2c6fdd8d56
parent 10011 340d4ef55b6f
child 10013 b68088082280
[RichString] Add markdown support Supporting markdown requires the 'Markdown' python packages, and since it widely available on the target platforms adding it as a strong requirements will not be a big constraint. Closes #3814302
__pkginfo__.py
cubicweb.spec
cwconfig.py
debian/control
ext/markdown.py
mttransforms.py
test/unittest_entity.py
uilib.py
web/formfields.py
web/test/unittest_form.py
--- a/__pkginfo__.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/__pkginfo__.py	Wed Apr 30 21:04:14 2014 +0200
@@ -51,6 +51,7 @@
     # server dependencies
     'logilab-database': '>= 1.12.1',
     'passlib': '',
+    'Markdown': ''
     }
 
 __recommends__ = {
--- a/cubicweb.spec	Thu Oct 23 14:57:02 2014 +0200
+++ b/cubicweb.spec	Wed Apr 30 21:04:14 2014 +0200
@@ -28,6 +28,7 @@
 Requires:       %{python}-passlib
 Requires:       %{python}-lxml
 Requires:       %{python}-twisted-web
+Requires:       %{python}-markdown
 # the schema view uses `dot'; at least on el5, png output requires graphviz-gd
 Requires:       graphviz-gd
 Requires:       gettext
--- a/cwconfig.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/cwconfig.py	Wed Apr 30 21:04:14 2014 +0200
@@ -278,7 +278,7 @@
       }),
     ('default-text-format',
      {'type' : 'choice',
-      'choices': ('text/plain', 'text/rest', 'text/html'),
+      'choices': ('text/plain', 'text/rest', 'text/html', 'text/markdown'),
       'default': 'text/html', # use fckeditor in the web ui
       'help': _('default text format for rich text fields.'),
       'group': 'ui',
--- a/debian/control	Thu Oct 23 14:57:02 2014 +0200
+++ b/debian/control	Wed Apr 30 21:04:14 2014 +0200
@@ -124,6 +124,7 @@
  ${misc:Depends},
  ${python:Depends},
  cubicweb-common (= ${source:Version}),
+ python-markdown,
 Recommends:
  python-docutils (>= 0.6),
  python-vobject,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ext/markdown.py	Wed Apr 30 21:04:14 2014 +0200
@@ -0,0 +1,27 @@
+from __future__ import absolute_import
+import markdown
+
+import logging
+
+log = logging.getLogger(__name__)
+
+
+def markdown_publish(context, data):
+    """publish a string formatted as MarkDown Text to HTML
+
+    :type context: a cubicweb application object
+
+    :type data: str
+    :param data: some MarkDown text
+
+    :rtype: unicode
+    :return:
+      the data formatted as HTML or the original data if an error occurred
+    """
+    md = markdown.Markdown()
+    try:
+        return md.convert(data)
+    except:
+        import traceback; traceback.print_exc()
+        log.exception("Error while converting Markdown to HTML")
+        return data
--- a/mttransforms.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/mttransforms.py	Wed Apr 30 21:04:14 2014 +0200
@@ -28,7 +28,7 @@
                                  register_pygments_transforms)
 
 from cubicweb.utils import UStringIO
-from cubicweb.uilib import rest_publish, html_publish
+from cubicweb.uilib import rest_publish, markdown_publish, html_publish
 
 HTML_MIMETYPES = ('text/html', 'text/xhtml', 'application/xhtml+xml')
 
@@ -40,6 +40,12 @@
     def _convert(self, trdata):
         return rest_publish(trdata.appobject, trdata.decode())
 
+class markdown_to_html(Transform):
+    inputs = ('text/markdown', 'text/x-markdown')
+    output = 'text/html'
+    def _convert(self, trdata):
+        return markdown_publish(trdata.appobject, trdata.decode())
+
 class html_to_html(Transform):
     inputs = HTML_MIMETYPES
     output = 'text/html'
@@ -53,6 +59,7 @@
 
 ENGINE = TransformEngine()
 ENGINE.add_transform(rest_to_html())
+ENGINE.add_transform(markdown_to_html())
 ENGINE.add_transform(html_to_html())
 
 try:
--- a/test/unittest_entity.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/test/unittest_entity.py	Wed Apr 30 21:04:14 2014 +0200
@@ -587,6 +587,16 @@
             # should be default groups but owners, i.e. managers, users, guests
             self.assertEqual(len(unrelated), 3)
 
+    def test_markdown_printable_value_string(self):
+        with self.admin_access.web_request() as req:
+            e = req.create_entity('Card', title=u'rest markdown',
+                                  content=u'This is [an example](http://example.com/ "Title") inline link`',
+                                  content_format=u'text/markdown')
+            self.assertEqual(
+                u'<p>This is <a href="http://example.com/" '
+                u'title="Title">an example</a> inline link`</p>',
+                e.printable_value('content'))
+
     def test_printable_value_string(self):
         with self.admin_access.web_request() as req:
             e = req.create_entity('Card', title=u'rest test',
--- a/uilib.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/uilib.py	Wed Apr 30 21:04:14 2014 +0200
@@ -163,6 +163,8 @@
 
 # text publishing #############################################################
 
+from cubicweb.ext.markdown import markdown_publish # pylint: disable=W0611
+
 try:
     from cubicweb.ext.rest import rest_publish # pylint: disable=W0611
 except ImportError:
@@ -170,6 +172,7 @@
         """default behaviour if docutils was not found"""
         return xml_escape(data)
 
+
 TAG_PROG = re.compile(r'</?.*?>', re.U)
 def remove_html_tags(text):
     """Removes HTML tags from text
--- a/web/formfields.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/web/formfields.py	Wed Apr 30 21:04:14 2014 +0200
@@ -779,11 +779,13 @@
     actually contains some text.
 
     If the stream format is one of text/plain, text/html, text/rest,
+    text/markdown
     then a :class:`~cubicweb.web.formwidgets.TextArea` will be additionaly
     displayed, allowing to directly the file's content when desired, instead
     of choosing a file from user's file system.
     """
-    editable_formats = ('text/plain', 'text/html', 'text/rest')
+    editable_formats = (
+        'text/plain', 'text/html', 'text/rest', 'text/markdown')
 
     def render(self, form, renderer):
         wdgs = [super(EditableFileField, self).render(form, renderer)]
--- a/web/test/unittest_form.py	Thu Oct 23 14:57:02 2014 +0200
+++ b/web/test/unittest_form.py	Wed Apr 30 21:04:14 2014 +0200
@@ -174,6 +174,7 @@
             self._test_richtextfield(req, '''<select id="description_format-subject:%(eid)s" name="description_format-subject:%(eid)s" size="1" style="display: block" tabindex="1">
 <option value="text/cubicweb-page-template">text/cubicweb-page-template</option>
 <option selected="selected" value="text/html">text/html</option>
+<option value="text/markdown">text/markdown</option>
 <option value="text/plain">text/plain</option>
 <option value="text/rest">text/rest</option>
 </select><textarea cols="80" id="description-subject:%(eid)s" name="description-subject:%(eid)s" onkeyup="autogrow(this)" rows="2" tabindex="2"></textarea>''')