imio.smartweb.core 1.1.23__py3-none-any.whl → 1.1.25__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 (36) hide show
  1. imio/smartweb/core/contents/__init__.py +59 -32
  2. imio/smartweb/core/contents/configure.zcml +3 -0
  3. imio/smartweb/core/contents/cropping.py +24 -0
  4. imio/smartweb/core/contents/sections/external_content/configure.zcml +8 -0
  5. imio/smartweb/core/contents/sections/external_content/view.pt +6 -1
  6. imio/smartweb/core/contents/sections/external_content/view_arcgis.pt +149 -0
  7. imio/smartweb/core/contents/sections/external_content/views.py +98 -7
  8. imio/smartweb/core/interfaces.py +7 -0
  9. imio/smartweb/core/profiles/default/metadata.xml +1 -1
  10. imio/smartweb/core/profiles/default/types/imio.smartweb.SectionExternalContent.xml +1 -0
  11. imio/smartweb/core/tests/test_banner.py +3 -3
  12. imio/smartweb/core/tests/test_cropping.py +14 -5
  13. imio/smartweb/core/tests/test_section_external_content.py +6 -6
  14. imio/smartweb/core/tests/test_sections.py +2 -2
  15. imio/smartweb/core/upgrades/configure.zcml +9 -0
  16. imio/smartweb/core/upgrades/upgrades.py +16 -0
  17. imio/smartweb/core/viewlets/arcgis_header.pt +143 -0
  18. imio/smartweb/core/viewlets/banner.py +5 -4
  19. imio/smartweb/core/viewlets/configure.zcml +11 -0
  20. imio/smartweb/core/viewlets/external_content.py +14 -0
  21. imio/smartweb/core/webcomponents/build/css/552.smartweb-webcomponents-compiled.css +1 -1
  22. imio/smartweb/core/webcomponents/build/js/195.smartweb-webcomponents-compiled.js +1 -1
  23. imio/smartweb/core/webcomponents/build/js/510.smartweb-webcomponents-compiled.js +1 -1
  24. imio/smartweb/core/webcomponents/build/js/552.smartweb-webcomponents-compiled.js +1 -1
  25. imio/smartweb/core/webcomponents/src/components/Annuaire/Annuaire.scss +3 -0
  26. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactContent/ContactContent.jsx +10 -11
  27. imio/smartweb/core/webcomponents/src/components/Events/ContactContent/ContactContent.jsx +1 -1
  28. imio/smartweb/core/webcomponents/src/components/News/ContactCard/ContactCard.jsx +5 -1
  29. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/METADATA +24 -1
  30. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/RECORD +36 -33
  31. /imio.smartweb.core-1.1.23-py3.10-nspkg.pth → /imio.smartweb.core-1.1.25-py3.10-nspkg.pth +0 -0
  32. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/LICENSE.GPL +0 -0
  33. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/LICENSE.rst +0 -0
  34. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/WHEEL +0 -0
  35. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/namespace_packages.txt +0 -0
  36. {imio.smartweb.core-1.1.23.dist-info → imio.smartweb.core-1.1.25.dist-info}/top_level.txt +0 -0
@@ -1,32 +1,59 @@
1
- from .blocks.link.content import IBlockLink, BlockLink # NOQA
2
- from .pages.pages import IPages, IDefaultPages, Pages # NOQA
3
- from .folder.content import IFolder, Folder # NOQA
4
- from .pages.cirkwi.content import ICirkwiView, CirkwiView # NOQA
5
- from .pages.footer.content import IFooter, Footer # NOQA
6
- from .pages.herobanner.content import IHeroBanner, HeroBanner # NOQA
7
- from .pages.page.content import IPage, Page # NOQA
8
- from .pages.portal_page.content import IPortalPage, PortalPage # NOQA
9
- from .pages.procedure.content import IProcedure, Procedure # NOQA
10
- from .rest.directory.content import IDirectoryView, DirectoryView # NOQA
11
- from .rest.events.content import IEventsView, EventsView # NOQA
12
- from .rest.news.content import INewsView, NewsView # NOQA
13
- from .sections.base import ISection, Section # NOQA
14
- from .sections.collection.content import ISectionCollection, SectionCollection # NOQA
15
- from .sections.contact.content import ISectionContact, SectionContact # NOQA
16
- from .sections.events.content import ISectionEvents, SectionEvents # NOQA
17
- from .sections.external_content.content import (
18
- ISectionExternalContent,
19
- SectionExternalContent,
20
- ) # NOQA
21
- from .sections.files.content import ISectionFiles, SectionFiles # NOQA
22
- from .sections.gallery.content import ISectionGallery, SectionGallery # NOQA
23
- from .sections.html.content import ISectionHTML, SectionHTML # NOQA
24
- from .sections.links.content import ISectionLinks, SectionLinks # NOQA
25
- from .sections.map.content import ISectionMap, SectionMap # NOQA
26
- from .sections.news.content import ISectionNews, SectionNews # NOQA
27
- from .sections.postit.content import ISectionPostit, SectionPostit # NOQA
28
- from .sections.selections.content import ISectionSelections, SectionSelections # NOQA
29
- from .sections.sendinblue.content import ISectionSendinblue, SectionSendinblue # NOQA
30
- from .sections.slide.content import ISectionSlide, SectionSlide # NOQA
31
- from .sections.text.content import ISectionText, SectionText # NOQA
32
- from .sections.video.content import ISectionVideo, SectionVideo # NOQA
1
+ from .blocks.link.content import BlockLink # NOQA
2
+ from .blocks.link.content import IBlockLink # NOQA
3
+ from .pages.pages import IDefaultPages # NOQA
4
+ from .pages.pages import IPages # NOQA
5
+ from .pages.pages import Pages # NOQA
6
+ from .folder.content import Folder # NOQA
7
+ from .folder.content import IFolder # NOQA
8
+ from .pages.cirkwi.content import CirkwiView # NOQA
9
+ from .pages.cirkwi.content import ICirkwiView # NOQA
10
+ from .pages.footer.content import Footer # NOQA
11
+ from .pages.footer.content import IFooter # NOQA
12
+ from .pages.herobanner.content import HeroBanner # NOQA
13
+ from .pages.herobanner.content import IHeroBanner # NOQA
14
+ from .pages.page.content import IPage # NOQA
15
+ from .pages.page.content import Page # NOQA
16
+ from .pages.portal_page.content import IPortalPage # NOQA
17
+ from .pages.portal_page.content import PortalPage # NOQA
18
+ from .pages.procedure.content import IProcedure # NOQA
19
+ from .pages.procedure.content import Procedure # NOQA
20
+ from .rest.directory.content import DirectoryView # NOQA
21
+ from .rest.directory.content import IDirectoryView # NOQA
22
+ from .rest.events.content import EventsView # NOQA
23
+ from .rest.events.content import IEventsView # NOQA
24
+ from .rest.news.content import INewsView # NOQA
25
+ from .rest.news.content import NewsView # NOQA
26
+ from .sections.base import ISection # NOQA
27
+ from .sections.base import Section # NOQA
28
+ from .sections.collection.content import ISectionCollection # NOQA
29
+ from .sections.collection.content import SectionCollection # NOQA
30
+ from .sections.contact.content import ISectionContact # NOQA
31
+ from .sections.contact.content import SectionContact # NOQA
32
+ from .sections.events.content import ISectionEvents # NOQA
33
+ from .sections.events.content import SectionEvents # NOQA
34
+ from .sections.external_content.content import ISectionExternalContent # NOQA
35
+ from .sections.external_content.content import SectionExternalContent # NOQA
36
+ from .sections.files.content import ISectionFiles # NOQA
37
+ from .sections.files.content import SectionFiles # NOQA
38
+ from .sections.gallery.content import ISectionGallery # NOQA
39
+ from .sections.gallery.content import SectionGallery # NOQA
40
+ from .sections.html.content import ISectionHTML # NOQA
41
+ from .sections.html.content import SectionHTML # NOQA
42
+ from .sections.links.content import ISectionLinks # NOQA
43
+ from .sections.links.content import SectionLinks # NOQA
44
+ from .sections.map.content import ISectionMap # NOQA
45
+ from .sections.map.content import SectionMap # NOQA
46
+ from .sections.news.content import ISectionNews # NOQA
47
+ from .sections.news.content import SectionNews # NOQA
48
+ from .sections.postit.content import ISectionPostit # NOQA
49
+ from .sections.postit.content import SectionPostit # NOQA
50
+ from .sections.selections.content import ISectionSelections # NOQA
51
+ from .sections.selections.content import SectionSelections # NOQA
52
+ from .sections.sendinblue.content import ISectionSendinblue # NOQA
53
+ from .sections.sendinblue.content import SectionSendinblue # NOQA
54
+ from .sections.slide.content import ISectionSlide # NOQA
55
+ from .sections.slide.content import SectionSlide # NOQA
56
+ from .sections.text.content import ISectionText # NOQA
57
+ from .sections.text.content import SectionText # NOQA
58
+ from .sections.video.content import ISectionVideo # NOQA
59
+ from .sections.video.content import SectionVideo # NOQA
@@ -8,6 +8,7 @@
8
8
  <include package=".sections" />
9
9
 
10
10
  <unconfigure>
11
+ <adapter factory="plone.app.imagecropping.dx.CroppingUtilsDexterity" />
11
12
  <adapter
12
13
  for="plone.dexterity.interfaces.IDexterityContent"
13
14
  provides="imio.smartweb.common.interfaces.ICropping"
@@ -15,6 +16,8 @@
15
16
  />
16
17
  </unconfigure>
17
18
 
19
+ <adapter factory=".cropping.SmartwebCroppingUtilsDexterity" />
20
+
18
21
  <adapter
19
22
  for="plone.dexterity.interfaces.IDexterityContent"
20
23
  provides="imio.smartweb.common.interfaces.ICropping"
@@ -1,6 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  from imio.smartweb.common.adapters import BaseCroppingProvider
4
+ from plone.app.imagecropping.dx import CroppingUtilsDexterity
5
+ from plone.app.imagecropping.interfaces import IImageCroppingUtils
6
+ from plone.namedfile.interfaces import IImage
7
+ from plone.namedfile.interfaces import IImageScaleTraversable
8
+ from zope.component import adapter
9
+ from zope.interface import implementer
10
+
11
+
12
+ UNCROPPABLE_FIELDS = ["banner"]
4
13
 
5
14
 
6
15
  class SmartwebCroppingProvider(BaseCroppingProvider):
@@ -14,3 +23,18 @@ class SmartwebCroppingProvider(BaseCroppingProvider):
14
23
  return ["liste", "vignette", "slide"]
15
24
  else:
16
25
  return super(SmartwebCroppingProvider, self).get_scales(fieldname, request)
26
+
27
+
28
+ @implementer(IImageCroppingUtils)
29
+ @adapter(IImageScaleTraversable)
30
+ class SmartwebCroppingUtilsDexterity(CroppingUtilsDexterity):
31
+ def _image_field_values(self):
32
+ """Remove banner field from cropping editor"""
33
+ for fieldname, field in self._all_fields():
34
+ value = getattr(self.context, fieldname, None)
35
+ if (
36
+ value
37
+ and IImage.providedBy(value)
38
+ and fieldname not in UNCROPPABLE_FIELDS
39
+ ):
40
+ yield (fieldname, value)
@@ -11,4 +11,12 @@
11
11
  layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
12
12
  />
13
13
 
14
+ <browser:page
15
+ name="view_arcgis"
16
+ for="*"
17
+ class="imio.smartweb.core.contents.sections.external_content.views.ArcgisView"
18
+ template="view_arcgis.pt"
19
+ permission="zope2.View"
20
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
21
+ />
14
22
  </configure>
@@ -10,10 +10,15 @@
10
10
  <metal:main fill-slot="content-core">
11
11
  <metal:content-core define-macro="content-core">
12
12
  <metal:macro use-macro="context/@@sections_macros/section_edition" />
13
- <div class="container section-container section-video"
13
+ <div class="container section-container section-external-content"
14
14
  id=""
15
15
  tal:attributes="id string:container-section-${context/id}">
16
16
 
17
+
18
+ <tal:check tal:condition="view/has_leadimage">
19
+ <img tal:attributes="src view/image" />
20
+ </tal:check>
21
+
17
22
  <metal:macro use-macro="context/@@sections_macros/section_title" />
18
23
 
19
24
  <p tal:replace="structure context/@@description" />
@@ -0,0 +1,149 @@
1
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
2
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
3
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
4
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
5
+ lang="en"
6
+ metal:use-macro="context/@@main_template/macros/master"
7
+ i18n:domain="plone">
8
+
9
+ <body>
10
+ <metal:main fill-slot="content-core">
11
+ <!-- Master Header -->
12
+ <nav class="navbar navbar-expand-lg sticky-top bg-body-tertiary rounded">
13
+ <!--div class="container-fluid">
14
+ <img src="../assets/img/navapp.png" width="100%" height="100%" />
15
+ </div-->
16
+ </nav>
17
+
18
+ <div id="viewDiv"></div>
19
+
20
+ <div id="titleDiv" class="esri-widget">
21
+ <div id="titleText"><b>Les voiries vicinales</b></div>
22
+ <div>Date de la donnée : 2014</div>
23
+ </div>
24
+
25
+ <div id="backbar">
26
+ <div id="linkBack"><a href=".."><i class="fa-solid fa-arrow-left fa-fade"></i>Retour</a></div>
27
+ </div>
28
+
29
+ <div id="arcgis_item" tal:attributes="data-id view/get_portal_item_id;"></div>
30
+
31
+ <script src="https://js.arcgis.com/4.27/"></script>
32
+ <script language="JavaScript">
33
+ require(["esri/views/MapView", "esri/widgets/Legend", "esri/widgets/Expand", "esri/widgets/Home", "esri/widgets/Search","esri/widgets/BasemapGallery", "esri/widgets/Print", "esri/widgets/LayerList", "esri/WebMap"],
34
+ (
35
+ MapView,
36
+ Legend,
37
+ Expand,
38
+ Home,
39
+ Search,
40
+ BasemapGallery,
41
+ Print,
42
+ LayerList,
43
+ WebMap
44
+ ) => {
45
+ const webmap = new WebMap({
46
+ portalItem: {
47
+ // autocasts as new PortalItem()
48
+ id: document.querySelector("#arcgis_item").dataset.id
49
+ }
50
+ });
51
+
52
+ const view = new MapView({
53
+ container: "viewDiv",
54
+ map: webmap
55
+ });
56
+
57
+ /* Legend */
58
+
59
+ const legend = new Expand({
60
+ content: new Legend({
61
+ view: view,
62
+ style: "classic" // other styles include 'classic'
63
+ }),
64
+ view: view,
65
+ expanded: true
66
+ });
67
+
68
+ view.ui.add(legend, "bottom-left");
69
+
70
+ /* Home */
71
+ const homeBtn = new Home({
72
+ view: view,
73
+ expanded: true
74
+ });
75
+
76
+ view.ui.add(homeBtn, "top-left");
77
+
78
+
79
+ /* Search */
80
+ const searchWidget = new Search({
81
+ view: view
82
+ });
83
+
84
+ SearchExpand = new Expand({
85
+ expandIcon: "search", // see https://developers.arcgis.com/calcite-design-system/icons/
86
+ // expandTooltip: "Expand LayerList", // optional, defaults to "Expand" for English locale
87
+ view: view,
88
+ content: searchWidget
89
+ });
90
+
91
+ /* Basemap Gallery */
92
+ const basemapGallery = new BasemapGallery({
93
+ view: view
94
+ });
95
+
96
+ BasemapGalleryExpand = new Expand({
97
+ expandIcon: "basemap", // see https://developers.arcgis.com/calcite-design-system/icons/
98
+ // expandTooltip: "Expand LayerList", // optional, defaults to "Expand" for English locale
99
+ view: view,
100
+ content: basemapGallery
101
+ });
102
+
103
+ /* Print */
104
+ const print = new Print({
105
+ view: view,
106
+ // specify your own print service
107
+ printServiceUrl:
108
+ "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task"
109
+ });
110
+
111
+ PrintExpand = new Expand({
112
+ expandIcon: "print", // see https://developers.arcgis.com/calcite-design-system/icons/
113
+ // expandTooltip: "Expand LayerList", // optional, defaults to "Expand" for English locale
114
+ view: view,
115
+ content: print
116
+ });
117
+
118
+ /* Layers List */
119
+ const layerList = new LayerList({
120
+ view: view,
121
+ listItemCreatedFunction: (event) => {
122
+ const item = event.item;
123
+ if (item.layer.type != "group") {
124
+ // don't show legend twice
125
+ item.panel = {
126
+ content: "legend",
127
+ open: true
128
+ };
129
+ }
130
+ }
131
+ });
132
+
133
+ layerListExpand = new Expand({
134
+ expandIcon: "layers", // see https://developers.arcgis.com/calcite-design-system/icons/
135
+ // expandTooltip: "Expand LayerList", // optional, defaults to "Expand" for English locale
136
+ view: view,
137
+ content: layerList,
138
+ expanded: false
139
+ });
140
+
141
+ view.ui.add([SearchExpand, BasemapGalleryExpand, PrintExpand, layerListExpand], "top-right");
142
+
143
+ view.ui.add("titleDiv", "bottom-right");
144
+ });
145
+ </script>
146
+ </metal:main>
147
+ </body>
148
+
149
+ </html>
@@ -3,31 +3,63 @@
3
3
  from embeddify import Embedder
4
4
  from embeddify import Plugin
5
5
  from imio.smartweb.core.contents.sections.views import SectionView
6
+ from imio.smartweb.core.interfaces import IArcgisViewUtils
6
7
  from imio.smartweb.locales import SmartwebMessageFactory as _
7
8
  from json.decoder import JSONDecodeError
9
+ from plone import api
10
+ from plone.app.contenttypes.behaviors.leadimage import ILeadImage
11
+ from Products.Five.browser import BrowserView
12
+ from zope.i18n import translate
13
+ from zope.interface import implementer
8
14
 
9
15
  import json
10
16
 
11
17
 
12
18
  class ExternalContentView(SectionView):
13
19
  def get_embed_external_content(self, width="100%", height=600):
20
+ current_lang = api.portal.get_current_language()[:2]
14
21
  plugins = [
15
22
  EaglebePlugin(),
16
23
  EllohaPlugin(),
17
24
  CognitoformPlugin(),
25
+ ArcgisPlugin(),
18
26
  UnknowServicePlugin(),
19
27
  ]
20
28
  extra_params = self.context.external_content_params
21
29
  plugin_config = {
22
30
  "eaglebeplugin": {"width": width},
23
- "ellohaplugin": {"width": width, "extra_params": extra_params},
24
- "cognitoformplugin": {"width": width, "extra_params": extra_params},
25
- "unknowserviceplugin": {"width": width},
31
+ "ellohaplugin": {
32
+ "width": width,
33
+ "current_lang": current_lang,
34
+ "extra_params": extra_params,
35
+ },
36
+ "cognitoformplugin": {
37
+ "width": width,
38
+ "current_lang": current_lang,
39
+ "extra_params": extra_params,
40
+ },
41
+ "arcgisplugin": {
42
+ "width": width,
43
+ "url": self.context.absolute_url(),
44
+ "current_lang": current_lang,
45
+ "extra_params": extra_params,
46
+ },
47
+ "unknowserviceplugin": {"width": width, "current_lang": current_lang},
26
48
  }
27
49
  embedder = Embedder(plugins=plugins, plugin_config=plugin_config)
28
50
  url = self.context.external_content_url
29
51
  return embedder(url, config={"width": width})
30
52
 
53
+ def has_leadimage(self):
54
+ if ILeadImage.providedBy(self.context) and getattr(
55
+ self.context, "image", False
56
+ ):
57
+ return True
58
+ return False
59
+
60
+ def image(self):
61
+ return f"{self.context.absolute_url()}/@@download/image"
62
+
31
63
 
32
64
  class EaglebePlugin(Plugin):
33
65
  def __call__(self, parts, config={}):
@@ -45,8 +77,12 @@ class EllohaPlugin(Plugin):
45
77
  # "ConstellationWidgetContainer": "917c4c52-c997-4077-9135-873a0b2e0c85",
46
78
  # "Idoi": "195ea849-1732-4a69-a051-e7911001cd09"
47
79
  # }
80
+ current_lang = config["current_lang"]
48
81
  extra_params = config["extra_params"]
49
- error_message = '<div class="elloha">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
82
+
83
+ error_message = "With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi"
84
+ error_message = translate(_(error_message), target_language=current_lang)
85
+ error_message = f'<div class="elloha elloha_error">{error_message}</div>'
50
86
 
51
87
  if (
52
88
  extra_params is None
@@ -85,9 +121,16 @@ class EllohaPlugin(Plugin):
85
121
 
86
122
  class CognitoformPlugin(Plugin):
87
123
  def __call__(self, parts, config={}):
88
- extra_params = config["extra_params"]
89
- error_message = '<div class="cognitoform">With a cognitoform plugin, extra params can be void but if you complete it you must specify : scrolling:(yes/no) and overflow:(hidden/scroll/auto)</div>'
90
124
  if "cognitoforms" in parts.netloc:
125
+ current_lang = config["current_lang"]
126
+ extra_params = config["extra_params"]
127
+
128
+ error_message = "With a cognitoform plugin, extra params can be void but if you complete it you must specify : scrolling:(yes/no) and overflow:(hidden/scroll/auto)"
129
+ error_message = translate(_(error_message), target_language=current_lang)
130
+ error_message = (
131
+ f'<div class="cognitoform cognitoform_error">{error_message}</div>'
132
+ )
133
+
91
134
  if extra_params is None:
92
135
  return f'<iframe src="{parts.geturl()}" style="border: 0px none; width: {config["width"]}%; overflow: auto;" scrolling="yes"></iframe>'
93
136
  else:
@@ -108,6 +151,54 @@ class CognitoformPlugin(Plugin):
108
151
  return None
109
152
 
110
153
 
154
+ class ArcgisPlugin(Plugin):
155
+ def __call__(self, parts, config={}):
156
+ if "arcgis" in parts.netloc:
157
+ # url : https://developers.arcgis.com/
158
+ # extra_params : {"portal_item_id":"27a432b0835149e6acd3ac39d0e4349c"}
159
+ current_lang = config["current_lang"]
160
+ extra_params = config["extra_params"]
161
+ url = config["url"]
162
+
163
+ error_message = "With arcgis plugin, extra params must contain a dictionary with one key : portal_item_id"
164
+ error_message = translate(_(error_message), target_language=current_lang)
165
+ error_message = f'<div class="arcgis arcgis_error">{error_message}</div>'
166
+
167
+ if (
168
+ extra_params is None
169
+ or extra_params[0] != "{"
170
+ or extra_params[-1] != "}"
171
+ ):
172
+ return error_message
173
+ try:
174
+ res = json.loads(extra_params.lower())
175
+ except JSONDecodeError:
176
+ return error_message
177
+ if res.get("portal_item_id") is None:
178
+ return error_message
179
+
180
+ portal_item_id = res.get("portal_item_id")
181
+ msg = "Consult the map"
182
+ msg = translate(_(msg), target_language=current_lang)
183
+ return (
184
+ f'<a href="{url}/view_arcgis?portal_item_id={portal_item_id}">{msg}</a>'
185
+ )
186
+ #
187
+ return None
188
+
189
+
111
190
  class UnknowServicePlugin(Plugin):
112
191
  def __call__(self, parts, config={}):
113
- return _("<p class='unknow_service'>Unknow service</p>")
192
+ current_lang = config["current_lang"]
193
+ msg = "Unknow service"
194
+ msg = translate(_(msg), target_language=current_lang)
195
+ return f'<p class="unknow_service">{msg}</p>'
196
+
197
+
198
+ @implementer(IArcgisViewUtils)
199
+ class ArcgisView(BrowserView):
200
+ _footer = None
201
+
202
+ @property
203
+ def get_portal_item_id(self):
204
+ return self.request.portal_item_id
@@ -24,3 +24,10 @@ class IImioSmartwebCoreLayer(
24
24
  ICollectiveMessagesviewletLayer,
25
25
  ):
26
26
  """Marker interface that defines a browser layer."""
27
+
28
+
29
+ class IArcgisViewUtils(Interface):
30
+ """ """
31
+
32
+ def get_portal_item_id():
33
+ """Return id of a map"""
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0' encoding='UTF-8'?>
2
2
  <metadata>
3
- <version>1044</version>
3
+ <version>1045</version>
4
4
  <dependencies>
5
5
  <dependency>profile-plone.app.dexterity:default</dependency>
6
6
  <dependency>profile-plone.app.imagecropping:default</dependency>
@@ -27,6 +27,7 @@
27
27
  <!-- Enabled behaviors -->
28
28
  <property name="behaviors" purge="false">
29
29
  <element value="plone.namefromtitle"/>
30
+ <element value="plone.leadimage"/>
30
31
  <element value="plone.locking"/>
31
32
  <element value="plone.shortname"/>
32
33
  <element value="imio.smartweb.topics"/>
@@ -34,7 +34,7 @@ class TestBanner(ImioSmartwebTestCase):
34
34
  self.folder.banner = NamedBlobImage(**make_named_image())
35
35
  self.assertTrue(viewlet.available())
36
36
  self.assertIn(
37
- "background-image:url(http://nohost/plone/folder/@@images/banner-1920",
37
+ "background-image:url(http://nohost/plone/folder/@@images/banner?cache_key=",
38
38
  viewlet.background_style(),
39
39
  )
40
40
  template = self.folder.restrictedTraverse("view")
@@ -124,7 +124,7 @@ class TestBanner(ImioSmartwebTestCase):
124
124
  # css_bg_image = f"background-image:url({scale.url});"
125
125
  # css_bg_size = "background-size:cover;"
126
126
  self.assertIn(
127
- "background-image:url(http://nohost/plone/folder/@@images/banner-1920",
127
+ "background-image:url(http://nohost/plone/folder/@@images/banner?cache_key=",
128
128
  subfolder_viewlet.background_style(),
129
129
  )
130
130
  page_viewlet = BannerViewlet(page, self.request, None, None)
@@ -132,7 +132,7 @@ class TestBanner(ImioSmartwebTestCase):
132
132
  self.assertTrue(page_viewlet.available())
133
133
  self.assertFalse(page_viewlet.is_banner_locally_hidden)
134
134
  self.assertIn(
135
- "background-image:url(http://nohost/plone/folder/@@images/banner-1920",
135
+ "background-image:url(http://nohost/plone/folder/@@images/banner?cache_key=",
136
136
  page_viewlet.background_style(),
137
137
  )
138
138
 
@@ -3,9 +3,10 @@
3
3
  from imio.smartweb.common.interfaces import ICropping
4
4
  from imio.smartweb.core.testing import IMIO_SMARTWEB_CORE_FUNCTIONAL_TESTING
5
5
  from imio.smartweb.core.testing import ImioSmartwebTestCase
6
- from imio.smartweb.core.tests.utils import make_named_image
7
6
  from imio.smartweb.core.tests.utils import get_sections_types
7
+ from imio.smartweb.core.tests.utils import make_named_image
8
8
  from plone import api
9
+ from plone.app.imagecropping.interfaces import IImageCroppingUtils
9
10
  from plone.app.testing import TEST_USER_ID
10
11
  from plone.app.testing import setRoles
11
12
  from plone.namedfile.file import NamedBlobImage
@@ -90,13 +91,21 @@ class TestCropping(ImioSmartwebTestCase):
90
91
  self.assertEqual([], adapter.get_scales("background_image", self.request))
91
92
  self.assertNotIn("banner", adapter.get_scales("image", self.request))
92
93
 
94
+ def test_uncroppable_fields(self):
95
+ self.folder.banner = NamedBlobImage(**make_named_image("plone.png"))
96
+ self.folder.image = NamedBlobImage(**make_named_image("plone.png"))
97
+ adapter = IImageCroppingUtils(self.folder, alternate=None)
98
+ self.assertIsNotNone(adapter)
99
+ self.assertEqual(len(list(adapter._image_field_values())), 1)
100
+ self.assertEqual(adapter.image_field_names(), ["image"])
101
+
93
102
  def test_cropping_view(self):
103
+ self.folder.banner = NamedBlobImage(**make_named_image("plone.png"))
104
+ self.folder.image = NamedBlobImage(**make_named_image("plone.png"))
94
105
  cropping_view = getMultiAdapter(
95
106
  (self.folder, self.request), name="croppingeditor"
96
107
  )
97
108
  self.assertEqual(len(list(cropping_view._scales("banner"))), 0)
98
109
  self.assertEqual(len(list(cropping_view._scales("image"))), 3)
99
- cropping_view = getMultiAdapter(
100
- (self.page, self.request), name="croppingeditor"
101
- )
102
- self.assertEqual(len(list(cropping_view._scales("image"))), 3)
110
+ self.assertNotIn("Banner", cropping_view())
111
+ self.assertIn("Lead Image", cropping_view())
@@ -29,7 +29,7 @@ class TestSectionExternalContent(ImioSmartwebTestCase):
29
29
  section_view = queryMultiAdapter((sec, self.request), name="view")
30
30
  self.assertEqual(
31
31
  section_view.get_embed_external_content(),
32
- "<p class='unknow_service'>Unknow service</p>",
32
+ '<p class="unknow_service">Unknow service</p>',
33
33
  )
34
34
 
35
35
  def test_eaglebe_plugin(self):
@@ -41,7 +41,7 @@ class TestSectionExternalContent(ImioSmartwebTestCase):
41
41
  section_view = queryMultiAdapter((sec, self.request), name="view")
42
42
  self.assertEqual(
43
43
  section_view.get_embed_external_content(),
44
- "<p class='unknow_service'>Unknow service</p>",
44
+ '<p class="unknow_service">Unknow service</p>',
45
45
  )
46
46
 
47
47
  sec.external_content_url = "https://app.eaglebe.com/auth/start"
@@ -63,7 +63,7 @@ class TestSectionExternalContent(ImioSmartwebTestCase):
63
63
  section_view = queryMultiAdapter((sec, self.request), name="view")
64
64
  self.assertEqual(
65
65
  section_view.get_embed_external_content(),
66
- '<div class="elloha">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>',
66
+ '<div class="elloha elloha_error">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>',
67
67
  )
68
68
 
69
69
  # with good extra params
@@ -87,14 +87,14 @@ class TestSectionExternalContent(ImioSmartwebTestCase):
87
87
  # with bad params
88
88
  sec.external_content_params = "kamoulox"
89
89
  section_view = queryMultiAdapter((sec, self.request), name="view")
90
- result = '<div class="elloha">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
90
+ result = '<div class="elloha elloha_error">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
91
91
  self.assertEqual(section_view.get_embed_external_content(), result)
92
92
 
93
93
  sec.external_content_params = """{
94
94
  "ConstellationWidgetContainer" : "11111111-1111-1111-1111-111111111111"
95
95
  }"""
96
96
  section_view = queryMultiAdapter((sec, self.request), name="view")
97
- result = '<div class="elloha">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
97
+ result = '<div class="elloha elloha_error">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
98
98
  self.assertEqual(section_view.get_embed_external_content(), result)
99
99
 
100
100
  sec.external_content_params = """{
@@ -102,5 +102,5 @@ class TestSectionExternalContent(ImioSmartwebTestCase):
102
102
  "IDOI" : "22222222-2222-2222-2222-222222222222"
103
103
  """
104
104
  section_view = queryMultiAdapter((sec, self.request), name="view")
105
- result = '<div class="elloha">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
105
+ result = '<div class="elloha elloha_error">With an elloha plugin, extra params must contain a dictionary with two keys : ConstellationWidgetContainer, Idoi</div>'
106
106
  self.assertEqual(section_view.get_embed_external_content(), result)
@@ -142,7 +142,7 @@ class TestSections(ImioSmartwebTestCase):
142
142
  embedded_content = view.get_embed_external_content()
143
143
  self.assertNotIn("iframe", embedded_content)
144
144
  self.assertNotIn("class='eaglebe'", embedded_content)
145
- self.assertIn("<p class='unknow_service'>Unknow service</p>", embedded_content)
145
+ self.assertIn('<p class="unknow_service">Unknow service</p>', embedded_content)
146
146
 
147
147
  def test_map_section(self):
148
148
  section = api.content.create(
@@ -217,7 +217,7 @@ class TestSections(ImioSmartwebTestCase):
217
217
  items = view.items()
218
218
  self.assertEqual(len(items), 2)
219
219
  self.assertEqual(len(items[0]), 3)
220
- self.assertEqual(reduce(lambda count, l: count + len(l), items, 0), 6)
220
+ self.assertEqual(reduce(lambda count, r: count + len(r), items, 0), 6)
221
221
  section_collection.nb_results_by_batch = 1
222
222
  section_collection.max_nb_batches = 4
223
223
  view = queryMultiAdapter((section_collection, self.request), name="table_view")