Browse Source

short image md from 0.5

Rafał Pitoń 10 years ago
parent
commit
c3c8f7719b

+ 0 - 0
misago/markup/md/__init__.py


+ 26 - 0
misago/markup/md/shortimgs.py

@@ -0,0 +1,26 @@
+import re
+
+import markdown
+from markdown.inlinepatterns import LinkPattern
+from markdown.util import etree
+
+
+IMAGES_RE =  r'\!(\s?)\((<.*?>|([^\)]*))\)'
+
+
+class ShortImagesExtension(markdown.Extension):
+    def extendMarkdown(self, md):
+        md.registerExtension(self)
+        md.inlinePatterns.add('misago_short_images',
+                              ShortImagePattern(IMAGES_RE, md),
+                              '_end')
+
+
+class ShortImagePattern(LinkPattern):
+    def handleMatch(self, m):
+        img_src = m.groups()[2].strip()
+        if img_src:
+            img = etree.Element("img")
+            img.set('src', img_src)
+            img.set('alt', img_src)
+            return img

+ 52 - 18
misago/markup/parser.py

@@ -4,6 +4,7 @@ from htmlmin.minify import html_minify
 import markdown
 import markdown
 
 
 from misago.markup.bbcode import inline, blocks
 from misago.markup.bbcode import inline, blocks
+from misago.markup.md.shortimgs import ShortImagesExtension
 from misago.markup.pipeline import pipeline
 from misago.markup.pipeline import pipeline
 
 
 
 
@@ -44,30 +45,16 @@ def parse(text, request, poster, allow_mentions=True, allow_links=True,
     if allow_links:
     if allow_links:
         linkify_paragraphs(parsing_result)
         linkify_paragraphs(parsing_result)
 
 
-    if allow_links or allow_images:
-        make_absolute_links_relative(parsing_result, request)
-
     parsing_result = pipeline.process_result(parsing_result)
     parsing_result = pipeline.process_result(parsing_result)
 
 
+    if allow_links or allow_images:
+        clean_links(parsing_result, request)
+
     if minify:
     if minify:
         minify_result(parsing_result)
         minify_result(parsing_result)
     return parsing_result
     return parsing_result
 
 
 
 
-def linkify_paragraphs(result):
-    result['parsed_text'] = bleach.linkify(
-        result['parsed_text'], skip_pre=True, parse_email=True)
-
-
-def make_absolute_links_relative(result, request):
-    pass
-
-
-def minify_result(result):
-    # [25:-14] trims <html><head></head><body> and </body></html>
-    result['parsed_text'] = html_minify(result['parsed_text'])[25:-14]
-
-
 def md_factory(allow_links=True, allow_images=True, allow_blocks=True):
 def md_factory(allow_links=True, allow_images=True, allow_blocks=True):
     """
     """
     Create and configure markdown object
     Create and configure markdown object
@@ -97,7 +84,8 @@ def md_factory(allow_links=True, allow_images=True, allow_blocks=True):
 
 
     if allow_images:
     if allow_images:
         # Add [img]
         # Add [img]
-        pass
+        short_images_md = ShortImagesExtension()
+        short_images_md.extendMarkdown(md)
     else:
     else:
         # Remove images
         # Remove images
         del md.inlinePatterns['image_link']
         del md.inlinePatterns['image_link']
@@ -118,3 +106,49 @@ def md_factory(allow_links=True, allow_images=True, allow_blocks=True):
         del md.parser.blockprocessors['ulist']
         del md.parser.blockprocessors['ulist']
 
 
     return pipeline.extend_markdown(md)
     return pipeline.extend_markdown(md)
+
+
+def linkify_paragraphs(result):
+    result['parsed_text'] = bleach.linkify(
+        result['parsed_text'], skip_pre=True, parse_email=True)
+
+
+def clean_links(result, request):
+    site_address = '%s://%s' % (request.scheme, request.get_host())
+
+    soup = BeautifulSoup(result['parsed_text'])
+    for link in soup.find_all('a'):
+        if link['href'].lower().startswith(site_address):
+            result['inside_links'].append(link['href'])
+            if link['href'].lower() == site_address:
+                link['href'] = '/'
+            else:
+                link['href'] = link['href'].lower()[len(site_address):]
+        else:
+            result['outgoing_links'].append(link['href'])
+
+        if link.string.startswith('http://'):
+            link.string = link.string[7:].strip()
+        if link.string.startswith('https://'):
+            link.string = link.string[8:].strip()
+
+    for img in soup.find_all('img'):
+        result['images'].append(img['src'])
+        if img['src'].lower().startswith(site_address):
+            if img['src'].lower() == site_address:
+                img['src'] = '/'
+            else:
+                img['src'] = img['src'].lower()[len(site_address):]
+
+        if img['alt'].startswith('http://'):
+            img['alt'] = img['alt'][7:].strip()
+        if img['alt'].startswith('https://'):
+            img['alt'] = img['alt'][8:].strip()
+
+    if result['outgoing_links'] or result['inside_links'] or result['images']:
+        result['parsed_text'] = soup.prettify()
+
+
+def minify_result(result):
+    # [25:-14] trims <html><head></head><body> and </body></html>
+    result['parsed_text'] = html_minify(result['parsed_text'])[25:-14]

+ 102 - 2
misago/markup/tests/test_parser.py

@@ -4,14 +4,17 @@ from misago.markup.parser import parse
 
 
 
 
 class MockRequest(object):
 class MockRequest(object):
-    pass
+    scheme = 'http'
+
+    def get_host(self):
+        return 'test.com'
 
 
 
 
 class MockPoster(object):
 class MockPoster(object):
     pass
     pass
 
 
 
 
-class ParserTests(TestCase):
+class BBCodeTests(TestCase):
     def test_inline_text(self):
     def test_inline_text(self):
         """inline elements are correctly parsed"""
         """inline elements are correctly parsed"""
         test_text = """
         test_text = """
@@ -62,3 +65,100 @@ Dolor met.
 
 
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         result = parse(test_text, MockRequest(), MockPoster(), minify=False)
         self.assertEqual(expected_result, result['parsed_text'])
         self.assertEqual(expected_result, result['parsed_text'])
+
+
+class MinifyTests(TestCase):
+    def test_minified_text(self):
+        """parsed minifies text successfully"""
+        test_text = """
+Lorem ipsum.
+
+Lorem ipsum.
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum.</p><p>Lorem ipsum.</p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+
+class CleanLinksTests(TestCase):
+    def test_clean_current_link(self):
+        """clean_links step leaves http://test.com alone"""
+        test_text = """
+Lorem ipsum: http://test.com
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum: <a href="/" rel="nofollow">test.com</a></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_trim_current_path(self):
+        """clean_links step leaves http://test.com path"""
+        test_text = """
+Lorem ipsum: http://test.com/somewhere-something/
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum: <a href="/somewhere-something/" rel="nofollow">test.com/somewhere-something/</a></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_clean_outgoing_link_domain(self):
+        """clean_links step leaves outgoing domain link"""
+        test_text = """
+Lorem ipsum: http://somewhere.com
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum: <a href="http://somewhere.com" rel="nofollow">somewhere.com</a></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_trim_outgoing_path(self):
+        """clean_links step leaves outgoing link domain and path"""
+        test_text = """
+Lorem ipsum: http://somewhere.com/somewhere-something/
+""".strip()
+
+        expected_result = """
+<p>Lorem ipsum: <a href="http://somewhere.com/somewhere-something/" rel="nofollow">somewhere.com/somewhere-something/</a></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_clean_local_image_src(self):
+        """clean_links step cleans local image src"""
+        test_text = """
+!(http://test.com/image.jpg)
+""".strip()
+
+        expected_result = """
+<p><img alt="test.com/image.jpg" src="/image.jpg"/></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])
+
+    def test_clean_remote_image_src(self):
+        """clean_links step cleans remote image src"""
+        test_text = """
+!(http://somewhere.com/image.jpg)
+""".strip()
+
+        expected_result = """
+<p><img alt="somewhere.com/image.jpg" src="http://somewhere.com/image.jpg"/></p>
+""".strip()
+
+        result = parse(test_text, MockRequest(), MockPoster(), minify=True)
+        self.assertEqual(expected_result, result['parsed_text'])