diff options
-rw-r--r-- | app/builder/sanitizer.py | 60 | ||||
-rw-r--r-- | app/lib/templatetags/templatetags/amp.py | 39 | ||||
-rw-r--r-- | design/sass/_writing_details.scss | 18 | ||||
-rw-r--r-- | design/templates/details/entry.amp | 14 |
4 files changed, 114 insertions, 17 deletions
diff --git a/app/builder/sanitizer.py b/app/builder/sanitizer.py new file mode 100644 index 0000000..8512f4f --- /dev/null +++ b/app/builder/sanitizer.py @@ -0,0 +1,60 @@ +from bs4 import BeautifulSoup + + +class Sanitizer(object): + blacklisted_tags = [] + blacklisted_attributes = [] + blacklisted_protocols = [] + + def __init__(self, tags=None, attributes=None, protocols=None): + if tags: + self.blacklisted_tags = tags + if attributes: + self.blacklisted_attributes = attributes + if protocols: + self.blacklisted_protocols = protocols + + def strip(self, content=None): + """Strip HTML content to meet standards of output type. + Meant to be subclassed for each converter. + + Keyword arguments: + content -- subset of an HTML document. (ie. contents of a body tag) + """ + if not content: + content = self.content + return content + + soup = BeautifulSoup(content, "lxml") + self.strip_tags(soup) + self.strip_attributes(soup) + + output = soup.body.decode_contents() + return output + + def strip_tags(self, soup): + if self.blacklisted_tags: + [x.extract() for x in soup.find_all(self.blacklisted_tags)] + + def strip_attributes_extra(self, node): + pass + + def strip_attributes(self, soup): + if not (self.blacklisted_attributes or self.blacklisted_protocols): + return + + for node in soup.body.find_all(True): + attributes = node.attrs.keys() + if not attributes: + continue + + for attr in self.blacklisted_attributes: + if attr in attributes: + del node.attrs[attr] + + self.strip_attributes_extra(node) + + if 'href' in attributes: + protocol = node['href'].split(':')[0] + if protocol in self.blacklisted_protocols: + del node['href']
\ No newline at end of file diff --git a/app/lib/templatetags/templatetags/amp.py b/app/lib/templatetags/templatetags/amp.py new file mode 100644 index 0000000..9c6f118 --- /dev/null +++ b/app/lib/templatetags/templatetags/amp.py @@ -0,0 +1,39 @@ +from django import template +from PIL import Image +from io import BytesIO +try: + import Image + import ImageFile +except ImportError: + try: + from PIL import Image + from PIL import ImageFile + except ImportError: + raise ImportError("Could not import the Python Imaging Library.") + +import requests +from bs4 import BeautifulSoup +from builder.sanitizer import Sanitizer + +register = template.Library() + + +def remove_img_tags(text): + soup = BeautifulSoup(text, 'xml') + for img in soup.find_all('img'): + r = requests.get(img['src']) + i = Image.open(BytesIO(r.content)) + width, height = i.size + try: + new_tag = soup.new_tag("amp-img", alt=img["alt"], width=width, height=height, src=img['src'], srcset=img['srcset']) + except: + new_tag = soup.new_tag("amp-img", alt=img["alt"], width=width, height=height, src=img['src']) + img.replace_with(new_tag) + return soup.prettify() + + +def do_amp(text): + bs = remove_img_tags(text) + return Sanitizer().strip(bs) + +register.filter('amp', do_amp) diff --git a/design/sass/_writing_details.scss b/design/sass/_writing_details.scss index 53b3aca..c7a57b0 100644 --- a/design/sass/_writing_details.scss +++ b/design/sass/_writing_details.scss @@ -153,20 +153,25 @@ .footnote { @include constrain_narrow(); margin: 1em auto 0 auto; - padding:0; - list-style-position:inside; + padding: 0; list-style-type: none; - &:before { + &:before, &:after { + @include faded_line_after; @include breakpoint(beta) { - @include faded_line_after; margin-bottom: 2em; } } p { font-size: 0.875em; - line-height: 1.4 + line-height: 1.4; } hr {display: none;} + ol { + padding-left: 1em; + @include breakpoint(alpha) { + margin-left: 1em; + } + } } .dark .footnote:before { @include light_faded_line_after; @@ -352,7 +357,8 @@ display: block; .comments--header { font-family: Helvetica Neue, Helvetica, sans-serif; line-height: 6em; - @include fontsize(24); + @include fontsize(16); + font-style: italic; &:before { @include faded_line_after; margin-top: 2em; diff --git a/design/templates/details/entry.amp b/design/templates/details/entry.amp index 6305d46..32b6d36 100644 --- a/design/templates/details/entry.amp +++ b/design/templates/details/entry.amp @@ -1,4 +1,5 @@ {% load typogrify_tags %} +{% load amp %} <!doctype html> <html amp lang="en"> <head> @@ -45,7 +46,6 @@ }, "publisher": { "@type": "Person", - "name": "Jeremy Keith", "name": "Scott Gilbertson" "logo": { "@type": "ImageObject", @@ -137,8 +137,6 @@ hr { border-bottom: 0.0625rem dotted #ccc; } </style> -<script async custom-element="amp-audio" src="https://cdn.ampproject.org/v0/amp-audio-0.1.js"></script> -<script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script> <style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript> <script async src="https://cdn.ampproject.org/v0.js"></script> </head> @@ -146,8 +144,7 @@ hr { <nav> <a href="https://luxagraf.net/"> -<amp-img src="https://adactio.com/skins/default/images/logo.png" srcset="https://adactio.com/skins/default/images/logox2.png 2x" alt="adactio" width="240" height="53" layout="fixed"></amp-img> -</a> +luxagraf</a> </nav> <main class="h-entry"> @@ -158,15 +155,10 @@ hr { <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p> <aside class="p-location h-adr adr post--location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place"> {% if object.country.name == "United States" %}<span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, <a class="p-region region" href="/jrnl/united-states/" title="travel writing from the United States">{{object.state.name|safe}}</a>, <span class="p-country-name">U.S.</span>{%else%}<span class="p-region">{{object.location.name|smartypants|safe}}</span>, <a class="p-country-name country-name" href="/jrnl/{{object.country.slug}}/" title="travel writing from {{object.country.name}}">{{object.country.name|safe}}</a>{%endif%} - <span style="display: none;" itemprop="geo" itemscope itemtype="http://schema.org/GeoCoordinates"> - <data itemprop="latitude" class="p-latitude" value="{{object.latitude}}">{{object.latitude}}</data> - <data itemprop="longitude" class="p-longitude" value="{{object.longitude}}">{{object.longitude}}</data> - </span> - {% with object.get_template_name_display as t %}{%if t == "single" or t == "single-dark" %} – <a href="" onclick="showMap({{object.latitude}}, {{object.longitude}}, { type:'point', lat:'{{object.latitude}}', lon:'{{object.longitude}}'}); return false;" title="see a map">Map</a>{%endif%}{%endwith%} </aside> </header> <div id="article" class="e-content entry-content post--body post--body--{% with object.template_name as t %}{%if t == 0 or t == 2 %}single{%endif%}{%if t == 1 or t == 3 %}double{%endif%}{%endwith%}" itemprop="articleBody"> - {{object.body_html|safe|smartypants|widont}} + {{object.body_html|amp|safe}} </div> </article> </main> |