[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
--- 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>''')