frontend for bookmark menu
This commit is contained in:
@@ -211,6 +211,7 @@ def create_app():
|
|||||||
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
|
from app.routes.api import bp as api_bp
|
||||||
|
from app.routes.hyperapi import bp as hyperapi_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)
|
||||||
@@ -218,6 +219,7 @@ def create_app():
|
|||||||
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)
|
app.register_blueprint(api_bp)
|
||||||
|
app.register_blueprint(hyperapi_bp)
|
||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
from .schema import create as create_tables
|
from .schema import create as create_tables
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ def tag_code(children, attr):
|
|||||||
else:
|
else:
|
||||||
code = input_code
|
code = input_code
|
||||||
|
|
||||||
button = f'<button type=button class="copy-code" data-s="copyCode">Copy</button>'
|
button = f'<button autocomplete=off disabled data-r="enhance" title="This feature requires JavaScript to be enabled." type=button class="copy-code" data-s="copyCode">Copy</button>'
|
||||||
block = f'<fieldset data-r="copyCode" data-code="{input_code}" class="code-block-container plank minimal no-shadow secondary-bg"><legend>{language}</legend>{button}<pre><code>{code}</code></pre></fieldset>'
|
block = f'<fieldset data-r="copyCode" data-code="{input_code}" class="code-block-container plank minimal no-shadow secondary-bg"><legend>{language}</legend>{button}<pre><code>{code}</code></pre></fieldset>'
|
||||||
return block
|
return block
|
||||||
|
|
||||||
|
|||||||
47
app/routes/hyperapi.py
Normal file
47
app/routes/hyperapi.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
from flask import Blueprint, render_template, request, url_for
|
||||||
|
from ..auth import get_active_user, is_logged_in, hard_login_required
|
||||||
|
from ..models import BookmarkCollections
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
bp = Blueprint('hyperapi', __name__, url_prefix='/hyperapi/')
|
||||||
|
|
||||||
|
def user_required(view_func):
|
||||||
|
@wraps(view_func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if get_active_user().is_guest():
|
||||||
|
return '<span>Your account must be approved by a moderator before you may perform this action.</span>', 403
|
||||||
|
return view_func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@bp.get('/bookmarks/dropdown/')
|
||||||
|
@hard_login_required
|
||||||
|
@user_required
|
||||||
|
def get_bookmark_dropdown():
|
||||||
|
user = get_active_user()
|
||||||
|
concept_kind = request.args.get('concept_kind', 'thread')
|
||||||
|
try:
|
||||||
|
concept_id = int(request.args.get('concept_id', 0))
|
||||||
|
except ValueError:
|
||||||
|
return 'error', 400
|
||||||
|
is_thread = concept_kind == 'thread'
|
||||||
|
collections = BookmarkCollections.findall({'user_id': user.id})
|
||||||
|
in_collection = None
|
||||||
|
for collection in collections:
|
||||||
|
callable = collection.has_thread if is_thread else collection.has_post
|
||||||
|
if callable(concept_id):
|
||||||
|
in_collection = collection.id
|
||||||
|
break
|
||||||
|
submit_url = url_for('.bookmark_thread' if is_thread else '.bookmark_post')
|
||||||
|
return render_template('hyper/bookmark_dropdown.html', collections=collections, in_collection=in_collection, is_thread=is_thread, concept_id=concept_id, submit_url=submit_url)
|
||||||
|
|
||||||
|
@bp.post('/bookmarks/thread/')
|
||||||
|
@hard_login_required
|
||||||
|
@user_required
|
||||||
|
def bookmark_thread():
|
||||||
|
return '', 204
|
||||||
|
|
||||||
|
@bp.post('/bookmarks/post/')
|
||||||
|
@hard_login_required
|
||||||
|
@user_required
|
||||||
|
def bookmark_post():
|
||||||
|
return '', 204
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
<span class="flex-last js-only" data-r="enhance babycodeEditorCharCount">stub: char count</span>
|
<span class="flex-last js-only" data-r="enhance babycodeEditorCharCount">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 babycodePreviewInit babycodeEditorCharCountInit babycodeEditorQuote" data-listeners="input" data-s="babycodeEditorCharCount" data-banned-tags="{{banned_tags | unique | list | tojson | forceescape}}">{{ 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 babycodeEditorQuote" data-listen="input" data-s="babycodeEditorCharCount" 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>
|
||||||
@@ -186,12 +186,12 @@
|
|||||||
<a class="linkbutton" href="{{url_for('posts.edit', post_id=post.id, _anchor='babycode-content')}}">Edit</a>
|
<a class="linkbutton" href="{{url_for('posts.edit', post_id=post.id, _anchor='babycode-content')}}">Edit</a>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- if can_reply -%}
|
{%- if can_reply -%}
|
||||||
<button data-r="enhance" data-s="babycodeEditorQuote" disabled title="This feature requires JavaScript to be enabled." data-quote="{{post.original_markup}}" data-poster-name="{{ post.display_name if post.display_name else post.username }}">Quote</button>
|
<button autocomplete='off' data-r="enhance" data-s="babycodeEditorQuote" disabled title="This feature requires JavaScript to be enabled." data-quote="{{post.original_markup}}" data-poster-name="{{ post.display_name if post.display_name else post.username }}">Quote</button>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- if can_delete -%}
|
{%- if can_delete -%}
|
||||||
<a class="linkbutton critical" href="{{url_for('posts.delete', post_id=post.id)}}">Delete</a>
|
<a class="linkbutton critical" href="{{url_for('posts.delete', post_id=post.id)}}">Delete</a>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">{{icn_bookmark(24)}}Bookmark…</button>
|
<button autocomplete='off' data-r="enhance" data-s="showBookmarkMenu" disabled title="This feature requires JavaScript to be enabled." data-concept-kind="post" data-concept-id="{{post.id}}">{{icn_bookmark(24)}}Bookmark…</button>
|
||||||
</span>
|
</span>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</div>
|
</div>
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
<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>
|
<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 -%}
|
{%- endfor -%}
|
||||||
</span>
|
</span>
|
||||||
{%- if is_logged_in() and allow_reacting -%}<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">Add reaction</button>{%- endif -%}
|
{%- if is_logged_in() and allow_reacting -%}<button autocomplete='off' data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">Add reaction</button>{%- endif -%}
|
||||||
{%- elif is_editing -%}
|
{%- elif is_editing -%}
|
||||||
<input type="submit" value="Save">
|
<input type="submit" value="Save">
|
||||||
<a href="{{get_post_url(post.id, _anchor=true)}}" class="linkbutton warn">Cancel</a>
|
<a href="{{get_post_url(post.id, _anchor=true)}}" class="linkbutton warn">Cancel</a>
|
||||||
|
|||||||
23
app/templates/hyper/bookmark_dropdown.html
Normal file
23
app/templates/hyper/bookmark_dropdown.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<form class="full-width" method="POST" action="{{submit_url}}" data-listen="submit" data-s="bookmarkMenuSubmit" data-r="bookmarkMenuSubmit">
|
||||||
|
<input type="hidden" name="concept_id" value="{{concept_id}}">
|
||||||
|
<div class="inline-group bookmark-menu-item">
|
||||||
|
<input data-s="bookmarkMenuResetSavedButton" autocomplete="off" type="radio" name="target_collection" id="collection-none" {{'checked' if in_collection==none else ''}} value="-1">
|
||||||
|
<label class="bookmark-menu-label" for="collection-none">
|
||||||
|
No collection
|
||||||
|
<small>Choose this option to remove this {{'thread' if is_thread else 'post'}} from your bookmarks.</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{%- for collection in collections -%}
|
||||||
|
<div class="inline-group bookmark-menu-item">
|
||||||
|
<input data-s="bookmarkMenuResetSavedButton" autocomplete="off" type="radio" name="target_collection" id="collection-{{collection.id}}" {{'checked' if in_collection==collection.id else ''}} value="{{collection.id}}">
|
||||||
|
{%- set tc = collection.get_threads_count() -%}
|
||||||
|
{%- set pc = collection.get_posts_count() -%}
|
||||||
|
<label class="bookmark-menu-label" for="collection-{{collection.id}}">
|
||||||
|
{{collection.name}}
|
||||||
|
<small>{{tc}} {{'thread' | pluralize(num=tc)}}, {{pc}} {{'post' | pluralize(num=pc)}}</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{%- endfor -%}
|
||||||
|
<input type="submit" value="Save" data-r="bookmarkMenuShowSavedButton bookmarkMenuResetSavedButton">
|
||||||
|
<span class="errors hidden" data-r="bookmarkMenuShowError bookmarkMenuHideError">Something went wrong. Try again later.</span>
|
||||||
|
</form>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<input type="hidden" name="last_post_id" value="{{last_post.id}}">
|
<input type="hidden" name="last_post_id" value="{{last_post.id}}">
|
||||||
<input type="submit" value="{{'Subscribe' if not get_active_user().is_subscribed(thread.id) else 'Unsubscribe'}}">
|
<input type="submit" value="{{'Subscribe' if not get_active_user().is_subscribed(thread.id) else 'Unsubscribe'}}">
|
||||||
</form>
|
</form>
|
||||||
<button data-r="enhance" disabled title="This feature requires JavaScript to be enabled.">{{icn_bookmark(24)}}Bookmark…</button>
|
<button disabled autocomplete='off' data-r="enhance" data-s="showBookmarkMenu" title="This feature requires JavaScript to be enabled." data-concept-kind="thread" data-concept-id="{{thread.id}}">{{icn_bookmark(24)}}Bookmark…</button>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
<a href="{{url_for('threads.feed', thread_id=thread.id)}}" class="linkbutton rss">Subscribe via RSS</a>
|
<a href="{{url_for('threads.feed', thread_id=thread.id)}}" class="linkbutton rss">Subscribe via RSS</a>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -82,6 +82,15 @@
|
|||||||
<button>Stop updates</button>
|
<button>Stop updates</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{%- if is_logged_in() -%}
|
||||||
|
<div id="bookmark-popover" data-r="showBookmarkMenu" class="plank even" popover>
|
||||||
|
<div class="bookmark-menu-header">
|
||||||
|
<span>Bookmark collections</span>
|
||||||
|
<a href="{{url_for('users.bookmarks', username=get_active_user().username)}}">View bookmarks</a>
|
||||||
|
</div>
|
||||||
|
<div class="bookmark-menu-inner" data-r="fillBookmarkMenu">Loading…</div>
|
||||||
|
</div>
|
||||||
|
{%- endif -%}
|
||||||
{%- if is_logged_in() and get_active_user().can_post_to_thread_or_topic(thread) -%}
|
{%- if is_logged_in() and get_active_user().can_post_to_thread_or_topic(thread) -%}
|
||||||
<form action="{{url_for('threads.reply', thread_id=thread.id)}}" method="POST" class="plank post-edit-form" data-listen="submit" data-r="clearThreadDraft" data-s="clearThreadDraft">
|
<form action="{{url_for('threads.reply', thread_id=thread.id)}}" method="POST" class="plank post-edit-form" data-listen="submit" data-r="clearThreadDraft" data-s="clearThreadDraft">
|
||||||
<h2 class="info">Reply to "{{thread.title}}"</h2>
|
<h2 class="info">Reply to "{{thread.title}}"</h2>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Welcome back! No account yet? <a href="{{url_for('users.sign_up')}}">Sign up</a>
|
|||||||
<input type="text" id="username" name="username" autocomplete="username" required>
|
<input type="text" id="username" name="username" autocomplete="username" required>
|
||||||
<label for="password">Password</label>
|
<label for="password">Password</label>
|
||||||
<input type="password" id="password" name="password" autocomplete="current-password" required>
|
<input type="password" id="password" name="password" autocomplete="current-password" required>
|
||||||
<span><input type="checkbox" name="remember" id="remember"> <label for="remember">Remember me</label></span>
|
<div class="inline-group"><input type="checkbox" name="remember" id="remember"> <label for="remember">Remember me</label></div>
|
||||||
<input type="submit" value="Log in">
|
<input type="submit" value="Log in">
|
||||||
</form>
|
</form>
|
||||||
{%- endblock -%}
|
{%- endblock -%}
|
||||||
|
|||||||
@@ -48,10 +48,10 @@
|
|||||||
<input type="text" name="display_name" id="display-name" value="{{user.display_name}}" placeholder="Same as username" pattern="(?:[\w!#$%^*\(\)\-_=+\[\]\{\}\|;:,.?\s]{3,50})?" title="Optional. 3-50 characters, no @, no <>, no &." maxlength="50" autocomplete=off>
|
<input type="text" name="display_name" id="display-name" value="{{user.display_name}}" placeholder="Same as username" pattern="(?:[\w!#$%^*\(\)\-_=+\[\]\{\}\|;:,.?\s]{3,50})?" title="Optional. 3-50 characters, no @, no <>, no &." maxlength="50" autocomplete=off>
|
||||||
<label for="status">Status</label>
|
<label for="status">Status</label>
|
||||||
<input type="text" name="status" id="status" maxlength="100" value="{{user.status}}" placeholder="Will be shown under your username on posts. Max. 100 characters." autocomplete="off">
|
<input type="text" name="status" id="status" maxlength="100" value="{{user.status}}" placeholder="Will be shown under your username on posts. Max. 100 characters." autocomplete="off">
|
||||||
<span>
|
<div class="inline-group">
|
||||||
<input type="checkbox" id="subscribe-by-default" name="subscribe_by_default" {{'' if session['dont_subscribe_by_default'] else 'checked'}} autocomplete="off">
|
<input type="checkbox" id="subscribe-by-default" name="subscribe_by_default" {{'' if session['dont_subscribe_by_default'] else 'checked'}} autocomplete="off">
|
||||||
<label for="subscribe-by-default">Automatically subscribe to thread when responding</label>
|
<label for="subscribe-by-default">Automatically subscribe to thread when responding</label>
|
||||||
</span>
|
</div>
|
||||||
<input type="submit" value="Save">
|
<input type="submit" value="Save">
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@@ -629,9 +629,20 @@ form.full-width {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
&> textarea, &> select, &> input[type="text"], &> input[type="password"] {
|
gap: var(--small-padding);
|
||||||
|
&> textarea, &> select, &> input[type="text"], &> input[type="password"], &> .inline-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&> .inline-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--base-padding);
|
||||||
|
|
||||||
|
&> label {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-explain {
|
.context-explain {
|
||||||
@@ -678,6 +689,42 @@ details.separated {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#bookmark-popover {
|
||||||
|
position: absolute;
|
||||||
|
min-width: 400px;
|
||||||
|
max-width: 400px;
|
||||||
|
max-height: 500px;
|
||||||
|
margin-block: var(--small-padding);
|
||||||
|
margin-inline: 0;
|
||||||
|
padding-inline: var(--medium-padding);
|
||||||
|
|
||||||
|
overflow: scroll;
|
||||||
|
|
||||||
|
.bookmark-menu-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-menu-inner .errors.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-menu-item {
|
||||||
|
padding-block: var(--medium-padding);
|
||||||
|
padding-inline: var(--base-padding);
|
||||||
|
|
||||||
|
&:has(.bookmark-menu-label:hover, input:hover) {
|
||||||
|
background-color: #0001;
|
||||||
|
}
|
||||||
|
.bookmark-menu-label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* babycode tags */
|
/* babycode tags */
|
||||||
.inline-code {
|
.inline-code {
|
||||||
background-color: var(--code-bg-color);
|
background-color: var(--code-bg-color);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function enhance(_, __, el) {
|
|||||||
if (el.disabled) {
|
if (el.disabled) {
|
||||||
el.disabled = false;
|
el.disabled = false;
|
||||||
if (el.title.search('JavaScript') !== -1) {
|
if (el.title.search('JavaScript') !== -1) {
|
||||||
el.title = '';
|
el.removeAttribute('title');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
export const b = {
|
export const b = {
|
||||||
babycodePreviewEndpoint: '/api/babycode-preview/',
|
babycodePreviewEndpoint: '/api/babycode-preview/',
|
||||||
|
bookmarksCollectionEndpoint: '/hyperapi/bookmarks/dropdown/',
|
||||||
init: 'babycodeEditorCharCountInit localizeTimestamps',
|
init: 'babycodeEditorCharCountInit localizeTimestamps',
|
||||||
|
|
||||||
|
bookmarkState: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
const getThreadId = () => {
|
const getThreadId = () => {
|
||||||
@@ -11,6 +14,22 @@ const getThreadId = () => {
|
|||||||
return parseInt(scheme[2]);
|
return parseInt(scheme[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getHTML(endpoint, options = {}) {
|
||||||
|
let query = {};
|
||||||
|
if (options._query !== undefined) {
|
||||||
|
query = options._query;
|
||||||
|
delete options._query;
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new URLSearchParams(query);
|
||||||
|
const res = await fetch(`${endpoint}?${params}`, options);
|
||||||
|
if (!res.ok) {
|
||||||
|
console.error(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { body: await res.text(), status: res.status };
|
||||||
|
}
|
||||||
|
|
||||||
export function setTab(_, sender, el) {
|
export function setTab(_, sender, el) {
|
||||||
if (sender.ariaSelected === 'true') {
|
if (sender.ariaSelected === 'true') {
|
||||||
return;
|
return;
|
||||||
@@ -223,3 +242,101 @@ export function localizeTimestamps(_, __, el) {
|
|||||||
const d = new Date(el.dateTime);
|
const d = new Date(el.dateTime);
|
||||||
el.innerText = d.toLocaleString();
|
el.innerText = d.toLocaleString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showBookmarkMenu(ev, sender, el) {
|
||||||
|
if (b.bookmarkState.state === undefined) {
|
||||||
|
el.addEventListener('toggle', e => {
|
||||||
|
if (e.newState === 'closed') {
|
||||||
|
b.bookmarkState.state = 'closed';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// dismiss if open and last invoker is the same button that opened it
|
||||||
|
if (b.bookmarkState.state === 'open' && b.bookmarkState.invoker === sender) {
|
||||||
|
el.hidePopover();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b.bookmarkState.invoker = sender;
|
||||||
|
b.bookmarkState.state = 'open';
|
||||||
|
b.send({ 'plain': 'Loading…' }, 'fillBookmarkMenu');
|
||||||
|
el.showPopover();
|
||||||
|
const bRect = sender.getBoundingClientRect();
|
||||||
|
const menuRect = el.getBoundingClientRect();
|
||||||
|
const preferredLeft = bRect.right - menuRect.width;
|
||||||
|
const enoughSpace = preferredLeft >= 0;
|
||||||
|
|
||||||
|
const scrollY = window.scrollY;
|
||||||
|
|
||||||
|
if (enoughSpace) {
|
||||||
|
el.style.left = `${preferredLeft}px`;
|
||||||
|
} else {
|
||||||
|
el.style.left = `${bRect.left}px`;
|
||||||
|
}
|
||||||
|
el.style.top = `${bRect.bottom + scrollY}px`;
|
||||||
|
|
||||||
|
const conceptKind = sender.prop('conceptKind');
|
||||||
|
const conceptId = sender.prop('conceptId');
|
||||||
|
|
||||||
|
const bookmarkCollections = await getHTML(b.bookmarksCollectionEndpoint, {
|
||||||
|
_query: {
|
||||||
|
concept_kind: conceptKind,
|
||||||
|
concept_id: conceptId,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
b.send({ 'html': bookmarkCollections.body }, 'fillBookmarkMenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function fillBookmarkMenu(payload, __, el) {
|
||||||
|
if (payload.plain) {
|
||||||
|
el.innerText = payload.plain;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.innerHTML = payload.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function bookmarkMenuSubmit(ev, _, el) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const url = el.action;
|
||||||
|
const body = new URLSearchParams(new FormData(el));
|
||||||
|
const options = { body: body, method: 'POST' };
|
||||||
|
const status = (await getHTML(url, options)).status;
|
||||||
|
|
||||||
|
if (status !== 204) {
|
||||||
|
b.trigger('bookmarkMenuShowError');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
b.trigger('bookmarkMenuShowSavedButton');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bookmarkMenuShowSavedButton(_, __, el) {
|
||||||
|
el.value = 'Saved!';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bookmarkMenuResetSavedButton(_, __, el) {
|
||||||
|
el.value = 'Save';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bookmarkMenuShowError(_, __, el) {
|
||||||
|
if (el === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el.classList.contains('hidden')) {
|
||||||
|
el.classList.remove('hidden');
|
||||||
|
setTimeout(() => { b.trigger('bookmarkMenuHideError') }, 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bookmarkMenuHideError(_, __, el) {
|
||||||
|
if (el === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!el.classList.contains('hidden')) {
|
||||||
|
el.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user