2
0
Fork 0

Corrected plenty of things.

This commit is contained in:
Thomas Touhey 2018-01-22 20:33:25 +01:00
parent 75189d08ab
commit df0bc1affa
No known key found for this signature in database
GPG key ID: 2ECEB0517AD947FB
9 changed files with 219 additions and 138 deletions

View file

@ -24,8 +24,7 @@ __test_cases = {
# Links.
'[url=http://hey.org/lol[]>"a]': '<a href="http://hey.org/lol[]&gt;' \
'&quot;a" target="_blank" rel="noopener">' \
'<a href="http://hey.org/lol[]&gt;&quot;a" target="_blank"' \
' rel="noopener">http://hey.org/lol[]&gt;&quot;a</a></a>',
'http://hey.org/lol[]&gt;&quot;a</a>',
'[url]javascript:alert(1)[/url]': '[url]javascript:alert(1)[/url]',
'(http://www.example.org/some-[damn-url]-(youknow))': \
'(<a href="http://www.example.org/some-[damn-url]-(youknow)" ' \
@ -52,6 +51,8 @@ __test_cases = {
'[url=https://thomas.touhey.fr/]mon profil est le meilleur[/url]':
'<a href="https://thomas.touhey.fr/" target="_blank" rel="noopener">' \
'mon profil est le meilleur</a>',
'[url=https://thomas.touhey.fr/]': '<a href="https://thomas.touhey.fr/" ' \
'target="_blank" rel="noopener">https://thomas.touhey.fr/</a>',
'https://thomas.touhey.fr/, tu vois ?': \
'<a href="https://thomas.touhey.fr/" target="_blank" rel="noopener">' \
'https://thomas.touhey.fr/</a>, tu vois ?',
@ -77,8 +78,7 @@ __test_cases = {
'<div class="video-wrapper video-medium"><iframe ' \
'src="https://www.youtube.com/embed/6odDOOyUawY" ' \
'frameborder="0" allowfullscreen></iframe></div>',
'[video]https://www.youtube.com/watch?v=<script>alert(1)</script>' \
'[/video]': \
'[video]https://www.youtube.com/watch?v=<script>alert(1)</script>': \
'<a href="https://www.youtube.com/watch?v=&lt;script&gt;alert(1)' \
'&lt;/script&gt;" target="_blank" rel="noopener">' \
'https://www.youtube.com/watch?v=&lt;script&gt;alert(1)' \
@ -86,7 +86,8 @@ __test_cases = {
# Quotes.
'[quote=Test 1 :)]lel[/quote]': \
'<div class="citation"><b>Test 1 :) a écrit:</b><br />lel</div>'
'<div class="citation"><b>Test 1 ' \
'<img src="/images/smileys/smile.gif"> a écrit:</b><br />lel</div>'
# Paragraphs (that's the most hardcore tests, I've not even settled on
# what the result should be yet).

View file

@ -36,8 +36,9 @@ class TextoutLinkTag(TextoutRawInlineTag):
# Otherwise, get the URL and validate.
self._url = value
self._validate()
self.default = self._default_if_value
def default(self):
def _default_if_value(self):
return self._url
def _preprocess_if_no_value(self, content):

View file

@ -36,9 +36,9 @@ class TextoutQuoteTag(TextoutParagraphTag):
def begin_html(self):
f = '<div class="citation">'
if self.value:
if self._value:
f += '<b>{} a écrit:</b><br />' \
.format(_htmlsmileys(_htmlescape(self.value)))
.format(_htmlsmileys(_htmlescape(self._value)))
return f
def end_html(self):

View file

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from .__base__ import *
from html import escape as _htmlescape
__all__ = ["TextoutSpoilerTag"]

View file

@ -3,6 +3,7 @@
import re as _re
import urllib.parse as _urlparse
from html import escape as _htmlescape
from .__base__ import *
from .Link import TextoutLinkTag
@ -27,9 +28,9 @@ class TextoutVideoTag(TextoutRawBlockTag):
def prepare(self, name, value):
""" Prepare the video tag. """
self.sizeclass = "video-tiny" if "tiny" in self.name \
self._sizeclass = "video-tiny" if "tiny" in self.name \
else "video-medium"
self.center = False
self._center = False
def _getvideo(self, url):
""" Try to get the video type for preprocessing. """
@ -39,25 +40,25 @@ class TextoutVideoTag(TextoutRawBlockTag):
raise Exception
if url.netloc == "youtu.be":
self.id = url.path[1:]
if not _hexcode.match(self.id):
self._id = url.path[1:]
if not _hexcode.match(self._id):
raise Exception
self.type = "youtube"
self._type = "youtube"
elif url.netloc in ('youtube.com', 'www.youtube.com'):
if url.path != '/watch':
raise Exception
self.id = _urlparse.parse_qs(url.query)['v'][0]
if not _hexcode.fullmatch(self.id):
self._id = _urlparse.parse_qs(url.query)['v'][0]
if not _hexcode.fullmatch(self._id):
raise Exception
self.type = "youtube"
self._type = "youtube"
elif url.netloc in ('dailymotion.com', 'www.dailymotion.com'):
self.code = _dailypath.match(url.path).groups()[0]
self.type = "dailymotion"
self._code = _dailypath.match(url.path).groups()[0]
self._type = "dailymotion"
elif url.netloc in ('vimeo.com', 'www.vimeo.com'):
self.code = url.path[1:]
if not _numcode.match(self.code):
self._code = url.path[1:]
if not _numcode.match(self._code):
raise Exception
self.type = "vimeo"
self._type = "vimeo"
else:
raise Exception
@ -68,33 +69,33 @@ class TextoutVideoTag(TextoutRawBlockTag):
url = _urlparse.urlparse(content)
if not url.scheme in ('http', 'https'):
raise Exception("No allowed prefix!")
self.type = None
self.url = content
self._type = None
self._url = content
def content_html(self):
""" Produce the embed code for the given type. """
if not self.type:
url = _htmlescape(self.url)
if not self._type:
url = _htmlescape(self._url)
return '<a href="{}" target="_blank" rel="noopener">{}</a>' \
.format(url, url)
code = '<div class="video-wrapper {}{}">'.format(self.sizeclass,
" video-center" if self.center else "")
code = '<div class="video-wrapper {}{}">'.format(self._sizeclass,
" video-center" if self._center else "")
if self.type == "youtube":
if self._type == "youtube":
code += '<iframe ' \
'src="https://www.youtube.com/embed/{}" frameborder="0" ' \
'allowfullscreen></iframe>'.format(self.id)
elif self.type == "dailymotion":
'allowfullscreen></iframe>'.format(self._id)
elif self._type == "dailymotion":
code += '<iframe frameborder="0" ' \
'src="https://www.dailymotion.com/embed/video/{}">' \
'</iframe>'.format(self.code)
elif self.type == "vimeo":
'</iframe>'.format(self._code)
elif self._type == "vimeo":
code += '<iframe src="https://player.vimeo.com/video/{}' \
'?title=0&byline=0&portrait=0" frameborder="0" ' \
'webkitAllowFullScreen allowFullScreen>' \
'</iframe>'.format(self.code)
'</iframe>'.format(self._code)
return code + '</div>'

View file

@ -1,9 +1,13 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__all__ = ["TextoutBlockTag", "TextoutParagraphTag", "TextoutInlineTag",
"TextoutRawTag", "TextoutRawBlockTag", "TextoutRawParagraphTag",
"TextoutRawInlineTag"]
from functools import partial as _p
__all__ = ["TextoutRawTag",
"TextoutBlockTag", "TextoutRawBlockTag",
"TextoutParagraphTag", "TextoutRawParagraphTag",
"TextoutInlineTag", "TextoutRawInlineTag",
"TextoutInlineBlockTag", "TextoutRawInlineBlockTag"]
# ---
# Main base tag class.
@ -48,35 +52,83 @@ class TextoutTag:
aliases = ()
@property
def name(self):
return self.__name
@property
def _full(self):
return self.__full
def __init__(self, name, value, ot):
""" Initialize the textout tag with the documented members. """
# FIXME: for all of the methods, call the general function first,
# then call the format-specific function, instead of only calling
# one of the two!!
# Store internal data.
self.__output_type = ot
self.__name = name
if name[0] + name[-1] == "[]":
self.__full = "[" + name[1:-1] + ("=" + value if value != None \
else "") + "]"
else:
self.__full = name
# Call both prepare functions.
if hasattr(self, 'prepare_' + ot):
self.prepare = getattr(self, 'prepare_' + ot)
if hasattr(self, 'prepare'):
self.prepare(name, value)
self.name = name
if name[0] + name[-1] == "[]":
self._full = "[" + name[1:-1] + ("=" + value if value != None \
else "") + "]"
else:
self._full = name
# Prepare the preprocessing elements.
if not hasattr(self, 'preprocess'):
if hasattr(self, 'preprocess_' + ot):
self.__preprocess0 = self.preprocess
self.preprocess = self.__preprocess_double
elif hasattr(self, 'preprocess_' + ot):
self.preprocess = getattr(self, 'preprocess_' + ot)
if hasattr(self, 'preprocess'):
self.__preprocess2 = self.preprocess
self.preprocess = self.__preprocess_and_prepare
else:
self.__after_preprocess()
if hasattr(self, 'begin_' + ot):
self.begin = getattr(self, 'begin_' + ot)
if hasattr(self, 'end_' + ot):
self.end = getattr(self, 'end_' + ot)
if hasattr(self, 'content_' + ot):
self.content = getattr(self, 'content_' + ot)
if hasattr(self, 'default_' + ot):
self.default = getattr(self, 'default_' + ot)
if hasattr(self, 'preprocess_' + ot):
self.preprocess = getattr(self, 'preprocess_' + ot)
def __preprocess_double(self, content):
""" Preprocess using the two methods. """
ct = self.__preprocess0(content)
if ct != None: content = ct; del ct
ct = self.__preprocess1(content)
if ct != None: content = ct; del ct
return content
def __preprocess_and_prepare(self, content):
""" Preprocess and do the things after. """
ret = self.__preprocess2(content)
self.__after_preprocess()
return ret
def __out(self, name):
""" Generic function to call two output functions of the same type. """
getattr(self, '__' + name)()
getattr(self, name + '_' + self.__output_type)()
def __after_preprocess(self):
ot = self.__output_type
for otype in ('begin', 'content', 'end'):
if hasattr(self, otype):
if hasattr(self, otype + '_' + ot):
setattr(self, '__' + otype, getattr(self, otype))
setattr(self, otype, _p(self.__out, otype))
elif hasattr(self, otype + '_' + ot):
setattr(self, otype, getattr(self, otype + '_' + ot))
# ---
# Role-specific base tag classes.
@ -95,14 +147,14 @@ class TextoutParagraphTag(TextoutBlockTag):
class TextoutRawParagraphTag(TextoutParagraphTag, TextoutRawTag):
pass
class TextoutInlineTag(TextoutTag):
pass
class TextoutRawInlineTag(TextoutInlineTag, TextoutRawTag):
pass
class TextoutInlineBlockTag(TextoutInlineBlockTag):
class TextoutInlineBlockTag(TextoutTag):
pass
class TextoutRawInlineBlockTag(TextoutInlineBlockTag, TextoutRawTag):
pass
class TextoutInlineTag(TextoutInlineBlockTag):
pass
class TextoutRawInlineTag(TextoutInlineBlockTag, TextoutRawTag):
pass
# End of file.

View file

@ -5,6 +5,7 @@
"""
import regex as _re
from html import escape as _htmlescape
__all__ = ["htmlsmileys"]
@ -16,46 +17,47 @@ _Smileys_prefix = "/images/smileys/"
_Smileys = {
'>:)': 'twisted.gif',
'>:(': '/images/smileys/evil.gif',
':)': '/images/smileys/smile.gif',
';)': '/images/smileys/wink.gif',
':(': '/images/smileys/sad.gif',
':D': '/images/smileys/grin.gif',
':p': '/images/smileys/hehe.gif',
'8-)': '/images/smileys/cool2.gif',
':@': '/images/smileys/mad.gif',
'0_0': '/images/smileys/eek.gif',
':E': '/images/smileys/mrgreen.gif',
':O': '/images/smileys/shocked.gif',
':s': '/images/smileys/confused2.gif',
'^^': '/images/smileys/eyebrows.gif',
":'(": '/images/smileys/cry.gif',
# ':-°': ('/images/smileys/whistle.gif', 'height: 15px;'),
'>:(': 'evil.gif',
':)': 'smile.gif',
';)': 'wink.gif',
':(': 'sad.gif',
':D': 'grin.gif',
':p': 'hehe.gif',
'8-)': 'cool2.gif',
':@': 'mad.gif',
'0_0': 'eek.gif',
':E': 'mrgreen.gif',
':O': 'shocked.gif',
':s': 'confused2.gif',
'^^': 'eyebrows.gif',
":'(": 'cry.gif',
# ':-°': ('whistle.gif', 'height: 15px;'),
# Name-based smileys.
':lol:': '/images/smileys/lol.gif',
':oops:': '/images/smileys/confused2.gif',
':grr:': '/images/smileys/evil.gif',
':sry:': '/images/smileys/redface.gif',
':mmm:': '/images/smileys/rolleyes.gif',
':waza:': '/images/smileys/waza.gif',
# ':whistle:': ('/images/smileys/whistle.gif', 'height: 15px;'),
':here:': '/images/smileys/pointer.gif',
':bow:': '/images/smileys/bow.gif',
':cool:': '/images/smileys/cool.gif',
':good:': '/images/smileys/welldone.gif',
':love:': '/images/smileys/love.gif',
':aie:': '/images/smileys/banghead2.gif',
':cry:': '/images/smileys/cry.gif',
':facepalm:': '/images/smileys/facepalm.gif',
':argh:': '/images/smileys/insults.gif',
':?:': '/images/smileys/what.gif',
':!:': '/images/smileys/excl.gif',
':arrow:': '/images/smileys/here.gif',
':grin:': '/images/smileys/grin.gif',
':lol:': 'lol.gif',
':oops:': 'confused2.gif',
':grr:': 'evil.gif',
':sry:': 'redface.gif',
':mmm:': 'rolleyes.gif',
':waza:': 'waza.gif',
# ':whistle:': ('whistle.gif', 'height: 15px;'),
':here:': 'pointer.gif',
':bow:': 'bow.gif',
':cool:': 'cool.gif',
':good:': 'welldone.gif',
':love:': 'love.gif',
':aie:': 'banghead2.gif',
':cry:': 'cry.gif',
':facepalm:': 'facepalm.gif',
':argh:': 'insults.gif',
':?:': 'what.gif',
':!:': 'excl.gif',
':arrow:': 'here.gif',
':grin:': 'grin.gif',
}
_Smileys_html = {_htmlescape(a): _Smileys_prefix + b}
_Smileys_html = {_htmlescape(a): _Smileys_prefix + b \
for a, b in _Smileys.items()}
def _Smiley_sub_html(m):
return m.group(1) + '<img src="' + _Smileys_html[m.group(2)] \

View file

@ -5,7 +5,6 @@
"""
import regex as _re
from io import StringIO as _sio
from html import escape as _htmlescape
from .Tags import TextoutRawTag, TextoutInlineTag, TextoutBlockTag, get_tag
from .stream import *
@ -45,10 +44,10 @@ class Translator:
self.cign = 0
# Paragraph management.
# The `cpar` is a boolean indicating if the current paragraph has
# content or not.
# The following member is a boolean indicating if the current
# paragraph has been open or not.
self.cpar = False
self.opened_group = False
# Text group management.
# In the following example text:
@ -94,9 +93,14 @@ class Translator:
# First of all, check if the text is empty or if we want to ignore it.
if not text or self.cign > 0:
if not code or self.cign > 0:
return
# If we ought to put code, that means that the paragraph content
# is starting and that we might have to put the start of paragraph.
self.start_block()
# The last queue is composed of booleans (does the group contain
# something or not) and texts.
# We want to set all of the booleans to True until the first text
@ -107,10 +111,11 @@ class Translator:
for pos, element in enumerate(self.last_queue):
if isinstance(element, bool):
self.last_queue[pos] = True
self.last_queue[pos] += self.text_group
continue
self.last_queue[pos] += code
break
else:
self.outp.write(self.process_text_group())
self.outp.write(code)
def put_newline(self):
""" Put a newline. """
@ -118,7 +123,7 @@ class Translator:
# If we ought to put a newline, that means that the paragraph content
# is starting and that we might have to put the start of paragraph.
self.startpar()
self.start_block()
# The newline depends on the output type and the context, of course.
@ -134,14 +139,10 @@ class Translator:
def put_text(self, text):
""" Output some text. """
# If we ought to put text, that means that the paragraph content
# is starting and that we might have to put the start of paragraph.
self.startpar()
# If we want to ignore the content (because it is not used
# nor output), let the text fall into the void.
if self.cign > 0:
# If we want to ignore the content (because it is not used
# nor output), let the text fall into the void.
return
# Add to the text group, which will be processed when `flush_text()`
@ -157,6 +158,11 @@ class Translator:
if not self.text_group or self.cign > 0:
return
# If we ought to put text, that means that the paragraph content
# is starting and that we might have to put the start of paragraph.
self.start_block()
# The last queue is composed of booleans (does the group contain
# something or not) and texts.
# We want to set all of the booleans to True until the first text
@ -167,6 +173,7 @@ class Translator:
for pos, element in enumerate(self.last_queue):
if isinstance(element, bool):
self.last_queue[pos] = True
continue
self.last_queue[pos] += self.text_group
break
else:
@ -180,24 +187,28 @@ class Translator:
def start_block(self):
""" Start the block paragraph if not started. """
# First of all, we ought to check the `cpar` variable to check if
# the paragraph has started or not.
return # TODO
if self.cpar:
# First of all, we ought to check the `opened_group` member to
# check if the paragraph has started or not.
if self.opened_group:
return
self.cpar = True
self.opened_group = True
# TODO: other things
def end_block(self):
""" End the block paragraph if not ended. """
# First of all, we ought to check the `cpar` variable to check if
# the paragraph has ended or not.
return # TODO
if not self.cpar:
# First of all, we ought to check the `opened_group` member to
# check if the paragraph has ended or not.
if not self.opened_group:
return
self.cpar = False
self.opened_group = False
# TODO: other things
@ -211,11 +222,13 @@ class Translator:
# doesn't care about the content in the input, and that the content
# should be ignored (hence the use of `cign`).
lq = False
if hasattr(tag, 'preprocess'):
self.last_queue.insert(0, "")
elif hasattr(tag, 'content'):
self.cign += 1
elif hasattr(tag, 'default'):
lq = True
self.last_queue.insert(0, False)
# If there is no content processing, we are starting things right now.
@ -225,6 +238,8 @@ class Translator:
if hasattr(tag, 'begin'):
self.put_code(tag.begin())
if lq:
self.last_queue[0] = False
# Don't forget to add the tag to the queue, and to enable raw
# mode if the tag expects a raw content (e.g. `[code]`).
@ -247,13 +262,9 @@ class Translator:
self.flush_text()
# Pop the tag out of the queue, and disable raw mode if it was
# a raw tag (which means that it enabled it, as tags into raw tags
# cannot be processed).
# Pop the tag out of the queue.
tag = self.queue.pop(0)
if isinstance(tag, TextoutRawTag):
self.raw_mode = False
# If preprocessing has been enabled, we ought to process the content,
# check if the tag is valid, and do everything we would have done
@ -265,6 +276,14 @@ class Translator:
# if the `preprocess()` method returns an exception).
content = self.last_queue.pop(0)
if not content and hasattr(tag, 'default'):
try:
content = tag.default()
except:
self.put_text(tag._full)
self.put_text(end)
return
try:
ct = tag.preprocess(content)
except:
@ -287,33 +306,38 @@ class Translator:
if hasattr(tag, 'begin'):
self.put_code(tag.begin())
if hasattr(tag, 'process'):
if hasattr(tag, 'content'):
self.put_code(tag.content())
else:
self.put_text(content)
else:
# Even when there is no preprocessing, there might be some
# content replacing method, this is where we manage it.
elif hasattr(tag, 'content'):
# Tag replaces content without preprocessing, which means
# the content has been ignored and the tag only puts the
# things.
if hasattr(tag, 'content'):
# Tag replaces content without preprocessing, which means
# the content has been ignored and the tag only puts the
# things.
self.cign -= 1
self.put_code(tag.content())
elif hasattr(tag, 'default'):
# Tag defines a default content if there might be none.
self.cign -= 1
self.put_code(tag.content())
elif hasattr(tag, 'default'):
# Tag defines a default content if there might be none.
has_content = self.last_queue.pop(0)
if not has_content:
has_content = self.last_queue.pop(0)
if not has_content:
try:
self.put_text(tag.default())
except:
self.put_text(tag._full)
# Don't forget to put the end of the tag, as well.
if hasattr(tag, 'end'):
self.put_code(tag.end())
# Disable raw mode if it was a raw tag (which means that it enabled it,
# as tags into raw tags cannot be processed).
if isinstance(tag, TextoutRawTag):
self.raw_mode = False
def process(self):
""" Main function of the translator. """

View file

@ -9,7 +9,6 @@ __all__ = ["htmlurls"]
# ---
# Autolinking regex.
# FIXME: they don't work yet by the look of it.
# ---
def _sub(m):