diff --git a/app/static/css/global.css b/app/static/css/global.css
index 28d9824..e90351e 100644
--- a/app/static/css/global.css
+++ b/app/static/css/global.css
@@ -120,6 +120,24 @@ input[type="submit"]:focus {
.bg-warn:active {
background: var(--warn-active);
}
+img.align-left {
+ text-align: left;
+}
+img.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+img.align-right {
+ display: block;
+ margin-left: auto;
+}
+.float-left {
+ float: left;
+}
+.float-right {
+ float: right;
+}
.skip-to-content-link {
height: 30px;
left: 50%;
diff --git a/app/static/less/global.less b/app/static/less/global.less
index 7ab5dc2..65ccd18 100644
--- a/app/static/less/global.less
+++ b/app/static/less/global.less
@@ -117,6 +117,25 @@ section {
}
}
+img.align-left {
+ text-align: left;
+}
+img.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+img.align-right {
+ display: block;
+ margin-left: auto;
+}
+.float-left {
+ float: left;
+}
+.float-right {
+ float: right;
+}
+
.skip-to-content-link {
height: 30px;
diff --git a/app/templates/forum/edit_comment.html b/app/templates/forum/edit_comment.html
index 3e0a45c..d57ec1b 100644
--- a/app/templates/forum/edit_comment.html
+++ b/app/templates/forum/edit_comment.html
@@ -14,7 +14,7 @@
diff --git a/app/utils/markdown_extensions/media.py b/app/utils/markdown_extensions/media.py
index ae45066..8d0c170 100644
--- a/app/utils/markdown_extensions/media.py
+++ b/app/utils/markdown_extensions/media.py
@@ -15,6 +15,40 @@ class MediaExtension(Extension):
media_processor.md = md
md.inlinePatterns.register(media_processor, 'media_link', 155)
+class AttrDict:
+ def __init__(self, attrs):
+ self.attrs = attrs
+
+ def has(self, name):
+ return name in self.attrs
+
+ def getString(self, name):
+ for attr in self.attrs:
+ if attr.startswith(name + "="):
+ return attr[len(name)+1:]
+
+ def getInt(self, name):
+ try:
+ s = self.getString(name)
+ return int(s) if s is not None else None
+ except ValueError:
+ return None
+
+ def getSize(self, name):
+ s = self.getString(name)
+ if s is None:
+ return None, None
+ dims = s.split("x", 1)
+ try:
+ if len(dims) == 1:
+ return int(dims[0]), None
+ else:
+ w = int(dims[0]) if dims[0] else None
+ h = int(dims[1]) if dims[1] else None
+ return w, h
+ except ValueError:
+ return None, None
+
class AttributeLinkInlineProcessor(LinkInlineProcessor):
"""
A LinkInlineProcessor which additionally supports attributes after links,
@@ -30,7 +64,7 @@ class AttributeLinkInlineProcessor(LinkInlineProcessor):
current_attr_text = ""
if index >= len(data) or data[index] != '{':
- return [], index, True
+ return AttrDict([]), index, True
index += 1
for pos in range(index, len(data)):
@@ -60,25 +94,7 @@ class AttributeLinkInlineProcessor(LinkInlineProcessor):
if current_attr_text:
attrs.append(current_attr_text)
- return attrs, index, has_closing_brace
-
- @staticmethod
- def hasAttribute(attrs, name):
- return name in attrs
-
- @staticmethod
- def getStringAttribute(attrs, name):
- for attr in attrs:
- if attr.startswith(name + "="):
- return attr[len(name)+1:]
-
- @staticmethod
- def getIntAttribute(attrs, name):
- try:
- s = AttributeLinkInlineProcessor.getStringAttribute(attrs, name)
- return int(s) if s is not None else None
- except ValueError:
- return None
+ return AttrDict(attrs), index, has_closing_brace
class MediaInlineProcessor(AttributeLinkInlineProcessor):
""" Return a media element from the given match. """
@@ -90,21 +106,6 @@ class MediaInlineProcessor(AttributeLinkInlineProcessor):
def isAudio(self, url):
return url.endswith(".mp3") or url.endswith(".ogg")
- def getSizeAttribute(self, attrs, name):
- s = self.getStringAttribute(attrs, name)
- if s is None:
- return None, None
- dims = s.split("x", 1)
- try:
- if len(dims) == 1:
- return int(dims[0]), None
- else:
- w = int(dims[0]) if dims[0] else None
- h = int(dims[1]) if dims[1] else None
- return w, h
- except ValueError:
- return None, None
-
def handleMatch(self, m, data):
text, index, handled = self.getText(data, m.end(0))
if not handled:
@@ -117,19 +118,31 @@ class MediaInlineProcessor(AttributeLinkInlineProcessor):
attrs, index, handled = self.getAttributes(data, index)
if not handled:
return None, None, None
- print(attrs, self.getSizeAttribute(attrs, "size"))
kind = "image"
- if self.hasAttribute(attrs, "audio") or self.isAudio(src):
+ if attrs.has("audio") or self.isAudio(src):
kind = "audio"
- elif self.hasAttribute(attrs, "video") or self.isVideo(src):
+ elif attrs.has("video") or self.isVideo(src):
kind = "video"
# Images
if kind == "image":
- w, h = self.getSizeAttribute(attrs, "size")
- pixelated = self.hasAttribute(attrs, "pixelated")
+ w, h = attrs.getSize("size")
+ class_ = ""
+ # TODO: Media converter: Find a way to clear atfer a float
+ if attrs.has("pixelated"):
+ class_ += " pixelated"
+ if attrs.has("left"):
+ class_ += " align-left"
+ if attrs.has("center"):
+ class_ += " align-center"
+ elif attrs.has("right"):
+ class_ += " align-right"
+ elif attrs.has("float-left"):
+ class_ += " float-left"
+ elif attrs.has("float-right"):
+ class_ += " float-right"
el = etree.Element("img")
el.set("src", src)
@@ -137,8 +150,8 @@ class MediaInlineProcessor(AttributeLinkInlineProcessor):
if title is not None:
el.set("title", title)
- if pixelated:
- el.set("class", "pixelated")
+ if class_ != "":
+ el.set("class", class_)
if w is not None:
el.set("width", str(w))
if h is not None: