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'') + 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 = [