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 @@ - +
{{ widget_user.profile(comment.author) }}
{{ comment.text | md }}
{{ comment.text | md }}
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: