-
-
Notifications
You must be signed in to change notification settings - Fork 294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improving bookmark details view #771
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,5 @@ Flask-API>=3.0.post1 | |
flask-paginate>=2022.1.8 | ||
Flask-WTF>=1.0.1 | ||
Flask>=2.2.2,<2.3 | ||
Jinja2>=3 | ||
werkzeug<2.4 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,11 +15,16 @@ table tr td:not(:first-child) { | |
} | ||
|
||
.tag-list { | ||
font-size: larger; | ||
display: flex; | ||
gap: 1px; | ||
flex-wrap: wrap; | ||
} | ||
.tag-list, .link .netloc { | ||
font-size: larger; | ||
} | ||
.tag-list a, .link .netloc, .select2-search-choice > *, .select2-result-label { | ||
white-space: pre; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensuring correct spacing within tags |
||
|
||
.description { | ||
white-space: pre-wrap; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,14 +41,9 @@ | |
{% endmacro %} | ||
|
||
{% macro details_formatting(prefix='') %} | ||
<script>{ | ||
$(`{{prefix}} td:nth-child(2)`).html((_, s) => s.trim().replaceAll('\n', '<br/>')); | ||
{%- if session.pop('netloc', None) %} | ||
const NEW_TAB = {{ config.get('BUKUSERVER_OPEN_IN_NEW_TAB', False)|tojson }}; | ||
const TARGET = (!NEW_TAB && !document.body.matches('.popup') ? '' : ' target="_blank"'); | ||
$(`{{prefix}} td:contains({{ _gettext('Url') | tojson }}) + td`).html((_, s) => `<a href="${s.replaceAll('"', '"')}"${TARGET}>${s}</a>`); | ||
{%- endif %} | ||
}</script> | ||
<script> | ||
$(`body.popup {{prefix}} a`).attr('target', '_blank'); | ||
</script> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding |
||
{% endmacro %} | ||
|
||
{% macro link_saved() %} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
|
||
import arrow | ||
import wtforms | ||
from jinja2 import pass_context | ||
from flask import current_app, flash, redirect, request, session, url_for | ||
from flask_admin.babel import gettext | ||
from flask_admin.base import AdminIndexView, BaseView, expose | ||
|
@@ -73,8 +74,11 @@ def last_page(self): | |
return redirect(url_for('.index_view', **args)) | ||
|
||
|
||
def app_param(key, default=None): | ||
return current_app.config.get(f'BUKUSERVER_{key}', default) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A convenient shorthand |
||
|
||
def readonly_check(self): | ||
if current_app.config.get("BUKUSERVER_READONLY", False): | ||
if app_param('READONLY'): | ||
self.can_create = False | ||
self.can_edit = False | ||
self.can_delete = False | ||
|
@@ -110,10 +114,10 @@ def _list_entry(self, context: Any, model: Namespace, name: str) -> Markup: | |
netloc = parsed_url.netloc | ||
get_index_view_url = functools.partial(url_for, "bookmark.index_view") | ||
res = [] | ||
if netloc and not current_app.config.get("BUKUSERVER_DISABLE_FAVICON", False): | ||
if netloc and not app_param('DISABLE_FAVICON'): | ||
res += [f'<img class="favicon" src="http://www.google.com/s2/favicons?domain={netloc}"/> '] | ||
title = model.title or '<EMPTY TITLE>' | ||
new_tab = current_app.config.get("BUKUSERVER_OPEN_IN_NEW_TAB", False) | ||
new_tab = app_param('OPEN_IN_NEW_TAB') | ||
url_for_index_view_netloc = None | ||
if netloc: | ||
url_for_index_view_netloc = get_index_view_url(flt0_url_netloc_match=netloc) | ||
|
@@ -138,6 +142,25 @@ def _list_entry(self, context: Any, model: Namespace, name: str) -> Markup: | |
res += [description] | ||
return Markup("".join(res)) | ||
|
||
@pass_context | ||
def get_detail_value(self, context, model, name): | ||
value = super().get_detail_value(context, model, name) | ||
if name == 'tags': | ||
tags = (link(s.strip(), url_for('bookmark.index_view', flt0_tags_contain=s.strip()), badge='default') | ||
for s in (value or '').split(',') if s.strip()) | ||
return Markup(f'<div class="tag-list">{"".join(tags)}</div>') | ||
if name == 'url': | ||
res, netloc, scheme = [], (parsed := urlparse(value)).netloc, parsed.scheme | ||
if netloc and not app_param('DISABLE_FAVICON', False): | ||
icon = f'<img class="favicon" title="netloc:{netloc}" src="http://www.google.com/s2/favicons?domain={netloc}"/>' | ||
res += [link(icon, url_for('bookmark.index_view', flt0_url_netloc_match=netloc), html=True)] | ||
elif netloc: | ||
badge = f'<span class="netloc">netloc:{escape(netloc)}</span>' | ||
res += [link(badge, url_for('bookmark.index_view', flt0_url_netloc_match=netloc), html=True, badge='success')] | ||
res += [escape(value) if not scheme else link(value, value, new_tab=app_param('OPEN_IN_NEW_TAB'))] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reproduces current logic for rendering URL as a hyperlink within |
||
return Markup(f'<div class="link">{" ".join(res)}</div>') | ||
return Markup(f'<div class="{name}">{escape(value)}</div>') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Overriding a method that renders value cell contents in details view |
||
|
||
can_set_page_size = True | ||
can_view_details = True | ||
column_filters = ["buku", "id", "url", "title", "tags"] | ||
|
@@ -168,11 +191,11 @@ def __init__(self, bukudb: buku.BukuDb, *args, **kwargs): | |
|
||
@property | ||
def page_size(self): | ||
return current_app.config.get('BUKUSERVER_PER_PAGE', DEFAULT_PER_PAGE) | ||
return app_param('PER_PAGE', DEFAULT_PER_PAGE) | ||
|
||
@property | ||
def url_render_mode(self): | ||
return current_app.config.get('BUKUSERVER_URL_RENDER_MODE', DEFAULT_URL_RENDER_MODE) | ||
return app_param('URL_RENDER_MODE', DEFAULT_URL_RENDER_MODE) | ||
|
||
def create_form(self, obj=None): | ||
form = super().create_form(obj) | ||
|
@@ -421,7 +444,7 @@ def __init__(self, bukudb, *args, **kwargs): | |
|
||
@property | ||
def page_size(self): | ||
return current_app.config.get('BUKUSERVER_PER_PAGE', DEFAULT_PER_PAGE) | ||
return app_param('PER_PAGE', DEFAULT_PER_PAGE) | ||
|
||
@expose('/refresh', methods=['POST']) | ||
def refresh(self): | ||
|
@@ -603,10 +626,10 @@ def format_value(field, bookmark, spacing=''): | |
s = bookmark[field.value] | ||
return s if field != BookmarkField.TAGS else (s or '').strip(',').replace(',', ','+spacing) | ||
|
||
def link(text, url, new_tab=False, badge=''): | ||
def link(text, url, new_tab=False, html=False, badge=''): | ||
target = ('' if not new_tab else ' target="_blank"') | ||
cls = ('' if not badge else f' class="btn label label-{badge}"') | ||
return f'<a{cls} href="{escape(url)}"{target}>{escape(text)}</a>' | ||
return f'<a{cls} href="{escape(url)}"{target}>{text if html else escape(text)}</a>' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Supporting non-plain-text hyperlinks |
||
|
||
def sorted_counter(keys, *, min_count=0): | ||
data = Counter(keys) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensuring Jinja version (
pass_content
is the name used since v3.0)