lino 25.8.2__py3-none-any.whl → 25.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lino/__init__.py +1 -1
- lino/api/dd.py +0 -1
- lino/config/unused/403.html +1 -1
- lino/config/unused/404.html +1 -1
- lino/config/unused/500.html +1 -1
- lino/core/__init__.py +0 -1
- lino/core/actions.py +2 -2
- lino/core/actors.py +10 -2
- lino/core/elems.py +1 -1
- lino/core/fields.py +4 -1
- lino/core/kernel.py +5 -1
- lino/core/model.py +2 -11
- lino/core/renderer.py +2 -2
- lino/core/requests.py +12 -12
- lino/core/site.py +5 -82
- lino/core/store.py +3 -1
- lino/core/urls.py +1 -1
- lino/core/user_types.py +1 -10
- lino/help_texts.py +6 -6
- lino/management/commands/initdb.py +0 -3
- lino/modlib/__init__.py +0 -1
- lino/modlib/bootstrap5/README.txt +2 -0
- lino/modlib/bootstrap5/__init__.py +69 -0
- lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/base.html +9 -4
- lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/detail.html +1 -1
- lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/index.html +1 -1
- lino/modlib/{bootstrap3/config/bootstrap3 → bootstrap5/config/bootstrap5}/table.html +1 -1
- lino/modlib/bootstrap5/models.py +30 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.css +4085 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.css +4084 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-grid.rtl.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.css +597 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.css +594 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-reboot.rtl.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.css +5406 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.css +5397 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap-utilities.rtl.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.css +12043 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.css +12016 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.min.css +6 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/css/bootstrap.rtl.min.css.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.js +6315 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.js.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.min.js +7 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.bundle.min.js.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.js +4450 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.js.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.min.js +7 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.esm.min.js.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.js +4497 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.js.map +1 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.min.js +7 -0
- lino/modlib/bootstrap5/static/bootstrap-5.3.7/js/bootstrap.min.js.map +1 -0
- lino/modlib/{bootstrap3 → bootstrap5}/views.py +12 -117
- lino/modlib/checkdata/choicelists.py +1 -1
- lino/modlib/comments/fixtures/demo2.py +1 -0
- lino/modlib/comments/mixins.py +1 -8
- lino/modlib/comments/models.py +2 -0
- lino/modlib/comments/ui.py +7 -7
- lino/modlib/extjs/__init__.py +2 -4
- lino/modlib/extjs/config/extjs/index.html +1 -1
- lino/modlib/extjs/ext_renderer.py +1 -7
- lino/modlib/extjs/views.py +2 -0
- lino/modlib/help/models.py +1 -12
- lino/modlib/jinja/renderer.py +1 -1
- lino/modlib/linod/mixins.py +3 -2
- lino/modlib/memo/__init__.py +11 -11
- lino/modlib/memo/mixins.py +38 -21
- lino/modlib/memo/models.py +10 -7
- lino/modlib/memo/parser.py +3 -1
- lino/modlib/notify/models.py +6 -9
- lino/modlib/odata/views.py +7 -7
- lino/modlib/publisher/__init__.py +15 -3
- lino/modlib/publisher/choicelists.py +8 -94
- lino/modlib/publisher/config/publisher/page.pub.html +82 -19
- lino/modlib/publisher/fixtures/std.py +14 -1
- lino/modlib/publisher/fixtures/synodalworld.py +3 -1
- lino/modlib/publisher/mixins.py +59 -77
- lino/modlib/publisher/models.py +109 -204
- lino/modlib/publisher/renderer.py +31 -11
- lino/modlib/publisher/ui.py +46 -98
- lino/modlib/publisher/views.py +61 -11
- lino/modlib/system/models.py +3 -2
- lino/modlib/uploads/__init__.py +1 -0
- lino/modlib/uploads/mixins.py +2 -2
- lino/modlib/uploads/models.py +55 -21
- lino/modlib/uploads/ui.py +1 -0
- lino/modlib/uploads/utils.py +2 -2
- lino/modlib/users/__init__.py +2 -3
- lino/modlib/users/actions.py +12 -17
- lino/modlib/users/fixtures/abc.py +20 -0
- lino/modlib/users/mixins.py +6 -6
- lino/modlib/users/models.py +37 -36
- lino/modlib/weasyprint/__init__.py +25 -14
- lino/modlib/weasyprint/choicelists.py +6 -0
- lino/modlib/weasyprint/config/weasyprint/base.weasy.html +43 -27
- lino/utils/diag.py +5 -3
- lino/utils/html.py +103 -0
- lino/utils/mldbc/mixins.py +2 -2
- lino/utils/soup.py +16 -8
- {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/METADATA +1 -1
- {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/RECORD +135 -95
- lino/modlib/bootstrap3/README.txt +0 -2
- lino/modlib/bootstrap3/__init__.py +0 -73
- lino/modlib/bootstrap3/models.py +0 -30
- lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.css +0 -6584
- lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.css.map +0 -1
- lino/modlib/bootstrap3/static/bootstrap-3.3.4/css/bootstrap.min.css +0 -5
- lino/modlib/bootstrap3/static/bootstrap-3.3.4/js/bootstrap.js +0 -2317
- lino/modlib/bootstrap3/static/bootstrap-3.3.4/js/bootstrap.min.js +0 -7
- /lino/modlib/{bootstrap3 → bootstrap5}/renderer.py +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.css +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.css.map +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/css/bootstrap-theme.min.css +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.eot +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.svg +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.ttf +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.woff +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/fonts/glyphicons-halflings-regular.woff2 +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/js/bootstrap_lino.js +0 -0
- /lino/modlib/{bootstrap3/static/bootstrap-3.3.4 → bootstrap5/static/bootstrap-5.3.7}/js/npm.js +0 -0
- {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/WHEEL +0 -0
- {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.8.2.dist-info → lino-25.9.0.dist-info}/licenses/COPYING +0 -0
lino/modlib/notify/models.py
CHANGED
@@ -519,13 +519,10 @@ if remove_after:
|
|
519
519
|
# "You do not have a working installation of the service_identity module: .* Many valid certificate/hostname mappings may be rejected.",
|
520
520
|
# UserWarning)
|
521
521
|
|
522
|
+
if dd.get_plugin_setting("linod", "use_channels", False):
|
522
523
|
|
523
|
-
@dd.receiver(dd.post_ui_save)
|
524
|
-
def notify_panels(sender, instance, ar=None, **kwargs):
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
):
|
529
|
-
return
|
530
|
-
data = get_updatables(instance, ar)
|
531
|
-
send_panel_update(data)
|
524
|
+
@dd.receiver(dd.post_ui_save)
|
525
|
+
def notify_panels(sender, instance, ar=None, **kwargs):
|
526
|
+
if instance.updatable_panels:
|
527
|
+
data = get_updatables(instance, ar)
|
528
|
+
send_panel_update(data)
|
lino/modlib/odata/views.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
2
|
# Copyright 2009-2017 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
|
-
"""Views for `lino.modlib.
|
4
|
+
"""Views for `lino.modlib.bootstrap5`.
|
5
5
|
|
6
6
|
"""
|
7
7
|
from __future__ import division
|
@@ -26,14 +26,14 @@ from lino.core.requests import BaseRequest
|
|
26
26
|
from lino.core.tables import AbstractTable
|
27
27
|
from lino.core.views import action_request
|
28
28
|
from lino.core.utils import navinfo
|
29
|
-
from lino.modlib.
|
29
|
+
from lino.modlib.bootstrap5.views import http_response
|
30
30
|
from lino.utils.html import E
|
31
31
|
|
32
32
|
|
33
33
|
class List(View):
|
34
34
|
def get(self, request, app_label=None, actor=None):
|
35
35
|
ar = action_request(app_label, actor, request, request.GET, True)
|
36
|
-
ar.renderer = settings.SITE.plugins.
|
36
|
+
ar.renderer = settings.SITE.plugins.bootstrap5.renderer
|
37
37
|
|
38
38
|
context = dict(
|
39
39
|
title=ar.get_title(),
|
@@ -53,7 +53,7 @@ class Element(View):
|
|
53
53
|
def get(self, request, app_label=None, actor=None, pk=None):
|
54
54
|
# print(request, app_label, actor, pk)
|
55
55
|
ar = action_request(app_label, actor, request, request.GET, False)
|
56
|
-
ar.renderer = settings.SITE.plugins.
|
56
|
+
ar.renderer = settings.SITE.plugins.bootstrap5.renderer
|
57
57
|
|
58
58
|
navigator = None
|
59
59
|
if pk and pk != "-99999" and pk != "-99998":
|
@@ -160,7 +160,7 @@ class Index(View):
|
|
160
160
|
def get(self, request, *args, **kw):
|
161
161
|
# raise Exception("20171122 {} {}".format(
|
162
162
|
# get_language(), settings.MIDDLEWARE_CLASSES))
|
163
|
-
ui = settings.SITE.plugins.
|
163
|
+
ui = settings.SITE.plugins.bootstrap5
|
164
164
|
# print("20170607", request.user)
|
165
165
|
# assert ui.renderer is not None
|
166
166
|
ar = BaseRequest(
|
@@ -172,7 +172,7 @@ class Index(View):
|
|
172
172
|
|
173
173
|
|
174
174
|
def index_response(ar):
|
175
|
-
ui = settings.SITE.plugins.
|
175
|
+
ui = settings.SITE.plugins.bootstrap5
|
176
176
|
|
177
177
|
main = settings.SITE.get_main_html(ar, front_end=ui)
|
178
178
|
main = ui.renderer.html_text(main)
|
@@ -185,7 +185,7 @@ def index_response(ar):
|
|
185
185
|
# else:
|
186
186
|
# user = request.subst_user or request.user
|
187
187
|
# context.update(ar=ar)
|
188
|
-
return http_response(ar, "
|
188
|
+
return http_response(ar, "bootstrap5/index.html", context)
|
189
189
|
|
190
190
|
|
191
191
|
class Metadata(View):
|
@@ -10,7 +10,7 @@ class Plugin(Plugin):
|
|
10
10
|
"lino.modlib.system", # 'lino.modlib.memo',
|
11
11
|
"lino.modlib.linod",
|
12
12
|
"lino.modlib.jinja",
|
13
|
-
"lino.modlib.
|
13
|
+
"lino.modlib.bootstrap5"
|
14
14
|
]
|
15
15
|
locations: list[tuple[str, str]] = []
|
16
16
|
|
@@ -47,12 +47,23 @@ class Plugin(Plugin):
|
|
47
47
|
for location, table_class in self.locations:
|
48
48
|
yield url(
|
49
49
|
f"^{location}/(?P<pk>.+)$",
|
50
|
+
# f"^{location}/<int:pk>$",
|
50
51
|
views.Element.as_view(table_class=table_class))
|
51
52
|
|
52
53
|
# Only if this is the primary front end:
|
53
|
-
if self.site.kernel.
|
54
|
+
if self.site.kernel.primary_front_end is self:
|
55
|
+
# yield url("^(?P<ref>.*)$", views.Index.as_view())
|
56
|
+
Tree = self.site.models.publisher.Tree
|
57
|
+
from django.db.utils import OperationalError, ProgrammingError
|
58
|
+
# language=self.site.DEFAULT_LANGUAGE.django_code
|
59
|
+
try:
|
60
|
+
for t in Tree.objects.filter(ref__isnull=False):
|
61
|
+
yield url(f"^{t.ref}$", views.Index.as_view(ref=t.ref))
|
62
|
+
except (OperationalError, ProgrammingError):
|
63
|
+
pass
|
54
64
|
yield url("^$", views.Index.as_view())
|
55
|
-
|
65
|
+
yield url('^login$',views.Login.as_view())
|
66
|
+
yield url('^logout$',views.Logout.as_view())
|
56
67
|
|
57
68
|
def setup_main_menu(self, site, user_type, m, ar=None):
|
58
69
|
mg = self.get_menu_group()
|
@@ -63,3 +74,4 @@ class Plugin(Plugin):
|
|
63
74
|
mg = self.get_menu_group()
|
64
75
|
m = m.add_menu(mg.app_label, mg.verbose_name)
|
65
76
|
m.add_action("publisher.SpecialPages")
|
77
|
+
m.add_action("publisher.Trees")
|
@@ -57,42 +57,6 @@ class PublisherBuildMethod(JinjaBuildMethod):
|
|
57
57
|
|
58
58
|
BuildMethods.add_item_instance(PublisherBuildMethod())
|
59
59
|
|
60
|
-
# class PublisherView(dd.Choice):
|
61
|
-
# table_class = None # TODO: rename this to data_view
|
62
|
-
#
|
63
|
-
# def __init__(self, location, table_class, text=None):
|
64
|
-
# self.table_class = table_class
|
65
|
-
# self.publisher_location = location
|
66
|
-
# # model = dd.resolve_model(table_class.model)
|
67
|
-
# # self.model = model
|
68
|
-
# # value = dd.full_model_name(model)
|
69
|
-
# value = str(table_class)
|
70
|
-
# if text is None:
|
71
|
-
# text = format_lazy("{} ({})", location, table_class)
|
72
|
-
# # text = model._meta.verbose_name + ' (%s)' % dd.full_model_name(model)
|
73
|
-
# # text = model._meta.verbose_name + ' (%s.%s)' % (
|
74
|
-
# # text = format_lazy("{} ({})", model._meta.verbose_name, value)
|
75
|
-
# # model.__module__, model.__name__)
|
76
|
-
# name = None
|
77
|
-
# super().__init__(value, text, name)
|
78
|
-
#
|
79
|
-
# def get_publisher_pages(self):
|
80
|
-
# return self.table_class.model.objects.all()
|
81
|
-
|
82
|
-
# class PublisherViews(dd.ChoiceList):
|
83
|
-
# item_class = PublisherView
|
84
|
-
# verbose_name = _("Publisher view")
|
85
|
-
# verbose_name_plural = _("Publisher views")
|
86
|
-
# column_names = "location value name text data_view *"
|
87
|
-
#
|
88
|
-
# @dd.virtualfield(models.CharField(_("Location")))
|
89
|
-
# def location(cls, choice, ar):
|
90
|
-
# return choice.publisher_location
|
91
|
-
#
|
92
|
-
# @dd.virtualfield(models.CharField(_("Data table")))
|
93
|
-
# def data_view(cls, choice, ar):
|
94
|
-
# return choice.table_class
|
95
|
-
|
96
60
|
|
97
61
|
class PublishingState(RegistrableState):
|
98
62
|
# is_published = False
|
@@ -123,60 +87,7 @@ add("20", _("Ready"), "ready", is_public=False)
|
|
123
87
|
add("30", _("Public"), "published", is_public=True)
|
124
88
|
add("40", _("Removed"), "removed", is_public=False)
|
125
89
|
|
126
|
-
# class EntryStates(dd.Workflow):
|
127
|
-
# # verbose_name_plural = _("Enrolment states")
|
128
|
-
# required_roles = dd.login_required(dd.SiteAdmin)
|
129
|
-
# is_public = models.BooleanField(_("Public"), default=False)
|
130
|
-
#
|
131
|
-
# @classmethod
|
132
|
-
# def get_column_names(self, ar):
|
133
|
-
# return "value name text button_text is_public"
|
134
|
-
#
|
135
|
-
# add = EntryStates.add_item
|
136
|
-
# add('10', _("Draft"), 'draft', is_public=False)
|
137
|
-
# add('20', _("Ready"), 'ready', is_public=False)
|
138
|
-
# add('30', _("Public"), 'published', is_public=True)
|
139
|
-
# add('40', _("Cancelled"), 'cancelled', is_public=False)
|
140
|
-
|
141
|
-
|
142
|
-
class PageFiller(Choice):
|
143
|
-
data_view = None
|
144
|
-
|
145
|
-
def __init__(self, data_view, *args, **kwargs):
|
146
|
-
self.data_view = data_view
|
147
|
-
super().__init__(str(data_view), *args, **kwargs)
|
148
|
-
|
149
|
-
def get_dynamic_story(self, ar, obj, **kwargs):
|
150
|
-
txt = ""
|
151
|
-
dv = self.data_view
|
152
|
-
sar = dv.create_request(parent=ar, limit=dv.preview_limit)
|
153
|
-
# print("20231028", dv, list(sar))
|
154
|
-
# print("20230409", ar.renderer)
|
155
|
-
# rv += "20230325 [show {}]".format(dv)
|
156
|
-
for e in sar.renderer.table2story(sar, **kwargs):
|
157
|
-
txt += tostring(e)
|
158
|
-
return txt
|
159
|
-
|
160
|
-
def get_dynamic_paragraph(self, ar, obj, **kwargs):
|
161
|
-
dv = self.data_view
|
162
|
-
# sar = dv.create_request(parent=ar, limit=dv.preview_limit)
|
163
|
-
sar = dv.create_request(parent=ar)
|
164
|
-
return " / ".join([sar.obj2htmls(row) for row in sar])
|
165
|
-
|
166
|
-
|
167
|
-
class PageFillers(ChoiceList):
|
168
|
-
verbose_name = _("Page filler")
|
169
|
-
verbose_name_plural = _("Page fillers")
|
170
|
-
item_class = PageFiller
|
171
|
-
max_length = 50
|
172
|
-
column_names = "value name text data_view *"
|
173
|
-
|
174
|
-
@dd.virtualfield(models.CharField(_("Data table")))
|
175
|
-
def data_view(cls, choice, ar):
|
176
|
-
return choice.data_view
|
177
|
-
|
178
90
|
|
179
|
-
# class SpecialPage(PointingChoice):
|
180
91
|
class SpecialPage(dd.Choice):
|
181
92
|
# pointing_field_name = 'publisher.Page.special_page'
|
182
93
|
# show_values = True
|
@@ -184,7 +95,8 @@ class SpecialPage(dd.Choice):
|
|
184
95
|
def __init__(self, name, text=None, parent=None, **kwargs):
|
185
96
|
self.parent_value = parent
|
186
97
|
self._default_values = dict()
|
187
|
-
for k in ("ref", "title", "filler", "body"):
|
98
|
+
# for k in ("ref", "title", "filler", "body"):
|
99
|
+
for k in ("ref", "title", "body"):
|
188
100
|
if k in kwargs:
|
189
101
|
self._default_values[k] = kwargs.pop(k)
|
190
102
|
super().__init__(name, text, name, **kwargs)
|
@@ -198,8 +110,8 @@ class SpecialPage(dd.Choice):
|
|
198
110
|
def on_page_created(self, obj):
|
199
111
|
for k, v in self._default_values.items():
|
200
112
|
setattr(obj, k, v)
|
201
|
-
if obj.filler and not obj.title:
|
202
|
-
|
113
|
+
# if obj.filler and not obj.title:
|
114
|
+
# obj.title = obj.filler.data_view.get_actor_label()
|
203
115
|
if not obj.title:
|
204
116
|
obj.title = self.text or "20250422"
|
205
117
|
if self.parent_value:
|
@@ -214,7 +126,8 @@ class SpecialPage(dd.Choice):
|
|
214
126
|
# else:
|
215
127
|
# language = ar.request.LANGUAGE_CODE
|
216
128
|
# return rt.models.publisher.Page.objects.get(ref=self.defaul_values['ref'], language=language)
|
217
|
-
return rt.models.publisher.Page.objects.get(
|
129
|
+
return rt.models.publisher.Page.objects.get(
|
130
|
+
special_page=self, language=language)
|
218
131
|
|
219
132
|
|
220
133
|
class SpecialPages(dd.ChoiceList):
|
@@ -237,7 +150,8 @@ class SpecialPages(dd.ChoiceList):
|
|
237
150
|
Page = rt.models.publisher.Page
|
238
151
|
for lng in settings.SITE.languages:
|
239
152
|
try:
|
240
|
-
page = Page.objects.get(
|
153
|
+
page = Page.objects.get(
|
154
|
+
special_page=choice, language=lng.django_code)
|
241
155
|
lst.append(ar.obj2html(page, lng.name))
|
242
156
|
except Page.DoesNotExist:
|
243
157
|
page = _("(create)")
|
@@ -1,10 +1,10 @@
|
|
1
|
-
{% extends "
|
2
|
-
|
1
|
+
{% extends "bootstrap5/base.html" %}
|
2
|
+
{% block title %}{{site.title or site.verbose_name}}{% endblock %}
|
3
3
|
{% block header %}
|
4
4
|
<div class="container-fluid lino-bs-header">
|
5
5
|
{% if ar -%}
|
6
6
|
{% if isinstance(obj, rt.models.publisher.Page) -%}
|
7
|
-
{{obj.get_prev_link(ar)}}
|
7
|
+
{{obj.get_prev_link(ar)}} {{obj.get_next_link(ar)}} |
|
8
8
|
{% endif -%}
|
9
9
|
{% if dd.is_installed('react') %}
|
10
10
|
{% set ar_react = obj.get_default_table().request(parent=ar, permalink_uris=True, renderer=dd.plugins.react.renderer) %}
|
@@ -18,9 +18,10 @@
|
|
18
18
|
{{_("Home")}}
|
19
19
|
{% endif -%}
|
20
20
|
{% if site.kernel.editing_front_end.url_prefix -%}
|
21
|
-
|
21
|
+
| <a href="/{{site.kernel.editing_front_end.url_prefix}}/">{{_("Admin")}}</a>
|
22
22
|
{% endif -%}
|
23
23
|
{% if len(site.languages) > 1 -%}
|
24
|
+
|
|
24
25
|
{% for lang in site.languages -%}
|
25
26
|
{% if lang.django_code == requested_language -%}
|
26
27
|
{{lang.django_code}}
|
@@ -29,32 +30,94 @@
|
|
29
30
|
{% endif -%}
|
30
31
|
{% endfor -%}
|
31
32
|
{% endif -%}
|
33
|
+
|
|
34
|
+
{% set user = ar.get_user() %}
|
35
|
+
{% if user.is_anonymous %}
|
36
|
+
<a href="" data-bs-toggle="modal" data-bs-target="#signinModal">
|
37
|
+
{{str(user)}}
|
38
|
+
</a>
|
39
|
+
{% else %}
|
40
|
+
{{str(user)}} <a href="/logout">{{_("Sign out")}}</a>
|
41
|
+
{% endif %}
|
32
42
|
{%- if site.kernel.admin_ui -%}
|
33
43
|
—
|
34
44
|
<a href="{{site.kernel.admin_ui.build_plain_url()}}/">{{site.kernel.admin_ui.ui_label}}</a>
|
35
45
|
{%- endif -%}
|
36
46
|
{% endif -%}
|
37
47
|
|
48
|
+
<div class="modal fade" id="signinModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
49
|
+
<div class="modal-dialog modal-dialog-centered">
|
50
|
+
<div class="modal-content">
|
51
|
+
<div class="modal-header">
|
52
|
+
<h1 class="modal-title fs-5" id="exampleModalLabel">{{_("Sign in form")}}</h1>
|
53
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
54
|
+
</div>
|
55
|
+
<div class="modal-body">
|
56
|
+
<form id="signinForm" action="/login" method="post">
|
57
|
+
<div id="signinError" class="alert alert-danger d-none" role="alert">
|
58
|
+
{{_("Incorrect username or password.")}}
|
59
|
+
</div>
|
60
|
+
<div class="mb-3">
|
61
|
+
<label for="signinInputUsername" class="form-label">{{_("Username")}}</label>
|
62
|
+
<input type="text" name="username" class="form-control" id="signinInputUsername" aria-describedby="usernameHelp" required="true">
|
63
|
+
<!-- <div id="usernameHelp" class="form-text">Enter your username.</div>-->
|
64
|
+
</div>
|
65
|
+
<div class="mb-3">
|
66
|
+
<label for="signinInputPassword" class="form-label">{{_("Password")}}</label>
|
67
|
+
<input type="password" name="password" class="form-control" id="signinInputPassword" required="true">
|
68
|
+
</div>
|
69
|
+
</form>
|
70
|
+
</div>
|
71
|
+
<div class="modal-footer">
|
72
|
+
<button form="signinForm" type="submit" class="btn btn-primary">{{_("Sign in")}}</button>
|
73
|
+
</div>
|
74
|
+
</div>
|
75
|
+
</div>
|
76
|
+
</div>
|
77
|
+
|
78
|
+
<script>
|
79
|
+
const form = document.getElementById("signinForm");
|
80
|
+
form.addEventListener("submit", (event) => {
|
81
|
+
event.preventDefault();
|
82
|
+
const formData = new FormData(form);
|
83
|
+
fetch(form.action, {
|
84
|
+
method: form.method,
|
85
|
+
body: formData
|
86
|
+
}).then((resp) => {
|
87
|
+
if (resp.status >= 400) {
|
88
|
+
const eel = document.getElementById("signinError");
|
89
|
+
eel.innerText = "Some unknown error occured, please contact site administrator";
|
90
|
+
eel.classList.remove("d-none")
|
91
|
+
return {success: false}
|
92
|
+
}
|
93
|
+
return resp.json()
|
94
|
+
}).then((resp) => {
|
95
|
+
if (resp.success) window.location.reload()
|
96
|
+
else {
|
97
|
+
const eel = document.getElementById("signinError");
|
98
|
+
eel.classList.remove("d-none")
|
99
|
+
}
|
100
|
+
})
|
101
|
+
});
|
102
|
+
</script>
|
103
|
+
|
38
104
|
</div>
|
39
105
|
{% endblock %}
|
40
106
|
|
41
107
|
{% block navbar %}
|
42
|
-
<nav class="navbar navbar-
|
108
|
+
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
43
109
|
<div class="container-fluid">
|
44
|
-
{% set
|
45
|
-
<
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
<span class="icon-bar"></span>
|
50
|
-
<span class="icon-bar"></span>
|
51
|
-
</button>
|
52
|
-
<a class="navbar-brand" href="{{ar.get_home_url()}}">{{ index_node.title }}</a>
|
53
|
-
</div>
|
110
|
+
{% set homepage, children = obj.home_and_children(ar) %}
|
111
|
+
<a class="navbar-brand" href="{{ar.obj2url(homepage)}}"><span class="pi pi-home"/></a>
|
112
|
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#bs-navbar-collapsible-content" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
113
|
+
<span class="navbar-toggler-icon"></span>
|
114
|
+
</button>
|
54
115
|
<div class="collapse navbar-collapse" id="bs-navbar-collapsible-content">
|
55
|
-
<ul class="nav
|
56
|
-
{% for child in
|
57
|
-
<li>
|
116
|
+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
117
|
+
{% for child in children %}
|
118
|
+
<li class="nav-item">
|
119
|
+
<a class="nav-link" href="{{ar.obj2url(child)}}">{{str(child)}}</a>
|
120
|
+
</li>
|
58
121
|
{% endfor %}
|
59
122
|
</ul>
|
60
123
|
</div>
|
@@ -63,7 +126,7 @@
|
|
63
126
|
{% endblock %}
|
64
127
|
|
65
128
|
{% block content %}
|
66
|
-
<div class="row-fluid">
|
129
|
+
<div class="row-fluid ql-editor">
|
67
130
|
{% for chunk in obj.as_page(ar) %}
|
68
131
|
{{ chunk }}
|
69
132
|
{% endfor %}
|
@@ -11,13 +11,26 @@ from lino.api import rt
|
|
11
11
|
|
12
12
|
|
13
13
|
def objects():
|
14
|
+
Tree = rt.models.publisher.Tree
|
14
15
|
Page = rt.models.publisher.Page
|
16
|
+
index = Tree(ref='index')
|
17
|
+
yield index
|
18
|
+
# lng2tree = dict()
|
19
|
+
# for lng in settings.SITE.languages:
|
20
|
+
# with translation.override(lng.django_code):
|
21
|
+
# kwargs = dict(language=lng.django_code, ref='index')
|
22
|
+
# obj = Tree(**kwargs)
|
23
|
+
# yield obj
|
24
|
+
# lng2tree[lng.django_code] = obj
|
25
|
+
|
15
26
|
for sp in SpecialPages.get_list_items():
|
16
27
|
translated_from = None
|
17
28
|
for lng in settings.SITE.languages:
|
18
29
|
with translation.override(lng.django_code):
|
19
|
-
|
30
|
+
# tree = lng2tree[lng.django_code]
|
31
|
+
kwargs = dict(publisher_tree=index, special_page=sp)
|
20
32
|
kwargs.update(publishing_state="published")
|
33
|
+
kwargs.update(language=lng.django_code)
|
21
34
|
# kwargs.update(sp.default_values)
|
22
35
|
if lng.suffix:
|
23
36
|
kwargs.update(translated_from=translated_from)
|
@@ -1,4 +1,6 @@
|
|
1
1
|
from lino.api import rt, _
|
2
|
+
raise Exception("20250809 content moved to lino_book/projects/noi2/fixtures/demo.py")
|
3
|
+
|
2
4
|
|
3
5
|
home_children = [
|
4
6
|
(_("Mission"), None, []),
|
@@ -15,6 +17,7 @@ home_children = [
|
|
15
17
|
|
16
18
|
def objects():
|
17
19
|
image = rt.models.uploads.Upload.objects.first()
|
20
|
+
|
18
21
|
def iterate(iterable):
|
19
22
|
try:
|
20
23
|
for obj in iterable:
|
@@ -25,4 +28,3 @@ def objects():
|
|
25
28
|
yield obj
|
26
29
|
for obj in rt.models.publisher.make_demo_pages(home_children):
|
27
30
|
yield iterate(obj)
|
28
|
-
|
lino/modlib/publisher/mixins.py
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2020-
|
2
|
+
# Copyright 2020-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
5
|
# from inspect import isclass
|
6
|
-
from lino.utils.html import tostring
|
7
|
-
from lino.api import dd, rt, _
|
8
|
-
|
9
6
|
from django import http
|
10
|
-
from django.db import models
|
11
|
-
from django.conf import settings
|
12
|
-
from django.utils.translation import get_language
|
13
|
-
from lino.core.renderer import add_user_language
|
14
|
-
from lino.core.utils import full_model_name
|
15
|
-
from lino.utils import buildurl
|
7
|
+
# from django.db import models
|
8
|
+
# from django.conf import settings
|
9
|
+
# from django.utils.translation import get_language
|
10
|
+
# from lino.core.renderer import add_user_language
|
11
|
+
# from lino.core.utils import full_model_name
|
12
|
+
# from lino.utils import buildurl
|
16
13
|
from lino.utils.html import mark_safe
|
17
14
|
from lino.modlib.printing.mixins import Printable
|
18
|
-
from lino.
|
19
|
-
from .choicelists import PublishingStates,
|
15
|
+
from lino.api import dd, rt, _
|
16
|
+
from .choicelists import PublishingStates, SpecialPages
|
20
17
|
# from .choicelists import PublisherViews, PublishingStates
|
21
18
|
|
22
19
|
|
@@ -48,6 +45,8 @@ class Publishable(Printable):
|
|
48
45
|
publisher_template = "publisher/page.pub.html"
|
49
46
|
_lino_publisher_location = None
|
50
47
|
|
48
|
+
publisher_tree = dd.ForeignKey("publisher.Tree", null=True, blank=True)
|
49
|
+
|
51
50
|
@dd.htmlbox()
|
52
51
|
def full_page(self, ar):
|
53
52
|
if ar is None:
|
@@ -65,95 +64,50 @@ class Publishable(Printable):
|
|
65
64
|
|
66
65
|
preview_publication = PreviewPublication()
|
67
66
|
|
68
|
-
# @classmethod
|
69
|
-
# def on_analyze(cls, site):
|
70
|
-
# # Inject the previous_page field to all models that have a publisher
|
71
|
-
# # view.
|
72
|
-
# # print("20231103", cls, [pv.table_class.model for pv in PublisherViews.get_list_items()])
|
73
|
-
# # for pv in PublisherViews.get_list_items():
|
74
|
-
# for loc, table_class in site.plugins.publisher.locations:
|
75
|
-
# if full_model_name(cls) == table_class.model:
|
76
|
-
# # print("20231103", cls)
|
77
|
-
# dd.inject_field(
|
78
|
-
# cls, 'previous_page',
|
79
|
-
# dd.ForeignKey("self", null=True, blank=True,
|
80
|
-
# verbose_name=_("Previous page")))
|
81
|
-
# return
|
82
|
-
|
83
|
-
# @dd.action(select_rows=False)
|
84
|
-
# def preview_publication(self, ar):
|
85
|
-
# sr_selected = not isclass(self)
|
86
|
-
# if sr_selected:
|
87
|
-
# ar.success(open_url=self.publisher_url())
|
88
|
-
# else:
|
89
|
-
# ar.success(open_url=self.publisher_url(self, not sr_selected))
|
90
|
-
|
91
|
-
# def publisher_url(self, ar, **kw):
|
92
|
-
# for i in PublisherViews.get_list_items():
|
93
|
-
# if isinstance(self, i.table_class.model):
|
94
|
-
# # print("20230409", self.__class__, i)
|
95
|
-
# # return "/{}/{}".format(i.publisher_location, self.pk)
|
96
|
-
# add_user_language(kw, ar)
|
97
|
-
# # return buildurl("/" + i.publisher_location, str(self.pk), **dd.urlkwargs())
|
98
|
-
# return ar.renderer.front_end.buildurl(i.publisher_location, str(self.pk), **kw)
|
99
|
-
# # return dd.plugins.publisher.buildurl("/"+i.publisher_location, str(self.pk), **kw)
|
100
|
-
# # return buildurl("/", i.publisher_location, str(self.pk), **kw)
|
101
|
-
# available = [i.table_class.model for i in PublisherViews.get_list_items()]
|
102
|
-
# return "No publisher view for {} in {}".format(self, available)
|
103
|
-
|
104
67
|
def is_public(self):
|
105
68
|
return True
|
106
69
|
|
107
70
|
def get_preview_context(self, ar):
|
108
71
|
return ar.get_printable_context(obj=self)
|
109
72
|
|
110
|
-
# def set_previous_page(self, ppv, ppi):
|
111
|
-
# if self.previous_page_id != ppi or self.previous_page_view != ppv:
|
112
|
-
# self.previous_page_id = ppi
|
113
|
-
# self.previous_page_view = ppv
|
114
|
-
# self.save()
|
115
|
-
|
116
|
-
# @classmethod
|
117
|
-
# def update_publisher_pages(cls):
|
118
|
-
# pass
|
119
|
-
|
120
|
-
# def render_from(self, tplname, ar):
|
121
|
-
# env = settings.SITE.plugins.jinja.renderer.jinja_env
|
122
|
-
# context = self.get_preview_context(ar)
|
123
|
-
# template = env.get_template(tplname)
|
124
|
-
# # print("20210112 publish {} {} using {}".format(cls, obj, template))
|
125
|
-
# # context = dict(obj=self, request=request, language=get_language())
|
126
|
-
# return template.render(**context)
|
127
|
-
|
128
|
-
def home_and_children(self, ar):
|
129
|
-
home = rt.models.publisher.SpecialPages.home.get_object()
|
130
|
-
return home, rt.models.publisher.Page.objects.filter(parent=home)
|
131
|
-
# return dv.model.objects.filter(models.Q(parent=index_node) | models.Q(ref='index'), language=language)
|
132
|
-
|
133
73
|
def get_publisher_response(self, ar):
|
134
74
|
if not self.is_public():
|
135
75
|
return http.HttpResponseNotFound(
|
136
|
-
"{} {} is not public"
|
137
|
-
)
|
76
|
+
f"{self.__class__} {self.pk} is not public")
|
138
77
|
context = self.get_preview_context(ar)
|
139
78
|
# html = ''.join(self.as_page(ar))
|
140
79
|
# # context.update(content=html, admin_site_prefix=dd.plugins.publisher.admin_location)
|
141
80
|
# context.update(content=html)
|
142
81
|
tpl = dd.plugins.jinja.renderer.jinja_env.get_template(self.publisher_template)
|
143
82
|
return http.HttpResponse(
|
144
|
-
tpl.render(**context), content_type='text/html;charset="utf-8"'
|
145
|
-
|
83
|
+
tpl.render(**context), content_type='text/html;charset="utf-8"')
|
84
|
+
|
85
|
+
def home_and_children(self, ar):
|
86
|
+
# home = self.publisher_tree.root_page
|
87
|
+
Page = rt.models.publisher.Page
|
88
|
+
qs = Page.objects.filter(
|
89
|
+
publisher_tree=self.publisher_tree, parent__isnull=True)
|
90
|
+
home = qs.first()
|
91
|
+
if home is None:
|
92
|
+
home = SpecialPages.home.get_object()
|
93
|
+
return home, Page.objects.filter(parent=home)
|
94
|
+
# return dv.model.objects.filter(models.Q(parent=index_node) | models.Q(ref='index'), language=language)
|
146
95
|
|
147
96
|
|
148
97
|
class PublishableContent(Publishable):
|
98
|
+
|
149
99
|
class Meta:
|
150
100
|
abstract = True
|
151
101
|
app_label = "publisher"
|
152
102
|
|
153
103
|
language = dd.LanguageField()
|
154
104
|
publishing_state = PublishingStates.field(default="draft")
|
155
|
-
|
156
|
-
|
105
|
+
main_image = dd.ForeignKey('uploads.Upload', blank=True,
|
106
|
+
null=True, verbose_name=_("Main image"))
|
107
|
+
translated_from = dd.ForeignKey(
|
108
|
+
"self", verbose_name=_("Translated from"),
|
109
|
+
null=True, blank=True,
|
110
|
+
related_name="translated_to")
|
157
111
|
|
158
112
|
def get_print_language(self):
|
159
113
|
return self.language
|
@@ -167,4 +121,32 @@ class PublishableContent(Publishable):
|
|
167
121
|
super().on_duplicate(ar, master)
|
168
122
|
|
169
123
|
def is_public(self):
|
124
|
+
if self.publisher_tree.private:
|
125
|
+
return False
|
170
126
|
return self.publishing_state.is_public
|
127
|
+
|
128
|
+
def get_publisher_response(self, ar):
|
129
|
+
if ar and ar.request and self.language != ar.request.LANGUAGE_CODE:
|
130
|
+
rqlang = ar.request.LANGUAGE_CODE
|
131
|
+
# tt = rt.models.pages.Translation.objects.filter(
|
132
|
+
# parent=self, language=ar.request.LANGUAGE_CODE).first()
|
133
|
+
obj = None
|
134
|
+
if self.translated_from_id and self.translated_from.language == rqlang:
|
135
|
+
obj = self.translated_from
|
136
|
+
else:
|
137
|
+
sources = set([self.id])
|
138
|
+
p = self.translated_from
|
139
|
+
while p is not None:
|
140
|
+
sources.add(p.id)
|
141
|
+
p = p.translated_from
|
142
|
+
qs = self.__class__.objects.filter(
|
143
|
+
language=rqlang, translated_from__in=sources)
|
144
|
+
obj = qs.first()
|
145
|
+
# obj = self.translated_to.filter(language=rqlang).first()
|
146
|
+
# print("20231027 redirect to translation", tt.language, ar.request.LANGUAGE_CODE)
|
147
|
+
if obj is not None:
|
148
|
+
# print("20231028", self.language, "!=", ar.request.LANGUAGE_CODE, tt)
|
149
|
+
ar.selected_rows = [obj]
|
150
|
+
url = ar.get_request_url()
|
151
|
+
return http.HttpResponseRedirect(url)
|
152
|
+
return super().get_publisher_response(ar)
|