diff --git a/bukuserver/requirements.txt b/bukuserver/requirements.txt
index e19a983d..454ee6c9 100644
--- a/bukuserver/requirements.txt
+++ b/bukuserver/requirements.txt
@@ -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
diff --git a/bukuserver/static/bukuserver/css/bookmark.css b/bukuserver/static/bukuserver/css/bookmark.css
index 7e99b829..24d79e7a 100644
--- a/bukuserver/static/bukuserver/css/bookmark.css
+++ b/bukuserver/static/bukuserver/css/bookmark.css
@@ -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;
+}
.description {
white-space: pre-wrap;
diff --git a/bukuserver/templates/bukuserver/bookmark_details.html b/bukuserver/templates/bukuserver/bookmark_details.html
index 6f677456..ea728c0e 100644
--- a/bukuserver/templates/bukuserver/bookmark_details.html
+++ b/bukuserver/templates/bukuserver/bookmark_details.html
@@ -4,7 +4,7 @@
{% block tail %}
{{ super() }}
{{ buku.limit_navigation_if_popup() }}
- {{ buku.details_formatting() }}
+ {{ buku.details_formatting('.table.searchable') }}
{{ buku.link_saved() }}
{% endblock %}
diff --git a/bukuserver/templates/bukuserver/lib.html b/bukuserver/templates/bukuserver/lib.html
index 0c793abf..4fe43eec 100644
--- a/bukuserver/templates/bukuserver/lib.html
+++ b/bukuserver/templates/bukuserver/lib.html
@@ -41,14 +41,9 @@
{% endmacro %}
{% macro details_formatting(prefix='') %}
-
+
{% endmacro %}
{% macro link_saved() %}
diff --git a/bukuserver/views.py b/bukuserver/views.py
index 4bc717bd..b0b31cac 100644
--- a/bukuserver/views.py
+++ b/bukuserver/views.py
@@ -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)
+
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' ']
title = model.title or ''
- 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'{"".join(tags)}
')
+ if name == 'url':
+ res, netloc, scheme = [], (parsed := urlparse(value)).netloc, parsed.scheme
+ if netloc and not app_param('DISABLE_FAVICON', False):
+ icon = f''
+ res += [link(icon, url_for('bookmark.index_view', flt0_url_netloc_match=netloc), html=True)]
+ elif netloc:
+ badge = f'netloc:{escape(netloc)}'
+ 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'))]
+ return Markup(f'{" ".join(res)}
')
+ return Markup(f'{escape(value)}
')
+
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'{escape(text)}'
+ return f'{text if html else escape(text)}'
def sorted_counter(keys, *, min_count=0):
data = Counter(keys)
diff --git a/setup.py b/setup.py
index da5e8f19..a8ce9b72 100644
--- a/setup.py
+++ b/setup.py
@@ -43,6 +43,7 @@
"flask-paginate>=2022.1.8",
"Flask-WTF>=1.0.1",
"Flask>=2.2.2,<2.3",
+ "Jinja2>=3",
"werkzeug<2.4",
]
install_requires = [