lino 25.7.0__py3-none-any.whl → 25.7.2__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.
Files changed (46) hide show
  1. lino/__init__.py +1 -1
  2. lino/api/dd.py +1 -0
  3. lino/api/doctest.py +13 -10
  4. lino/core/__init__.py +0 -2
  5. lino/core/actions.py +24 -5
  6. lino/core/actors.py +22 -177
  7. lino/core/dashboard.py +3 -2
  8. lino/core/dbtables.py +1 -1
  9. lino/core/elems.py +1 -1
  10. lino/core/fields.py +3 -0
  11. lino/core/kernel.py +6 -0
  12. lino/core/layouts.py +5 -7
  13. lino/core/model.py +1 -0
  14. lino/core/plugin.py +1 -1
  15. lino/core/renderer.py +7 -5
  16. lino/core/requests.py +4 -5
  17. lino/core/site.py +1 -1
  18. lino/core/utils.py +6 -4
  19. lino/help_texts.py +2 -1
  20. lino/mixins/registrable.py +4 -2
  21. lino/modlib/checkdata/management/commands/checkdata.py +3 -3
  22. lino/modlib/extjs/views.py +7 -0
  23. lino/modlib/help/models.py +3 -1
  24. lino/modlib/linod/__init__.py +1 -1
  25. lino/modlib/memo/__init__.py +1 -2
  26. lino/modlib/office/roles.py +0 -1
  27. lino/modlib/printing/actions.py +2 -6
  28. lino/modlib/printing/choicelists.py +6 -6
  29. lino/modlib/printing/mixins.py +2 -2
  30. lino/modlib/publisher/__init__.py +21 -30
  31. lino/modlib/publisher/models.py +3 -1
  32. lino/modlib/publisher/renderer.py +2 -5
  33. lino/modlib/publisher/views.py +4 -11
  34. lino/modlib/weasyprint/__init__.py +9 -0
  35. lino/modlib/weasyprint/choicelists.py +14 -9
  36. lino/modlib/weasyprint/config/weasyprint/base.weasy.html +15 -13
  37. lino/utils/jsgen.py +2 -1
  38. {lino-25.7.0.dist-info → lino-25.7.2.dist-info}/METADATA +1 -1
  39. {lino-25.7.0.dist-info → lino-25.7.2.dist-info}/RECORD +42 -46
  40. lino/modlib/forms/__init__.py +0 -51
  41. lino/modlib/forms/models.py +0 -0
  42. lino/modlib/forms/renderer.py +0 -74
  43. lino/modlib/forms/views.py +0 -311
  44. {lino-25.7.0.dist-info → lino-25.7.2.dist-info}/WHEEL +0 -0
  45. {lino-25.7.0.dist-info → lino-25.7.2.dist-info}/licenses/AUTHORS.rst +0 -0
  46. {lino-25.7.0.dist-info → lino-25.7.2.dist-info}/licenses/COPYING +0 -0
lino/core/utils.py CHANGED
@@ -664,10 +664,11 @@ class Parametrizable:
664
664
  parameters = None
665
665
  params_layout = None
666
666
  params_panel_hidden = True
667
- params_panel_pos = "top" # allowed values "top", "bottom", "left" and "right"
667
+ params_panel_pos = "bottom" # allowed values "top", "bottom", "left" and "right"
668
668
  use_detail_param_panel = False
669
669
 
670
670
  _params_layout_class = NotImplementedError
671
+ _field_actions = dict()
671
672
 
672
673
  def get_window_layout(self, actor):
673
674
  return self.params_layout
@@ -1238,11 +1239,12 @@ def register_params(cls):
1238
1239
  cls.params_layout = cls._params_layout_class.join_str.join(
1239
1240
  cls.parameters.keys()
1240
1241
  )
1242
+ if cls.params_layout is not None:
1241
1243
  install_layout(cls, "params_layout", cls._params_layout_class)
1242
1244
 
1243
- # e.g. accounting.ByJournal is just a mixin but provides a default value for its children
1244
- elif cls.params_layout is not None:
1245
- raise Exception("{} has a params_layout but no parameters".format(cls))
1245
+ # # e.g. accounting.ByJournal is just a mixin but provides a default value for its children
1246
+ # elif cls.params_layout is not None:
1247
+ # raise Exception("{} has a params_layout but no parameters".format(cls))
1246
1248
 
1247
1249
  # if isinstance(cls, type) and cls.__name__.endswith("Users"):
1248
1250
  # # if isinstance(cls, type) and cls.model is not None and cls.model.__name__ == "User":
lino/help_texts.py CHANGED
@@ -312,7 +312,6 @@ help_texts = {
312
312
  'lino.core.model.Model.create_from_choice' : _("""Called when a learning combo has been submitted. Create a persistent database object if the given text contains enough information."""),
313
313
  'lino.core.model.Model.choice_text_to_dict' : _("""Return a dict of the fields to fill when the given text contains enough information for creating a new database object."""),
314
314
  'lino.core.model.Model.allow_cascaded_delete' : _("""A set of names of ForeignKey or GenericForeignKey fields of this model that allow for cascaded delete."""),
315
- 'lino.core.model.Model.disabled_fields' : _("""Return a set of field names that should be disabled (i.e. not editable) for this database object."""),
316
315
  'lino.core.model.Model.__str__' : _("""Return a translatable text that describes this database row."""),
317
316
  'lino.core.model.Model.as_str' : _("""Return a translatable text that describes this database row. Unlike __str__() this method gets an action request when it is called, so it knows the context."""),
318
317
  'lino.core.model.Model.get_str_words' : _("""Yield a series of words that describe this database row in plain text."""),
@@ -705,11 +704,13 @@ help_texts = {
705
704
  'lino.modlib.weasyprint.WeasyHtmlBuildMethod' : _("""Renders the input template and returns the unmodified output as plain HTML."""),
706
705
  'lino.modlib.weasyprint.WeasyPdfBuildMethod' : _("""Like WeasyBuildMethod, but the rendered HTML is then passed through weasyprint which converts from HTML to PDF."""),
707
706
  'lino.core.model.Model' : _("""Lino extension of Django’s database model. This is a subclass of Django’s Model class (django.db.models.Model)."""),
707
+ 'lino.core.model.Model.__init__' : _("""The first positional argument is the optional label, other arguments should be specified as keywords and can be any of the existing class attributes."""),
708
708
  'lino.core.model.Model.overview' : _("""A multi-paragraph representation of this database row."""),
709
709
  'lino.core.model.Model.navigation_panel' : _("""A virtual field that displays the navigation panel for this row. This may be included in a detail layout, usually either on the left or the right side with full height."""),
710
710
  'lino.core.model.Model.workflow_buttons' : _("""Shows the current workflow state of this database row and a list of available workflow actions."""),
711
711
  'lino.core.model.Model.workflow_state_field' : _("""Optional default value for the workflow_state_field of all data tables based on this model."""),
712
712
  'lino.core.model.Model.workflow_owner_field' : _("""Optional default value for workflow_owner_field on all data tables based on this model."""),
713
+ 'lino.core.model.Model.disabled_fields' : _("""Return a set of field names that should be disabled (i.e. not editable) for this database object."""),
713
714
  'lino.core.model.Model.FOO_changed' : _("""Called when field FOO of an instance of this model has been modified through the user interface."""),
714
715
  'lino.core.model.Model.FOO_choices' : _("""Return a queryset or list of allowed choices for field FOO."""),
715
716
  'lino.core.model.Model.create_FOO_choice' : _("""For every field named “FOO” for which a chooser exists, if the model also has a method called “create_FOO_choice”, then this chooser will be a learning chooser. That is, users can enter text into the combobox, and Lino will create a new database object from it."""),
@@ -118,12 +118,14 @@ class Registrable(model.Model):
118
118
  # yield 'date'
119
119
 
120
120
  def disabled_fields(self, ar):
121
+ rv = super().disabled_fields(ar)
121
122
  if not self.state.is_editable:
122
123
  # return self._registrable_fields
123
124
  # Copy _registrable_fields otherwise _registrable_fields get
124
125
  # modified as more disabled fields are added to the set.
125
- return self._registrable_fields.copy()
126
- return super().disabled_fields(ar)
126
+ # return self._registrable_fields.copy()
127
+ rv |= self._registrable_fields
128
+ return rv
127
129
 
128
130
  def get_row_permission(self, ar, state, ba):
129
131
  """Only rows in an editable state may be edited.
@@ -1,5 +1,5 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2015-2023 Rumma & Ko Ltd
2
+ # Copyright 2015-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
5
  from django.core.management.base import BaseCommand, CommandError
@@ -7,7 +7,7 @@ from django.core.management.base import BaseCommand, CommandError
7
7
  from lino.modlib.checkdata.choicelists import Checkers
8
8
  from lino.modlib.checkdata.models import check_data
9
9
 
10
- from lino.api import rt
10
+ from lino.api import dd, rt
11
11
 
12
12
 
13
13
  class Command(BaseCommand):
@@ -56,7 +56,7 @@ class Command(BaseCommand):
56
56
  app = options.get("checkers", args)
57
57
  if app:
58
58
  args += tuple(app)
59
- ar = rt.login()
59
+ ar = rt.login(dd.plugins.users.demo_username)
60
60
  if options["list"]:
61
61
  ar.show(Checkers, column_names="value text")
62
62
  else:
@@ -463,6 +463,13 @@ class ApiElement(View):
463
463
  else:
464
464
  datarec = ar.elem2rec_detailed(elem)
465
465
  datarec.update(**vm)
466
+
467
+ fa = dict()
468
+ for k, lst in rpt._field_actions.items():
469
+ fa[k] = [ar.row_action_button(elem, ba) for ba in lst]
470
+ if fa:
471
+ datarec.update(field_actions=fa)
472
+
466
473
  return json_response(datarec)
467
474
 
468
475
  after_show = ar.get_status(record_id=pk)
@@ -21,7 +21,9 @@ class OpenHelpWindow(dd.Action):
21
21
  # I undid that change:
22
22
  # button_text = " ? "
23
23
  # button_text = "?"
24
- button_text = "🛈"
24
+ # button_text = "🛈"
25
+ button_text = "ⓘ" # 24d8
26
+ # button_text = "🯄" # 1fbc4
25
27
  select_rows = False
26
28
  help_text = _("Open Help Window")
27
29
  show_in_plain = True
@@ -50,7 +50,7 @@ class Plugin(ad.Plugin):
50
50
  m = m.add_menu(mg.app_label, mg.verbose_name)
51
51
  m.add_action("linod.Procedures")
52
52
 
53
- def get_required_plugins(self):
53
+ def get_needed_plugins(self):
54
54
  # We don't use needs_plugins because it depends on use_channels. We must
55
55
  # not install the plugin when the Python package isn't installed because
56
56
  # otherwise `pm install` fails with ModuleNotFoundError: No module named
@@ -50,7 +50,7 @@ class Plugin(ad.Plugin):
50
50
  """The front end to use when writing previews.
51
51
 
52
52
  If this is `None`, Lino will use the default :term:`front end`
53
- (:attr:`lino.core.site.Site.web_front_ends`).
53
+ (:attr:`lino.core.site.Site.editing_front_end`).
54
54
 
55
55
  Used on sites that are available through more than one web front ends. The
56
56
  :term:`server administrator` must then decide which front end is the primary
@@ -115,7 +115,6 @@ class Plugin(ad.Plugin):
115
115
  def post_site_startup(self, site):
116
116
  if self.front_end is None:
117
117
  self.front_end = site.kernel.editing_front_end
118
- # web_front_ends[0]
119
118
  else:
120
119
  self.front_end = site.plugins.resolve(self.front_end)
121
120
 
@@ -1,7 +1,6 @@
1
1
  # Copyright 2015-2023 Rumma & Ko Ltd
2
2
  # License: GNU Affero General Public License v3 (see file COPYING for details)
3
3
 
4
- from lino.core.roles import UserRole
5
4
  from lino.modlib.uploads.roles import UploadsReader
6
5
 
7
6
 
@@ -294,19 +294,15 @@ class EditTemplate(BasePrintAction):
294
294
  ar.confirm(ok, msg, _("Are you sure?"))
295
295
 
296
296
 
297
- class ClearCacheAction(Action):
297
+ class ClearCache(Action):
298
298
  sort_index = 51
299
299
  url_action_name = "clear"
300
300
  label = _("Clear cache")
301
301
  icon_name = "printer_delete"
302
302
 
303
- # def disabled_for(self,obj,request):
304
- # if not obj.build_time:
305
- # return True
306
-
307
303
  def get_action_permission(self, ar, obj, state):
308
304
  # obj may be None when Lino asks whether this action
309
- # should be visible in the UI
305
+ # should be visible in the table toolbar
310
306
  if obj is not None and not obj.build_time:
311
307
  return False
312
308
  return super().get_action_permission(ar, obj, state)
@@ -33,9 +33,9 @@ except ImportError:
33
33
 
34
34
 
35
35
  class BuildMethod(Choice):
36
- target_ext = None
37
- cache_name = "cache"
38
- use_webdav = False
36
+ target_ext: str = None
37
+ cache_name: str = "cache"
38
+ use_webdav: bool = False
39
39
 
40
40
  def __init__(self, names=None, **kwargs):
41
41
  # For build methods, `Choice.names` and `Choice.value` are the
@@ -65,9 +65,9 @@ class BuildMethod(Choice):
65
65
 
66
66
 
67
67
  class TemplatedBuildMethod(BuildMethod):
68
- template_ext = None
69
- templates_name = None
70
- default_template = "" # overridden by lino_xl.lib.appypod
68
+ template_ext: str = None
69
+ templates_name: str = None
70
+ default_template: str = "" # overridden by lino_xl.lib.appypod
71
71
 
72
72
  def __init__(self, *args, **kwargs):
73
73
  super().__init__(*args, **kwargs)
@@ -22,7 +22,7 @@ from .choicelists import BuildMethods
22
22
  from .actions import (
23
23
  DirectPrintAction,
24
24
  CachedPrintAction,
25
- ClearCacheAction,
25
+ ClearCache,
26
26
  EditTemplate,
27
27
  )
28
28
 
@@ -153,7 +153,7 @@ class CachedPrintable(Duplicable, Printable):
153
153
  abstract = True
154
154
 
155
155
  do_print = CachedPrintAction()
156
- do_clear_cache = ClearCacheAction()
156
+ do_clear_cache = ClearCache()
157
157
  edit_template = EditTemplate()
158
158
 
159
159
  build_time = models.DateTimeField(
@@ -1,5 +1,5 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2020-2024 Rumma & Ko Ltd
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 lino.api.ad import Plugin
@@ -12,17 +12,7 @@ class Plugin(Plugin):
12
12
  "lino.modlib.jinja",
13
13
  "lino.modlib.bootstrap3",
14
14
  ]
15
- locations = []
16
-
17
- def setup_main_menu(self, site, user_type, m, ar=None):
18
- mg = self.get_menu_group()
19
- m = m.add_menu(mg.app_label, mg.verbose_name)
20
- m.add_action("publisher.Pages")
21
-
22
- def setup_config_menu(self, site, user_type, m, ar=None):
23
- mg = self.get_menu_group()
24
- m = m.add_menu(mg.app_label, mg.verbose_name)
25
- m.add_action("publisher.SpecialPages")
15
+ locations: list[tuple[str, str]] = []
26
16
 
27
17
  def get_requirements(self, site):
28
18
  yield "python-lorem"
@@ -41,34 +31,35 @@ class Plugin(Plugin):
41
31
  app = site.models.get(app_label)
42
32
  cls = getattr(app, model_name, None)
43
33
  if not isinstance(cls, type) or not issubclass(cls, Actor):
44
- raise Exception("location {}: {} is not an Actor".format(view, cls))
34
+ raise Exception(f"location {loc}: {cls} is not an Actor")
45
35
  if not issubclass(cls.model, Publishable):
46
36
  raise Exception(
47
- "location {}: model is a {}, which is not Publishable".format(
48
- view, type(cls.model)
49
- )
50
- )
51
-
37
+ f"location {loc},{view}: "
38
+ f"model {type(cls.model)} is not Publishable")
52
39
  cls.model._lino_publisher_location = loc
53
40
  locations.append((loc, cls))
54
41
  self.locations = tuple(locations)
55
42
 
56
43
  def get_patterns(self):
57
44
  from django.urls import re_path as url
58
- from lino.core.utils import models_by_base
59
45
  from . import views
60
- # from .choicelists import PublisherViews
61
- # raise Exception("20220927")
62
- # print("20220927", list(PublisherViews.get_list_items()))
63
46
 
64
- # for pv in PublisherViews.get_list_items():
65
- for publisher_location, table_class in self.locations:
66
- # print("20220927", pv.publisher_location)
67
- # if publisher_location is not None:
47
+ for location, table_class in self.locations:
68
48
  yield url(
69
- "^{}/(?P<pk>.+)$".format(publisher_location),
70
- views.Element.as_view(table_class=table_class),
71
- )
49
+ f"^{location}/(?P<pk>.+)$",
50
+ views.Element.as_view(table_class=table_class))
72
51
 
73
- yield url("^$", views.Index.as_view())
52
+ # Only if this is the primary front end:
53
+ if self.site.kernel.web_front_ends[0] is self:
54
+ yield url("^$", views.Index.as_view())
74
55
  # yield url('^login$',views.Login.as_view())
56
+
57
+ def setup_main_menu(self, site, user_type, m, ar=None):
58
+ mg = self.get_menu_group()
59
+ m = m.add_menu(mg.app_label, mg.verbose_name)
60
+ m.add_action("publisher.Pages")
61
+
62
+ def setup_config_menu(self, site, user_type, m, ar=None):
63
+ mg = self.get_menu_group()
64
+ m = m.add_menu(mg.app_label, mg.verbose_name)
65
+ m.add_action("publisher.SpecialPages")
@@ -47,6 +47,8 @@ from .ui import *
47
47
 
48
48
  # class Node(Referrable, Hierarchical, Sequenced, Previewable, Publishable, Commentable):
49
49
  # Polymorphic,
50
+
51
+
50
52
  class Page(
51
53
  Hierarchical, Sequenced, Previewable, Commentable, PublishableContent, Taggable
52
54
  ):
@@ -205,7 +207,7 @@ class Page(
205
207
  if not self.children.exists():
206
208
  return
207
209
 
208
- yield "<p><b>{}</b></p>".format(_("Children:"))
210
+ # yield "<p><b>{}</b></p>".format(_("Children:"))
209
211
 
210
212
  if hlevel > home.child_node_depth:
211
213
  yield " (...)"
@@ -2,13 +2,9 @@
2
2
  # Copyright 2023 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from lino.core import constants as ext_requests
6
- from lino.core.renderer import HtmlRenderer
5
+ from lino import logger
7
6
  from lino.core.renderer import add_user_language
8
-
9
7
  from lino.modlib.bootstrap3.renderer import Renderer
10
- from .mixins import Publishable
11
- # from .choicelists import PublisherViews
12
8
 
13
9
 
14
10
  class Renderer(Renderer):
@@ -27,6 +23,7 @@ class Renderer(Renderer):
27
23
  # if ar.actor is None or not isinstance(obj, ar.actor.model):
28
24
  loc = obj.__class__._lino_publisher_location
29
25
  if loc is None:
26
+ # logger.warning("No location for %s", obj.__class__)
30
27
  return None
31
28
  add_user_language(kwargs, ar)
32
29
  return self.front_end.buildurl(loc, str(obj.pk), **kwargs)
@@ -1,19 +1,12 @@
1
1
  # -*- coding: UTF-8 -*-
2
- # Copyright 2020-2024 Rumma & Ko Ltd
2
+ # Copyright 2020-2025 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from django.conf import settings
6
5
  from django import http
7
- from django.views.generic import View
8
- from django.utils import translation
9
-
10
- from lino.api import dd
11
- from lino.core import auth
12
- from lino.core.requests import BaseRequest, ActionRequest
6
+ from django.conf import settings
13
7
  from django.core.exceptions import ObjectDoesNotExist
14
-
15
- from django.shortcuts import redirect
16
- from django.views.decorators.csrf import ensure_csrf_cookie
8
+ from django.utils import translation
9
+ from django.views.generic import View
17
10
 
18
11
 
19
12
  class Element(View):
@@ -39,9 +39,18 @@ class Plugin(ad.Plugin):
39
39
  margin_left = 17
40
40
  margin_right = 10
41
41
  space_before_recipient = 15
42
+ with_bulma = False
43
+
44
+ def get_needed_plugins(self):
45
+ for p in super().get_needed_plugins():
46
+ yield p
47
+ if self.with_bulma:
48
+ yield 'bulma'
42
49
 
43
50
  def get_requirements(self, site):
44
51
  yield "imagesize"
52
+ if self.with_bulma:
53
+ yield 'django-bulma'
45
54
 
46
55
  def pre_site_startup(self, site):
47
56
  for ext in ("jpg", "png"):
@@ -2,22 +2,26 @@
2
2
  # Copyright 2016-2024 Rumma & Ko Ltd
3
3
  # License: GNU Affero General Public License v3 (see file COPYING for details)
4
4
 
5
- from pathlib import Path
6
5
  from lino.modlib.jinja.choicelists import JinjaBuildMethod
7
6
  from lino.modlib.printing.choicelists import BuildMethods
7
+ from lino.api import dd
8
8
 
9
9
  try:
10
10
  from weasyprint import HTML
11
11
  except ImportError:
12
12
  HTML = None
13
13
 
14
- try:
15
- import bulma
16
- from weasyprint import CSS
17
- BULMA_CSS = Path(bulma.__file__).parent / "static/bulma/css/style.min.css"
18
- assert BULMA_CSS.exists()
19
- except ImportError:
20
- BULMA_CSS = None
14
+ BULMA_CSS = None
15
+
16
+ if dd.plugins.weasyprint.with_bulma:
17
+ try:
18
+ from pathlib import Path
19
+ import bulma
20
+ from weasyprint import CSS
21
+ BULMA_CSS = Path(bulma.__file__).parent / "static/bulma/css/style.min.css"
22
+ assert BULMA_CSS.exists()
23
+ except ImportError:
24
+ pass
21
25
 
22
26
 
23
27
  class WeasyBuildMethod(JinjaBuildMethod):
@@ -38,7 +42,8 @@ class WeasyPdfBuildMethod(WeasyBuildMethod):
38
42
  def html2file(self, html, filename, context):
39
43
  pdf = HTML(string=html)
40
44
  if BULMA_CSS and context.get('use_bulma_css', False):
41
- pdf.write_pdf(filename, stylesheets=[CSS(filename=BULMA_CSS)])
45
+ pdf.write_pdf(
46
+ filename, stylesheets=[CSS(filename=BULMA_CSS)])
42
47
  else:
43
48
  pdf.write_pdf(filename)
44
49
 
@@ -31,13 +31,18 @@ table.footer td {
31
31
  border: none;
32
32
  padding: 6pt;
33
33
  }
34
- span.page_num_of::after {
35
- content: '{{_("Page")}} ' counter(page) ' {{_("of {0}").format("")}}' counter(pages);
36
- }
34
+ {#
35
+ Removed after #6179 (The footer of a multipage invoice shows the same
36
+ pagenumber on each page)
37
37
 
38
- span.printed_time::after {
39
- content: '{{_("Printed")}} {{fdm(dd.today())}} {{_("at")}} {{now.time().strftime("%H:%M")}}';
40
- }
38
+ span.page_num_of::after {
39
+ content: '{{_("Page")}} ' counter(page) ' {{_("of {0}").format("")}}' counter(pages);
40
+ }
41
+
42
+ span.printed_time::after {
43
+ content: '{{_("Printed")}} {{fdm(dd.today())}} {{_("at")}} {{now.time().strftime("%H:%M")}}';
44
+ }
45
+ #}
41
46
 
42
47
  body {
43
48
  font-family: "Liberation sans", "Arial", "Helvetica";
@@ -83,13 +88,10 @@ div.recipient {
83
88
  margin-left: {{dd.plugins.weasyprint.margin_left}}mm;
84
89
  margin-right: {{dd.plugins.weasyprint.margin_right}}mm;
85
90
  {%- if dd.plugins.weasyprint.page_background_image -%}
86
- {#
87
- background: url(file://{{dd.plugins.weasyprint.page_background_image}}) no-repeat center center fixed;
88
- #}
89
- background-image: url(file://{{dd.plugins.weasyprint.page_background_image}});
90
- background-repeat: no-repeat;
91
- background-attachment: fixed;
92
- background-size: contain;
91
+ background-image: url(file://{{dd.plugins.weasyprint.page_background_image}});
92
+ background-repeat: no-repeat;
93
+ background-attachment: fixed;
94
+ background-size: contain;
93
95
  {%- endif -%}
94
96
  font-family: "Liberation sans", "arial";
95
97
  font-size: 10pt;
lino/utils/jsgen.py CHANGED
@@ -430,7 +430,8 @@ def py2js(v, compact=True):
430
430
  # raise Exception("Please call the function yourself")
431
431
  return "\n".join([ln for ln in v()])
432
432
  if isinstance(v, MissingRow):
433
- raise Exception("Cannot render {}".format(v))
433
+ return json.dumps(repr(v))
434
+ # raise Exception("Cannot render {}".format(v))
434
435
  if isinstance(v, js_code):
435
436
  return str(v.s) # v.s might be a unicode
436
437
  if v is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lino
3
- Version: 25.7.0
3
+ Version: 25.7.2
4
4
  Summary: A framework for writing desktop-like web applications using Django and ExtJS or React
5
5
  Project-URL: Homepage, https://www.lino-framework.org
6
6
  Project-URL: Repository, https://gitlab.com/lino-framework/lino