add babycode preview
This commit is contained in:
@@ -203,12 +203,14 @@ def create_app():
|
|||||||
from app.routes.guides import bp as guides_bp
|
from app.routes.guides import bp as guides_bp
|
||||||
from app.routes.mod import bp as mod_bp
|
from app.routes.mod import bp as mod_bp
|
||||||
from app.routes.posts import bp as posts_bp
|
from app.routes.posts import bp as posts_bp
|
||||||
|
from app.routes.api import bp as api_bp
|
||||||
app.register_blueprint(topics_bp)
|
app.register_blueprint(topics_bp)
|
||||||
app.register_blueprint(threads_bp)
|
app.register_blueprint(threads_bp)
|
||||||
app.register_blueprint(users_bp)
|
app.register_blueprint(users_bp)
|
||||||
app.register_blueprint(guides_bp)
|
app.register_blueprint(guides_bp)
|
||||||
app.register_blueprint(mod_bp)
|
app.register_blueprint(mod_bp)
|
||||||
app.register_blueprint(posts_bp)
|
app.register_blueprint(posts_bp)
|
||||||
|
app.register_blueprint(api_bp)
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
from .schema import create as create_tables
|
from .schema import create as create_tables
|
||||||
|
|||||||
@@ -105,6 +105,14 @@ def login_required(view_func):
|
|||||||
return view_func(*args, **kwargs)
|
return view_func(*args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
def hard_login_required(view_func):
|
||||||
|
@wraps(view_func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if not is_logged_in():
|
||||||
|
abort(403)
|
||||||
|
return view_func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
def mod_only(view_func):
|
def mod_only(view_func):
|
||||||
@wraps(view_func)
|
@wraps(view_func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
|||||||
21
app/routes/api.py
Normal file
21
app/routes/api.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
from ..auth import is_logged_in, hard_login_required, get_active_user
|
||||||
|
from ..lib.babycode import babycode_to_html
|
||||||
|
from ..models import APIRateLimits
|
||||||
|
|
||||||
|
bp = Blueprint('api', __name__, url_prefix='/api/')
|
||||||
|
|
||||||
|
@bp.post('/babycode-preview/')
|
||||||
|
@hard_login_required
|
||||||
|
def babycode_preview():
|
||||||
|
user = get_active_user()
|
||||||
|
if not APIRateLimits.is_allowed(user.id, 'babycode_preview', 5):
|
||||||
|
return {'error': 'too many requests'}, 429
|
||||||
|
markup = str(request.json.get('markup', ''))
|
||||||
|
if not markup:
|
||||||
|
return {'error': 'markup field missing or invalid type'}, 400
|
||||||
|
banned_tags = request.json.get('banned_tags', [])
|
||||||
|
if not isinstance(banned_tags, list):
|
||||||
|
return {'error': 'banned_tags field is invalid type'}, 400
|
||||||
|
rendered = babycode_to_html(markup, banned_tags).result
|
||||||
|
return {'html': rendered}
|
||||||
@@ -72,15 +72,15 @@
|
|||||||
</span>
|
</span>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro tabs(prefix='', labels = []) -%}
|
{% macro tabs(prefix='', labels=[], signal_ss=[], signal_rs=[]) -%}
|
||||||
<div class="tab-container" data-r="setTab">
|
<div class="tab-container" data-r="setTab">
|
||||||
<div class="tab-bar" role="tablist">
|
<div class="tab-bar" role="tablist">
|
||||||
{%- for tab_label in labels -%}
|
{%- for tab_label in labels -%}
|
||||||
<button type="button" class="tab-button" role="tab" aria-selected="{{'true' if loop.index0==0 else 'false'}}" id="{{prefix+'-'+(tab_label | lower)+'-tab'}}" aria-controls="{{prefix+'-'+(tab_label | lower)+'-content'}}" disabled data-r="enhance" data-s="setTab" data-tab-index="{{loop.index0}}">{{tab_label}}</button>
|
<button type="button" class="tab-button" role="tab" aria-selected="{{'true' if loop.index0==0 else 'false'}}" id="{{prefix+'-'+(tab_label | lower)+'-tab'}}" aria-controls="{{prefix+'-'+(tab_label | lower)+'-content'}}" disabled data-r="enhance" data-s="setTab {{signal_ss[loop.index0] if signal_ss[loop.index0] else ''}}" data-tab-index="{{loop.index0}}">{{tab_label}}</button>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</div>
|
</div>
|
||||||
{%- for tab_label in labels -%}
|
{%- for tab_label in labels -%}
|
||||||
<div class="plank secondary-bg even no-shadow tab-content {{'hidden' if loop.index0!=0 else ''}}" role="tabpanel" aria-labelledby="{{prefix+'-'+(tab_label | lower)+'-tab'}}" id="{{prefix+'-'+(tab_label | lower)+'-content'}}">
|
<div class="plank secondary-bg even no-shadow tab-content {{'hidden' if loop.index0!=0 else ''}}" role="tabpanel" aria-labelledby="{{prefix+'-'+(tab_label | lower)+'-tab'}}" id="{{prefix+'-'+(tab_label | lower)+'-content'}}" data-r="{{signal_rs[loop.index0] if signal_rs[loop.index0] else ''}}">
|
||||||
{{- caller(loop.index0) -}}
|
{{- caller(loop.index0) -}}
|
||||||
</div>
|
</div>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
id='babycode-content',
|
id='babycode-content',
|
||||||
banned_tags=[]
|
banned_tags=[]
|
||||||
) -%}
|
) -%}
|
||||||
{%- call(idx) tabs(prefix='babycode', labels=['Write', 'Preview']) -%}
|
{%- call(idx) tabs(prefix='babycode', labels=['Write', 'Preview'], signal_ss=[none, 'babycodePreviewInit'], signal_rs=[none, 'babycodePreview']) -%}
|
||||||
{%- if idx == 0 -%}
|
{%- if idx == 0 -%}
|
||||||
<span class="babycode-editor-controls">
|
<span class="babycode-editor-controls">
|
||||||
<span class="button-row js-only" data-r="enhance">
|
<span class="button-row js-only" data-r="enhance">
|
||||||
@@ -109,10 +109,10 @@
|
|||||||
<button type="button" title="insert spoiler" class="minimal" data-babycode-tag="spoiler=" data-break-line data-prefill="spoiler content" data-s="insertBabycode">s</button>
|
<button type="button" title="insert spoiler" class="minimal" data-babycode-tag="spoiler=" data-break-line data-prefill="spoiler content" data-s="insertBabycode">s</button>
|
||||||
<button type="button" title="insert emoji…" class="minimal"><img src="/static/emoji/angry.png" class="emoji"></button>
|
<button type="button" title="insert emoji…" class="minimal"><img src="/static/emoji/angry.png" class="emoji"></button>
|
||||||
</span>
|
</span>
|
||||||
<span class="flex-last">{# stub: char count #}</span>
|
<span class="flex-last js-only" data-r="enhance">stub: char count</span>
|
||||||
</span>
|
</span>
|
||||||
<input type="hidden" name="babycode_banned_tags" id="{{id}}-banned-tags" value="{{banned_tags | unique | list | tojson | forceescape}}">
|
<input type="hidden" name="babycode_banned_tags" id="{{id}}-banned-tags" value="{{banned_tags | unique | list | tojson | forceescape}}">
|
||||||
<textarea name="babycode_content" id="{{id}}" class="babycode-editor" placeholder="{{placeholder}}" {{'required' if required else ''}} autocomplete="off" maxlength="5000" data-r="insertBabycode">{{ prefill }}</textarea>
|
<textarea name="babycode_content" id="{{id}}" class="babycode-editor" placeholder="{{placeholder}}" {{'required' if required else ''}} autocomplete="off" maxlength="5000" data-r="insertBabycode babycodePreviewInit" data-banned-tags="{{banned_tags | unique | list | tojson | forceescape}}">{{ prefill }}</textarea>
|
||||||
{%- if banned_tags -%}
|
{%- if banned_tags -%}
|
||||||
<div>
|
<div>
|
||||||
<span>Forbidden tags:</span>
|
<span>Forbidden tags:</span>
|
||||||
@@ -124,6 +124,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<a href="##">babycode help</a>
|
<a href="##">babycode help</a>
|
||||||
|
{%- else -%}
|
||||||
|
<div data-r="showBabycodePreview"></div>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- endcall -%}
|
{%- endcall -%}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<input type="submit" value="Clear MOTD" class="warn">
|
<input type="submit" value="Clear MOTD" class="warn">
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
{{babycode_editor_component(placeholder='test', id='test-content')}}
|
||||||
<fieldset class="plank" id="sort-topics">
|
<fieldset class="plank" id="sort-topics">
|
||||||
<legend>Sort topics</legend>
|
<legend>Sort topics</legend>
|
||||||
<p>Drag topics around to reorder them. Press "Save order" when done.</p>
|
<p>Drag topics around to reorder them. Press "Save order" when done.</p>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
export const b = {}
|
export const b = {
|
||||||
|
babycodePreviewEndpoint: '/api/babycode-preview/',
|
||||||
|
}
|
||||||
|
|
||||||
export function setTab(_, sender, el) {
|
export function setTab(_, sender, el) {
|
||||||
if (sender.ariaSelected === 'true') {
|
if (sender.ariaSelected === 'true') {
|
||||||
@@ -78,3 +80,64 @@ export function insertBabycode(_, sender, el) {
|
|||||||
}
|
}
|
||||||
el.focus();
|
el.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function babycodePreviewInit(ev, sender, el) {
|
||||||
|
if (!sender.parentNode.parentNode.contains(el)) { // tab container > tab bar > button
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.send({ text: el.value, sender: sender, bannedTags: JSON.parse(el.dataset.bannedTags) }, 'babycodePreview');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function babycodePreview(payload, _, el) {
|
||||||
|
if (!payload.sender.parentNode.parentNode.contains(el)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!payload.text.trim()) {
|
||||||
|
b.send({ plain: 'Type something to get a preview.', sender: el }, 'showBabycodePreview');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
markup: payload.text,
|
||||||
|
banned_tags: payload.bannedTags,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
const f = await fetch(b.babycodePreviewEndpoint, options);
|
||||||
|
try {
|
||||||
|
if (!f.ok) {
|
||||||
|
console.error(f);
|
||||||
|
let msg = '';
|
||||||
|
switch (f.status) {
|
||||||
|
case 429:
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
msg = '(Something went wrong. Try again later.)'
|
||||||
|
}
|
||||||
|
b.send({ plain: msg, sender: el }, 'showBabycodePreview');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
b.send({ ...(await f.json()), sender: el }, 'showBabycodePreview');
|
||||||
|
} catch (error) {
|
||||||
|
b.send({ plain: '(Something went wrong. Try again later.)', sender: el }, 'showBabycodePreview');
|
||||||
|
console.error(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showBabycodePreview(payload, _, el) {
|
||||||
|
if (!payload.sender.parentNode.contains(el)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload.plain) {
|
||||||
|
el.innerHTML = `<p>${payload.plain}</p>`;
|
||||||
|
} else {
|
||||||
|
el.innerHTML = payload.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user