From 5dbd487fb7e64aa968da9c3fcbe8a0215d2b3298 Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 28 Jul 2023 16:12:33 +0200 Subject: [PATCH] thema chooser --- src/catalogue/urls.py | 3 + src/catalogue/views.py | 80 ++++++++++++++++++- src/redakcja/settings/__init__.py | 2 +- .../static/css/{dialogs.css => dialogs.scss} | 19 ++++- .../static/js/wiki/view_properties.js | 63 +++++++++++++++ src/wiki/templates/wiki/document_details.html | 1 + src/wiki/templates/wiki/meta_chooser.html | 13 +++ src/wlxml/views.py | 10 ++- 8 files changed, 183 insertions(+), 8 deletions(-) rename src/redakcja/static/css/{dialogs.css => dialogs.scss} (65%) create mode 100644 src/wiki/templates/wiki/meta_chooser.html diff --git a/src/catalogue/urls.py b/src/catalogue/urls.py index d512eea0..e0b1a507 100644 --- a/src/catalogue/urls.py +++ b/src/catalogue/urls.py @@ -23,6 +23,9 @@ urlpatterns = [ path('terms/editor/', views.EditorTerms.as_view()), + path('chooser/thema/', views.ThemaChooser.as_view()), + path('chooser/thema-main/', views.MainThemaChooser.as_view()), + path('wikidata//', views.WikidataView.as_view()), path('publish/author//', views.publish_author, name='catalogue_publish_author'), diff --git a/src/catalogue/views.py b/src/catalogue/views.py index 44ad3058..697a5acf 100644 --- a/src/catalogue/views.py +++ b/src/catalogue/views.py @@ -92,7 +92,7 @@ class BookAPIView(RetrieveAPIView): 'original_year', 'pd_year', ] - + class TermSearchFilter(SearchFilter): search_param = 'term' @@ -135,7 +135,7 @@ class EditorTerms(Terms): def get_label(self, obj): return f'{obj.last_name}, {obj.first_name}' - + class BookTitleTerms(Terms): queryset = models.Book.objects.all() search_fields = ['title', 'slug'] @@ -146,7 +146,7 @@ class BookTitleTerms(Terms): class WLURITerms(Terms): queryset = models.Book.objects.all() search_fields = ['title', 'slug'] - + class serializer_class(serializers.Serializer): label = serializers.CharField(source='wluri') @@ -163,6 +163,78 @@ class MainThemaTerms(ThemaTerms): queryset = models.Thema.objects.filter(usable=True, hidden=False, usable_as_main=True) + +class Chooser(APIView): + def get(self, request): + return Response([{ + 'value': 'x', + 'name': 'name', + 'description': 'desc', + 'sub': [ + { + 'value': 'y', + 'name': 'name y', + 'description': 'desc y', + } + ] + }]) + + +class ThemaChooser(Chooser): + queryset = models.Thema.objects.filter(usable=True, hidden=False) + + def get(self, request): + tree = {} + + def getitem(code): + if len(code) == 1: + parent = tree + else: + parent = getitem(code[:-1]).setdefault('sub', {}) + return parent.setdefault(code, {}) + + def getmissing(t): + for k, v in t.items(): + if 'name' not in v: + yield k + if 'sub' in v: + for c in getmissing(v['sub']): + yield c + + def populate(thema): + item = getitem(thema.code) + item['usable'] = thema.usable + item['hidden'] = thema.hidden + item['name'] = thema.name + item['description'] = thema.description + + def order(tree): + res = [] + for k, v in tree.items(): + v.update(value=k) + if 'sub' in v: + v['sub'] = order(v['sub']) + res.append(v) + while len(res) == 1 and 'name' not in res[0] and 'sub' in res[0]: + res = res[0]['sub'] + return res + + for thema in self.queryset.all(): + populate(thema) + + missing = list(getmissing(tree)) + for thema in models.Thema.objects.filter(code__in=missing): + populate(thema) + + tree = order(tree) + + return Response(tree) + + +class MainThemaChooser(ThemaChooser): + queryset = models.Thema.objects.filter(usable=True, hidden=False, usable_as_main=True)[:1000] + + class WikidataView(APIView): permission_classes = [IsAdminUser] @@ -218,7 +290,7 @@ class WikidataView(APIView): else: d[fieldname] = localize_input(d[fieldname]) return Response(d) - + def get(self, request, model, qid): return self.get_object(model, qid, save=False) diff --git a/src/redakcja/settings/__init__.py b/src/redakcja/settings/__init__.py index ce3289b0..61a80c87 100644 --- a/src/redakcja/settings/__init__.py +++ b/src/redakcja/settings/__init__.py @@ -153,7 +153,7 @@ PIPELINE = { 'css/history.css', 'css/summary.css', 'css/imgareaselect-default.css', - 'css/dialogs.css', + 'css/dialogs.scss', 'wiki/scss/splitter.scss', 'wiki/scss/visual.scss' diff --git a/src/redakcja/static/css/dialogs.css b/src/redakcja/static/css/dialogs.scss similarity index 65% rename from src/redakcja/static/css/dialogs.css rename to src/redakcja/static/css/dialogs.scss index 1032b138..d19d874e 100644 --- a/src/redakcja/static/css/dialogs.css +++ b/src/redakcja/static/css/dialogs.scss @@ -29,4 +29,21 @@ #save_dialog textarea, #revert_dialog textarea { width: 90%; margin: 0.2em 4%; -} \ No newline at end of file +} + + + +#meta-chooser { + .form-check { + margin: 1em; + } + .meta-chooser_toggle { + position: absolute; + top: 1.5em; + left: 0; + cursor: pointer; + } + .name { + font-weight: bold; + } +} diff --git a/src/redakcja/static/js/wiki/view_properties.js b/src/redakcja/static/js/wiki/view_properties.js index 9fa1c9d2..56bd84d3 100644 --- a/src/redakcja/static/js/wiki/view_properties.js +++ b/src/redakcja/static/js/wiki/view_properties.js @@ -178,6 +178,65 @@ $('#media-chooser').modal('hide'); }); + /* Meta chooser */ + $('#meta-chooser').on('show.bs.modal', function (event) { + let input = $("input", $(event.relatedTarget).closest('.input-group')); + let $fg = $(event.relatedTarget).closest('.form-group'); + let field = $fg.data('field'); + let modal = $(this); + modal.data('target-input', input); + let body = modal.find('.modal-body'); + body.html(''); + + let add_options = function(cnt, options, value) { + $.each(options, (i, item) => { + let elem = $('
'); + if (!item.usable) { + $('input', elem).remove(); + } + if (item.hidden) { + $('input', elem).prop('disabled', 'disabled'); + } + $('input', elem).val(item.value); + $('input', elem).val(item.value); + $('.value', elem).text(item.value); + $('.name', elem).append(item.name); + $('.description', elem).append(item.description); + let valueMatch = value && value.startsWith(item.value); + if (valueMatch) { + $('label', elem).addClass('text-primary') + if (value == item.value) { + $('input', elem).prop('checked', true); + } + } + if (item.sub) { + let subT = $('
+
'); + let sub = $('
'); + elem.append(subT); + elem.append(sub); + subT.on('click', () => { + sub.toggle() + }); + add_options(sub, item.sub, valueMatch ? value : null); + } + elem.appendTo(cnt); + }); + }; + + $.ajax({ + url: field.value_type.chooser.source, + success: function(data) { + add_options(body, data, input.val()); + } + }); + }) + $('#meta-chooser .ctrl-ok').on('click', function (event) { + $('#meta-chooser').data('target-input').val( + $('#meta-chooser :checked').val() + ).trigger('change'); + $('#meta-chooser').modal('hide'); + }); + self.$pane.on('click', '.current-convert', function() { self.convert($(this).attr('data-to')); }); @@ -311,6 +370,10 @@ let ap = $("
"); ap.appendTo(ig); + + if (field.value_type.chooser) { + ap.append($("")); + } $("").appendTo(ap); // lang diff --git a/src/wiki/templates/wiki/document_details.html b/src/wiki/templates/wiki/document_details.html index 214940e0..7236ee22 100644 --- a/src/wiki/templates/wiki/document_details.html +++ b/src/wiki/templates/wiki/document_details.html @@ -60,6 +60,7 @@ {% include "wiki/revert_dialog.html" %} {% include "wiki/media_dialog.html" %} {% include "wiki/gallery_dialog.html" %} + {% include "wiki/meta_chooser.html" %} {% if can_pubmark %} {% include "wiki/pubmark_dialog.html" %} {% endif %} diff --git a/src/wiki/templates/wiki/meta_chooser.html b/src/wiki/templates/wiki/meta_chooser.html new file mode 100644 index 00000000..b7b42a0f --- /dev/null +++ b/src/wiki/templates/wiki/meta_chooser.html @@ -0,0 +1,13 @@ +{% load i18n %} + diff --git a/src/wlxml/views.py b/src/wlxml/views.py index 3784b777..64a49dc8 100644 --- a/src/wlxml/views.py +++ b/src/wlxml/views.py @@ -58,12 +58,18 @@ VALUE_TYPES = { ThemaCategory: { 'autocomplete': { 'source': '/catalogue/terms/thema/', - } + }, + 'chooser': { + 'source': '/catalogue/chooser/thema/', + }, }, MainThemaCategory: { 'autocomplete': { 'source': '/catalogue/terms/thema-main/', - } + }, + 'chooser': { + 'source': '/catalogue/chooser/thema-main/', + }, }, Epoch: { 'autocomplete': { -- 2.20.1