Compare commits
5 Commits
fc7d826c13
...
69f208fb8b
Author | SHA1 | Date | |
---|---|---|---|
69f208fb8b | |||
5e51b10953 | |||
fa2e373550 | |||
d20c7fd11d | |||
9f300a677c |
@ -40,6 +40,56 @@ class CommentCollection(admin.Administerable):
|
||||
|
||||
return None
|
||||
|
||||
comment_markdown_help = """
|
||||
Allows limited markdown, but no HTML.
|
||||
|
||||
**Emphasis:**
|
||||
|
||||
* `*italic*` → *italic*
|
||||
* `**bold**` → **bold**
|
||||
* `***bold italic***` → ***bold italic***
|
||||
* `~~strikethrough~~` → ~~strikethrough~~
|
||||
* `` `simple code` `` → `simple code`
|
||||
|
||||
**Blockquotes:**
|
||||
|
||||
*Input:*
|
||||
|
||||
```md
|
||||
> This is a blockquote.
|
||||
> It can span multiple lines and will appear indented.
|
||||
```
|
||||
|
||||
*Output:*
|
||||
|
||||
> This is a blockquote.
|
||||
> It can span multiple lines and will appear indented.
|
||||
|
||||
**Fenced code blocks:**
|
||||
|
||||
*Input:*
|
||||
|
||||
````md
|
||||
```
|
||||
def example(x):
|
||||
if x >= 2:
|
||||
do_stuff(x)
|
||||
else:
|
||||
do_thing(x)
|
||||
```
|
||||
````
|
||||
|
||||
*Output:*
|
||||
|
||||
```
|
||||
def example(x):
|
||||
if x >= 2:
|
||||
do_stuff(x)
|
||||
else:
|
||||
do_thing(x)
|
||||
```
|
||||
"""
|
||||
|
||||
class Comment(admin.Administerable):
|
||||
|
||||
autoform_blacklist = ('id',)
|
||||
@ -51,7 +101,7 @@ class Comment(admin.Administerable):
|
||||
captcha_passed = peewee.BooleanField(null=False, default=False, verbose_name="Passed captcha", help_text="Whether the comment passed the captcha challenge.")
|
||||
moderation_passed = peewee.BooleanField(null=False, default=False, verbose_name="Passed moderation", help_text="Whether the comment passed moderation.")
|
||||
nick = peewee.CharField(null=False, verbose_name='Your name')
|
||||
text = markdown.SafeMarkdownTextField(verbose_name="Your message")
|
||||
text = markdown.SafeMarkdownTextField(verbose_name="Your message", help_text=comment_markdown_help)
|
||||
|
||||
@werkzeug.utils.cached_property
|
||||
def replies(self):
|
||||
|
10
main.py
10
main.py
@ -460,7 +460,7 @@ class FrontPage(rendering.Renderable):
|
||||
else:
|
||||
stmt = stmt.union_all(select)
|
||||
|
||||
stmt = stmt.order_by(stmt.c.created.desc())
|
||||
stmt = stmt.order_by(stmt.c.created.desc(), stmt.c.name.asc())
|
||||
|
||||
results = stmt.dicts()
|
||||
|
||||
@ -1215,7 +1215,13 @@ class Page(admin.Administerable):
|
||||
@rendering.page(title_show=False)
|
||||
def view_page(path):
|
||||
|
||||
return Page.get(Page.path == path)
|
||||
# thrown Page.DoesNotExist will automatically trigger 404.
|
||||
page = Page.get(Page.path == path)
|
||||
|
||||
if page.published or flask.g.user:
|
||||
return page
|
||||
|
||||
raise Page.DoesNotExist()
|
||||
|
||||
class PermaRedirect(admin.Administerable):
|
||||
|
||||
|
36
markdown.py
36
markdown.py
@ -169,10 +169,19 @@ def renderable_inline_render(self, tokens, idx, options, env):
|
||||
|
||||
def section_core_rule(state):
|
||||
|
||||
if not state.inlineMode: # inline rendering shouldn't contain sections
|
||||
|
||||
tokens = []
|
||||
nesting = 0 # NOTE: Section nesting isn't really a thing, a bool whether a section is opened should suffice
|
||||
open_next = False # whether to open a new section in the next loop iteration
|
||||
|
||||
# less-than-stringent hack to identify rules of renderable_plugin.
|
||||
# this is needed because core rules are evaluated *before* inline
|
||||
# rules so we only have raw type 'inline' tokens instead of
|
||||
# 'renderable_inline' ones. the alternative would be using
|
||||
# the same string parsing logic as the actual plugin, i.e.
|
||||
# renderable_inline_rule with faked state object, or
|
||||
# decoupling the parsing from the rule
|
||||
regexp_renderable = re.compile('^#\[.+/.+\]\s*$')
|
||||
|
||||
for idx, token in enumerate(state.tokens):
|
||||
@ -184,7 +193,24 @@ def section_core_rule(state):
|
||||
nesting += 1
|
||||
|
||||
if idx == 0: # for the first element in the document
|
||||
if token.type != 'heading_open':
|
||||
|
||||
renderable_at_start = False
|
||||
if len(state.tokens) >= idx + 2: # token after current one exists
|
||||
|
||||
# if markdown source begins with a renderable_plugin rule,
|
||||
# the first *token* will be a paragraph_open, with the
|
||||
# inline token containing the renderable following
|
||||
# immediately after it
|
||||
|
||||
token_check = state.tokens[idx + 1]
|
||||
|
||||
if token_check.type == 'inline' and isinstance(token_check.content, str) and \
|
||||
re.match(regexp_renderable, token_check.content): # found match for plugin_renderable
|
||||
renderable_at_start = True
|
||||
|
||||
if renderable_at_start:
|
||||
open_next = False
|
||||
elif token.type != 'heading_open':
|
||||
tokens.append(markdown_it.token.Token('section_open', 'section', 1))
|
||||
nesting += 1
|
||||
else:
|
||||
@ -210,7 +236,7 @@ def section_core_rule(state):
|
||||
token_check = state.tokens[idx + 3] # +3 to skip paragraph_close/paragraph_open tokens
|
||||
|
||||
if token_check.type == 'inline' and isinstance(token_check.content, str) and \
|
||||
re.match(regexp_renderable, token_check.content): # next token is also an inline renderable
|
||||
re.match(regexp_renderable, token_check.content): # found match for plugin_renderable
|
||||
|
||||
open_next = False
|
||||
|
||||
@ -248,9 +274,9 @@ def section_plugin(md):
|
||||
|
||||
# splits output into <section>s, based on <h2> placements
|
||||
|
||||
md.core.ruler.push("section_core", section_core_rule)
|
||||
md.add_render_rule("section_open", section_open)
|
||||
md.add_render_rule("section_close", section_close)
|
||||
md.core.ruler.push('section_core', section_core_rule)
|
||||
md.add_render_rule('section_open', section_open)
|
||||
md.add_render_rule('section_close', section_close)
|
||||
|
||||
md_unsafe = markdown_it.MarkdownIt('commonmark', {'highlight': code_highlight})
|
||||
md_unsafe.enable('table')
|
||||
|
@ -161,8 +161,6 @@ class TagCollection(admin.Administerable):
|
||||
@werkzeug.utils.cached_property
|
||||
def parent(self):
|
||||
|
||||
import pudb; pudb.set_trace()
|
||||
|
||||
stmt = None
|
||||
|
||||
for taggable_name, taggable in Taggable.__class_descendants__.items():
|
||||
|
@ -783,6 +783,34 @@ article.errorpage > .content > .message {
|
||||
scale: 1.2;
|
||||
}
|
||||
|
||||
article.tagcollection ul {
|
||||
list-style: none;
|
||||
padding: var(--distance-main);
|
||||
}
|
||||
|
||||
article.tagcollection ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
article.tagcollection ul li a {
|
||||
display: inline-block;
|
||||
padding: var(--distance-minor);
|
||||
background: var(--color-highlight-inactive);
|
||||
color: var(--color-highlight-contrast);
|
||||
font-weight: 300;
|
||||
text-decoration: none;
|
||||
transition-duration: 0.2s;
|
||||
transition-timing-function: var(--ease-bounce);
|
||||
transition-property: scale, background-color;
|
||||
}
|
||||
|
||||
article.tagcollection ul li a:hover,
|
||||
article.tagcollection ul li a:focus {
|
||||
background: var(--color-highlight);
|
||||
scale: 1.1;
|
||||
}
|
||||
|
||||
|
||||
/* common constructs */
|
||||
|
||||
article .unpublished {
|
||||
@ -913,22 +941,53 @@ a.download:active {
|
||||
|
||||
.mode-teaser,
|
||||
.mode-admin-teaser {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
position: relative; /* enables z-index */
|
||||
background: var(--color-bg-alt);
|
||||
transition: scale 0.2s var(--ease-bounce);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.mode-teaser a {
|
||||
.mode-teaser > .content,
|
||||
.mode-teaser > .content .teaser-link,
|
||||
.mode-admin-teaser > .content,
|
||||
.mode-admin-teaser > .content .teaser-link {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.mode-teaser > .content,
|
||||
.mode-teaser > .content .teaser-link,
|
||||
.mode-admin-teaser > .content,
|
||||
.mode-admin-teaser > .content .teaser-link {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.mode-teaser a,
|
||||
.mode-admin-teaser a {
|
||||
text-decoration: none;
|
||||
color: var(--color-text-main);
|
||||
}
|
||||
|
||||
.mode-teaser:hover {
|
||||
scale: 1.1;
|
||||
.mode-teaser:hover,
|
||||
.mode-teaser:has(:focus),
|
||||
.mode-admin-teaser:hover,
|
||||
.mode-admin-teaser:has(:focus) {
|
||||
scale: 1.05;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.mode-teaser > .content .teaser-link section {
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/*.mode-teaser > :first-child,
|
||||
.mode-admin-teaser > :first-child {*/
|
||||
/* keeping original selector around in case it was actually a smart thing to do */
|
||||
@ -957,8 +1016,7 @@ a.download:active {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mode-teaser .lead-image .description,
|
||||
.mode-admin-teaser .lead-image .description {
|
||||
.lead-image .description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -1041,11 +1099,7 @@ article.administerable > header > article.upload {
|
||||
|
||||
.listing > ul > li > .mode-teaser,
|
||||
.listing > ul > li > .mode-admin-teaser {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
height: 100%; /* makes all teasers in the same row have the same height */
|
||||
}
|
||||
|
||||
/* renderables */
|
||||
@ -1070,6 +1124,7 @@ article.administerable > .content section {
|
||||
|
||||
font-size: 120%;
|
||||
text-align: justify;
|
||||
line-height: 120%;
|
||||
}
|
||||
|
||||
article.administerable > .content section:last-child {
|
||||
@ -1092,13 +1147,16 @@ article.administerable > .content section:has(p:empty:only-child) {
|
||||
|
||||
/* uploads */
|
||||
|
||||
article.upload {
|
||||
margin-bottom: var(--distance-main);
|
||||
}
|
||||
|
||||
article.upload .description {
|
||||
position: absolute;
|
||||
translate: 0 -100%;
|
||||
max-width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
padding: var(--distance-main);
|
||||
background: var(--color-bg-alt);
|
||||
backdrop-filter: blur(8px);
|
||||
padding: var(--distance-main);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
article.image img {
|
||||
@ -1122,16 +1180,26 @@ article.audio audio {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
article.audio audio::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
background: #f00;
|
||||
article.image .description {
|
||||
position: absolute;
|
||||
left: 50vw;
|
||||
translate: -50% -100%;
|
||||
}
|
||||
|
||||
article.file .description {
|
||||
padding: 0;
|
||||
padding-left: 4.5rem;
|
||||
translate: 0 100%;
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fileinfo {
|
||||
height: 4rem; /* remove -100% y-translated filesize from height */
|
||||
width: 100%;
|
||||
max-width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.fileinfo .filesize {
|
||||
@ -1508,25 +1576,6 @@ body > .menus .searchminiform .field-help-wrapper {
|
||||
background: var(--color-bg-alt);
|
||||
}
|
||||
|
||||
/*.propagandapiece .files > .fileinfo {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.propagandapiece .files > .fileinfo > * {
|
||||
display: table-cell;
|
||||
background: var(--color-highlight);
|
||||
color: var(--color-highlight-contrast);
|
||||
padding: var(--distance-minor);
|
||||
}
|
||||
|
||||
.propagandapiece .files > .fileinfo > *:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.propagandapiece .files > .fileinfo > *:last-child {
|
||||
text-align: right;
|
||||
}*/
|
||||
|
||||
.propagandapiece .modal article,
|
||||
.propagandapiece .modal .content {
|
||||
min-height: 100vh;
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 2.5 MiB |
@ -2,9 +2,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>{% if title %}{{ title }} | {{ site_name }}{% else %}{{ site_name }}{% endif %}</title>
|
||||
|
||||
<link rel="stylesheet" href="/theme/css/main.css" />
|
||||
<link rel="stylesheet" href="/theme/css/highlight.css" />
|
||||
<link rel="stylesheet" href="/theme/css/nativeads.js.css" />
|
||||
|
||||
</head>
|
||||
<body
|
||||
{% if content is renderable %}
|
||||
|
@ -1,4 +1,3 @@
|
||||
{% extends 'default/templates/renderable/audio.html' %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
{% block fileinfo %}{% endblock %}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends 'default/templates/renderable/upload.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% block fileview %}
|
||||
<audio
|
||||
controls
|
||||
{% if content.description %}
|
||||
@ -10,5 +10,4 @@
|
||||
<source src={{ content.url('raw') }} type="{{ content.media_type }}" />
|
||||
Audio playback not supported by your browser.
|
||||
</audio>
|
||||
{% block fileinfo %}{{ super() }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
13
themes/default/templates/renderable/file.html
Normal file
13
themes/default/templates/renderable/file.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends 'default/templates/renderable/upload.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ self.hints() }}
|
||||
|
||||
{{ self.fileview() }}
|
||||
|
||||
{{ self.description() }}
|
||||
|
||||
{{ self.fileinfo() }} {# fileinfo is essentially fileview for raw files #}
|
||||
|
||||
{% endblock %}
|
@ -1,21 +1,11 @@
|
||||
{% extends 'default/templates/renderable/upload.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if not content.published %}
|
||||
<span class="warning unpublished" title="This {{ content._lowerclass }} has NOT been published."></span>
|
||||
{% endif %}
|
||||
|
||||
<img
|
||||
{% block fileview %}
|
||||
<img
|
||||
src="{{ content.url('raw') }}"
|
||||
{% if content.description %}
|
||||
alt="{{ content.description }}"
|
||||
title="{{ content.description }}"
|
||||
{% endif %}
|
||||
/>
|
||||
|
||||
{% if content.description %}
|
||||
<div class="description">{{ content.description.render() }}</div>
|
||||
{% endif %}
|
||||
{% block fileinfo %}{{ super() }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends 'default/templates/renderable/leadimagecontent.html' %}
|
||||
|
||||
{% block content %}
|
||||
<a href="{{ content.url() }}">
|
||||
<a class="teaser-link" href="{{ content.url() }}">
|
||||
<header>
|
||||
<div class="lead-image">
|
||||
{% if content.lead_image_id %}
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<span>Match path:</span> <span class="match-path path">{{ content.match_path }}</span>
|
||||
<span>Match path:</span> <code class="match-path path">{{ content.match_path }}</code>
|
||||
</div>
|
||||
<div>
|
||||
<span>Redirect path:</span> <span class="redirect-path path">{{ content.redirect_path }}</span>
|
||||
<span>Redirect path:</span> <code class="redirect-path path">{{ content.redirect_path }}</code>
|
||||
</div>
|
||||
|
||||
<a class="permaredirect-link" target="_blank" href="{{ content.match_path }}">Try it</a>
|
||||
{% endblock %}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<a href="{{ content.url() }}">
|
||||
<a class="teaser-link" href="{{ content.url() }}">
|
||||
|
||||
<div class="preview">
|
||||
{% for piece in content.pieces_ordered %}
|
||||
|
@ -1,3 +1,4 @@
|
||||
{% if config.DEBUG %}<!-- template begins: {{ self._TemplateReference__context.name }} -->{% endif %}
|
||||
<article class="{{ content.css_classes }} mode-{{ mode }}">
|
||||
|
||||
{% if self.header()|trim %}
|
||||
@ -20,7 +21,14 @@
|
||||
|
||||
{% if self.footer()|trim %}
|
||||
<footer>
|
||||
{% block footer %}{% endblock %}
|
||||
{% block footer %}
|
||||
{% if self.meta()|trim %}
|
||||
<div class="meta">
|
||||
{% block meta %}{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</article>
|
||||
{% if config.DEBUG %}<!-- template ends: {{ self._TemplateReference__context.name }} -->{% endif %}
|
||||
|
@ -1,7 +1,14 @@
|
||||
{% extends 'default/templates/renderable/administerable.html' %}
|
||||
|
||||
{% block content %}
|
||||
<a class="url" href="{{ content.url }}" style="background-image: url('/theme/dynamic/scoredlink/{{ content.id }}');">{{ content.url }}</a>
|
||||
<a
|
||||
class="url"
|
||||
href="{{ content.url }}"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
style="background-image: url('/theme/dynamic/scoredlink/{{ content.id }}');"
|
||||
title="This URL loads data from {{ content.external_site_count }} external sites (median: {{ content.median }}, mean: {{ content.mean }}, min {{ content.min }}, max: {{ content.max }}, set size: {{ content.set_size }})"
|
||||
>{{ content.url }}</a>
|
||||
<ul class="fields">
|
||||
<li class="field external-site-count">
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
{% extends 'default/templates/renderable/administerable.html' %}
|
||||
|
||||
{% block footer %}
|
||||
{% block meta %}
|
||||
|
||||
{{ super() }}
|
||||
|
||||
{% if content.tag_collection_id and content.tag_collection.items|length %}
|
||||
{{ content.tag_collection.render('inline') }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
@ -2,9 +2,20 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block hints %}
|
||||
{% if not content.published %}
|
||||
<span class="warning unpublished" title="This {{ content._lowerclass }} has NOT been published."></span>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block fileview %}
|
||||
{% endblock %}
|
||||
|
||||
{% block description %}
|
||||
{% if content.description %}
|
||||
<div class="description">{{ content.description.render('inline') }}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block fileinfo %}
|
||||
<div class="fileinfo">
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends 'default/templates/renderable/upload.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% block fileview %}
|
||||
<video
|
||||
controls
|
||||
{% if content.description %}
|
||||
@ -10,5 +10,4 @@
|
||||
<source src={{ content.url('raw') }} type="{{ content.media_type }}" />
|
||||
Video playback not supported by your browser.
|
||||
</video>
|
||||
{% block fileinfo %}{{ super() }}{% endblock %}
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user