Compare commits
9 Commits
6b7a0e7a17
...
cd3fce17ae
| Author | SHA1 | Date | |
|---|---|---|---|
|
cd3fce17ae
|
|||
|
572e6e86c4
|
|||
|
0224e2e390
|
|||
|
27314f34a5
|
|||
|
daf205f200
|
|||
|
687d72e5ab
|
|||
|
ed395a0175
|
|||
|
160629fca7
|
|||
|
d2ea0bbd51
|
@@ -149,6 +149,13 @@ def clear_stale_sessions():
|
||||
for sess in stale_sessions:
|
||||
sess.delete()
|
||||
|
||||
def clear_api_limits():
|
||||
from .db import db
|
||||
from .models import APIRateLimits
|
||||
with db.transaction():
|
||||
limits = APIRateLimits.select()
|
||||
for l in limits:
|
||||
l.delete()
|
||||
|
||||
cache = Cache()
|
||||
|
||||
@@ -203,12 +210,14 @@ def create_app():
|
||||
from app.routes.guides import bp as guides_bp
|
||||
from app.routes.mod import bp as mod_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(threads_bp)
|
||||
app.register_blueprint(users_bp)
|
||||
app.register_blueprint(guides_bp)
|
||||
app.register_blueprint(mod_bp)
|
||||
app.register_blueprint(posts_bp)
|
||||
app.register_blueprint(api_bp)
|
||||
|
||||
with app.app_context():
|
||||
from .schema import create as create_tables
|
||||
@@ -221,6 +230,7 @@ def create_app():
|
||||
create_deleted_user()
|
||||
|
||||
clear_stale_sessions()
|
||||
clear_api_limits()
|
||||
|
||||
reparse_babycode()
|
||||
|
||||
@@ -318,6 +328,15 @@ def create_app():
|
||||
else:
|
||||
return render_template('common/404.html'), e.code
|
||||
|
||||
@app.errorhandler(405)
|
||||
def _handle_405(e):
|
||||
if request.path.startswith('/hyperapi/'):
|
||||
return '<h1>method not allowed</h1>', e.code
|
||||
elif request.path.startswith('/api/'):
|
||||
return {'error': 'method not allowed'}, e.code
|
||||
else:
|
||||
return render_template('common/404.html'), e.code
|
||||
|
||||
@app.errorhandler(403)
|
||||
def _handle_403(e):
|
||||
if request.path.startswith('/hyperapi/'):
|
||||
|
||||
@@ -105,6 +105,14 @@ def login_required(view_func):
|
||||
return view_func(*args, **kwargs)
|
||||
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):
|
||||
@wraps(view_func)
|
||||
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}
|
||||
@@ -62,7 +62,7 @@ def thread(thread_id, slug):
|
||||
user = get_active_user()
|
||||
if user:
|
||||
subscription = Subscriptions.find({'user_id': user.id, 'thread_id': thread.id})
|
||||
if subscription:
|
||||
if subscription and last_post['created_at'] > int(subscription.last_seen):
|
||||
subscription.update({'last_seen': last_post['created_at']})
|
||||
return render_template(
|
||||
'threads/thread.html', thread=thread,
|
||||
@@ -82,13 +82,16 @@ def reply(thread_id):
|
||||
if not user.can_post_to_thread_or_topic(thread):
|
||||
return redirect(url_for('.thread_by_id', thread_id=thread_id))
|
||||
post = Posts.new(user.id, thread.id, request.form.get('babycode_content'))
|
||||
subscription = Subscriptions.find({'user_id': user.id, 'thread_id': thread.id})
|
||||
if get_form_checkbox('subscribe'):
|
||||
if not Subscriptions.find({'user_id': user.id, 'thread_id': thread.id}):
|
||||
Subscriptions.create({
|
||||
if not subscription:
|
||||
subscription = Subscriptions.create({
|
||||
'user_id': user.id,
|
||||
'thread_id': thread.id,
|
||||
'last_seen': time_now(),
|
||||
})
|
||||
if subscription and subscription.last_seen < time_now():
|
||||
subscription.update({'last_seen': time_now()})
|
||||
return redirect(url_for('.thread_by_id', thread_id=thread_id, after=post.id, _anchor=f'post-{post.id}'))
|
||||
|
||||
@bp.get('/<int:thread_id>/edit/')
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
{%- endif -%}
|
||||
</head>
|
||||
<body>
|
||||
<bitty-8 data-connect="/static/js/bits/progressive-enhancement.js"></bitty-8>
|
||||
<bitty-8 data-connect="/static/js/bits/ui.js"></bitty-8>
|
||||
{%- include 'common/topnav.html' -%}
|
||||
{%- with messages = get_flashed_messages(with_categories=true) -%}
|
||||
{%- if messages -%}
|
||||
@@ -23,6 +25,7 @@
|
||||
{%- endwith -%}
|
||||
{%- block content -%}{%- endblock -%}
|
||||
{%- include 'common/footer.html' -%}
|
||||
<script type="module" src="/static/js/vnd/bitty-8.0.0.js"></script>
|
||||
<script src="{{'/static/js/ui.js' | cachebust}}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -72,15 +72,15 @@
|
||||
</span>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro tabs(prefix='', labels = []) -%}
|
||||
<div class="tab-container">
|
||||
{% macro tabs(prefix='', labels=[], signal_ss=[], signal_rs=[]) -%}
|
||||
<div class="tab-container" data-r="setTab">
|
||||
<div class="tab-bar" role="tablist">
|
||||
{%- 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>{{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 -%}
|
||||
</div>
|
||||
{%- 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) -}}
|
||||
</div>
|
||||
{%- endfor -%}
|
||||
@@ -94,24 +94,25 @@
|
||||
id='babycode-content',
|
||||
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 -%}
|
||||
<span class="babycode-editor-controls">
|
||||
<span class="button-row">
|
||||
<button type="button" class="minimal" disabled><b>B</b></button>
|
||||
<button type="button" class="minimal" disabled><i>i</i></button>
|
||||
<button type="button" class="minimal" disabled><s>S</s></button>
|
||||
<button type="button" class="minimal" disabled><u>U</u></button>
|
||||
<button type="button" class="minimal" disabled><code>://</code></button>
|
||||
<button type="button" class="minimal" disabled><code></></code></button>
|
||||
<button type="button" class="minimal" disabled>1.</button>
|
||||
<button type="button" class="minimal" disabled>•</button>
|
||||
<button type="button" class="minimal" disabled><img src="/static/emoji/angry.png" class="emoji"></button>
|
||||
<span class="button-row js-only" data-r="enhance">
|
||||
<button type="button" title="insert bold" class="minimal" data-babycode-tag="b" data-s="insertBabycode"><b>B</b></button>
|
||||
<button type="button" title="insert italic" class="minimal" data-babycode-tag="i" data-s="insertBabycode"><i>i</i></button>
|
||||
<button type="button" title="insert strikethrough" class="minimal" data-babycode-tag="s" data-s="insertBabycode"><s>S</s></button>
|
||||
<button type="button" title="insert underline" class="minimal" data-babycode-tag="u" data-s="insertBabycode"><u>U</u></button>
|
||||
<button type="button" title="insert link" class="minimal" data-babycode-tag="url" data-prefill="link label" data-s="insertBabycode"><code>://</code></button>
|
||||
<button type="button" title="insert code block" class="minimal" data-babycode-tag="code" data-break-line data-s="insertBabycode"><code></></code></button>
|
||||
<button type="button" title="insert ordered list" class="minimal" data-babycode-tag="ol" data-break-line data-s="insertBabycode">1.</button>
|
||||
<button type="button" title="insert unordered list" class="minimal" data-babycode-tag="ul" data-break-line data-s="insertBabycode">•</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>
|
||||
</span>
|
||||
<span class="flex-last">{# stub: char count #}</span>
|
||||
<span class="flex-last js-only" data-r="enhance babycodeEditorCharCount">stub: char count</span>
|
||||
</span>
|
||||
<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">{{ 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 babycodeEditorCharCountInit" data-listeners="input" data-s="babycodeEditorCharCount" data-banned-tags="{{banned_tags | unique | list | tojson | forceescape}}">{{ prefill }}</textarea>
|
||||
{%- if banned_tags -%}
|
||||
<div>
|
||||
<span>Forbidden tags:</span>
|
||||
@@ -123,6 +124,8 @@
|
||||
</div>
|
||||
{%- endif -%}
|
||||
<a href="##">babycode help</a>
|
||||
{%- else -%}
|
||||
<div data-r="showBabycodePreview"></div>
|
||||
{%- endif -%}
|
||||
{%- endcall -%}
|
||||
{%- endmacro %}
|
||||
@@ -183,12 +186,12 @@
|
||||
<a class="linkbutton" href="{{url_for('posts.edit', post_id=post.id, _anchor='babycode-content')}}">Edit</a>
|
||||
{%- endif -%}
|
||||
{%- if can_reply -%}
|
||||
<button disabled title="This feature requires JavaScript to be enabled.">Quote</button>
|
||||
<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">Quote</button>
|
||||
{%- endif -%}
|
||||
{%- if can_delete -%}
|
||||
<a class="linkbutton critical" href="{{url_for('posts.delete', post_id=post.id)}}">Delete</a>
|
||||
{%- endif -%}
|
||||
<button disabled title="This feature requires JavaScript to be enabled.">{{icn_bookmark(24)}}Bookmark…</button>
|
||||
<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">{{icn_bookmark(24)}}Bookmark…</button>
|
||||
</span>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
@@ -213,10 +216,10 @@
|
||||
{% set reactors_str = reactors_str + '\n...and many others' %}
|
||||
{% endif %}
|
||||
{% set has_reacted = get_active_user() is not none and get_active_user().username in reactors %}
|
||||
<button type="button" disabled title="{{reactors_str}}" class="minimal {{'alt' if has_reacted else ''}}"><img src="/static/emoji/{{reaction.reaction_text}}.png">{{reaction.c}}</button>
|
||||
<button data-r="enhance" type="button" disabled title="{{reactors_str}}" class="minimal {{'alt' if has_reacted else ''}}"><img src="/static/emoji/{{reaction.reaction_text}}.png">{{reaction.c}}</button>
|
||||
{%- endfor -%}
|
||||
</span>
|
||||
{%- if is_logged_in() and allow_reacting -%}<button disabled title="This feature requires JavaScript to be enabled.">Add reaction</button>{%- endif -%}
|
||||
{%- if is_logged_in() and allow_reacting -%}<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">Add reaction</button>{%- endif -%}
|
||||
{%- elif is_editing -%}
|
||||
<input type="submit" value="Save">
|
||||
<a href="{{get_post_url(post.id, _anchor=true)}}" class="linkbutton warn">Cancel</a>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<input type="submit" value="Clear MOTD" class="warn">
|
||||
</form>
|
||||
</fieldset>
|
||||
{{babycode_editor_component(placeholder='test', id='test-content')}}
|
||||
<fieldset class="plank" id="sort-topics">
|
||||
<legend>Sort topics</legend>
|
||||
<p>Drag topics around to reorder them. Press "Save order" when done.</p>
|
||||
|
||||
@@ -263,7 +263,7 @@ a.site-title {
|
||||
--rotation: 180deg;
|
||||
padding: var(--medium-padding) var(--huge-padding);
|
||||
|
||||
background: linear-gradient(var(--rotation), var(--lighter-color) 0%, var(--main-color) 30%, var(--main-color) 70%, var(--darker-color) 100%);
|
||||
background: linear-gradient(var(--rotation), var(--lighter-color) 0%, var(--main-color) 40px, var(--main-color) calc(100% - 40px), var(--darker-color) 100%);
|
||||
background-color: var(--main-color);
|
||||
|
||||
border: 2px groove var(--border-color);
|
||||
@@ -905,6 +905,9 @@ ol.sortable-list {
|
||||
}
|
||||
}
|
||||
|
||||
.js-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body {
|
||||
@@ -928,9 +931,9 @@ ol.sortable-list {
|
||||
min-height: 140px;
|
||||
}
|
||||
|
||||
.usercard-inner {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.usercard-inner:has(.usercard-rest) {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
}
|
||||
|
||||
.thread-title-counter {
|
||||
|
||||
16
data/static/js/bits/progressive-enhancement.js
Normal file
16
data/static/js/bits/progressive-enhancement.js
Normal file
@@ -0,0 +1,16 @@
|
||||
export const b = {
|
||||
init: 'enhance',
|
||||
}
|
||||
|
||||
export function enhance(_, __, el) {
|
||||
if (el.classList.contains('js-only')) {
|
||||
el.classList.remove('js-only');
|
||||
}
|
||||
|
||||
if (el.disabled) {
|
||||
el.disabled = false;
|
||||
if (el.title.search('JavaScript') !== -1) {
|
||||
el.title = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
164
data/static/js/bits/ui.js
Normal file
164
data/static/js/bits/ui.js
Normal file
@@ -0,0 +1,164 @@
|
||||
export const b = {
|
||||
babycodePreviewEndpoint: '/api/babycode-preview/',
|
||||
init: 'babycodeEditorCharCountInit',
|
||||
}
|
||||
|
||||
export function setTab(_, sender, el) {
|
||||
if (sender.ariaSelected === 'true') {
|
||||
return;
|
||||
}
|
||||
if (!el.contains(sender)) {
|
||||
return;
|
||||
}
|
||||
const tabIndex = parseInt(sender.dataset.tabIndex);
|
||||
const tabPanels = el.querySelectorAll('.tab-content');
|
||||
const tabButtons = el.querySelectorAll('.tab-bar button');
|
||||
|
||||
for (let i = 0; i < tabPanels.length; i++) {
|
||||
const tabPanel = tabPanels[i];
|
||||
const tabButton = tabButtons[i];
|
||||
if (i === tabIndex) {
|
||||
tabPanel.classList.remove('hidden');
|
||||
tabButton.ariaSelected = 'true';
|
||||
} else if (!tabPanel.classList.contains('hidden')) {
|
||||
tabPanel.classList.add('hidden');
|
||||
tabButton.ariaSelected = 'false';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function insertBabycode(_, sender, el) {
|
||||
if (!el.parentNode.contains(sender)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagStart = sender.dataset.babycodeTag;
|
||||
const breakLine = 'breakLine' in sender.dataset;
|
||||
const prefill = 'prefill' in sender.dataset ? sender.dataset.prefill : '';
|
||||
|
||||
const hasAttr = tagStart[tagStart.length - 1] === '=';
|
||||
|
||||
let tagEnd = tagStart;
|
||||
let tagInsertStart = `[${tagStart}]${breakLine ? '\n' : ''}`;
|
||||
if (hasAttr) {
|
||||
tagEnd = tagEnd.slice(0, -1);
|
||||
}
|
||||
const tagInsertEnd = `${breakLine ? '\n' : ''}[/${tagEnd}]`;
|
||||
const hasSelection = el.selectionStart !== el.selectionEnd;
|
||||
const text = el.value;
|
||||
|
||||
if (hasSelection) {
|
||||
const realStart = Math.min(el.selectionStart, el.selectionEnd);
|
||||
const realEnd = Math.max(el.selectionStart, el.selectionEnd);
|
||||
const selectionLength = realEnd - realStart;
|
||||
|
||||
const strStart = text.slice(0, realStart);
|
||||
const strEnd = text.substring(realEnd);
|
||||
const frag = `${tagInsertStart}${text.slice(realStart, realEnd)}${tagInsertEnd}`;
|
||||
const reconst = `${strStart}${frag}${strEnd}`;
|
||||
el.value = reconst;
|
||||
if (!hasAttr) {
|
||||
el.setSelectionRange(realStart + tagInsertStart.length, realStart + tagInsertEnd.length + selectionLength - 1);
|
||||
} else {
|
||||
const attrCursor = realStart + tagInsertEnd.length - (1 + (breakLine ? 1 : 0))
|
||||
el.setSelectionRange(attrCursor, attrCursor); // cursor on attr
|
||||
}
|
||||
} else {
|
||||
if (hasAttr) {
|
||||
tagInsertStart += prefill;
|
||||
}
|
||||
const cursor = el.selectionStart;
|
||||
const strStart = text.slice(0, cursor);
|
||||
const strEnd = text.substring(cursor);
|
||||
|
||||
let newCursor = strStart.length + tagInsertStart.length;
|
||||
if (hasAttr) {
|
||||
newCursor = cursor + tagInsertStart.length - prefill.length - (1 + (breakLine ? 1 : 0)); //cursor on attr
|
||||
}
|
||||
const reconst = `${strStart}${tagInsertStart}${tagInsertEnd}${strEnd}`;
|
||||
el.value = reconst;
|
||||
el.setSelectionRange(newCursor, newCursor);
|
||||
}
|
||||
el.focus();
|
||||
b.send({ sender: el }, 'babycodeEditorCharCount');
|
||||
}
|
||||
|
||||
export function babycodeEditorCharCount(evOrPayload, sender, el) {
|
||||
if (!sender) { // sent from bitty, not input
|
||||
sender = evOrPayload.sender;
|
||||
}
|
||||
|
||||
if (!sender.parentNode.contains(el)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxLength = sender.maxLength;
|
||||
const currentLength = sender.value.length;
|
||||
|
||||
el.innerText = `${currentLength}/${maxLength}`
|
||||
}
|
||||
|
||||
export function babycodeEditorCharCountInit(_, __, el) {
|
||||
b.send({ sender: el }, 'babycodeEditorCharCount');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
1
data/static/js/vnd/bitty-8.0.0.js
Normal file
1
data/static/js/vnd/bitty-8.0.0.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user