Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/24.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dynamically set the value of the related Image, checking the TinyMCE control panel @erral
Empty file.
12 changes: 12 additions & 0 deletions src/cs_dynamicpages/adapters/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:i18n="http://namespaces.zope.org/i18n"
i18n_domain="cs_dynamicpages"
>

<adapter
factory=".patterns.RelatedImageContentbrowserPatternOptions"
name="pattern_options"
/>

</configure>
52 changes: 52 additions & 0 deletions src/cs_dynamicpages/adapters/patterns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
See for some context: https://community.plone.org/t/customizing-contentbrowser-pattern-options/22812

this adapter provides dynamic pattern_options to allow selecting any Image-ish
content-type that previously is enabled in the TinyMCE control-panel as an
"image object"

"""

from ..behaviors.related_image import IImageRelationList
from plone import api


try:
# This is for Plone 6.1
from plone.app.z3cform.interfaces import IContentBrowserWidget
except ImportError:
# This is for previous versions of Plone
from plone.app.z3cform.interfaces import (
IRelatedItemsWidget as IContentBrowserWidget,
)

from z3c.form.interfaces import IValue
from zope.component import adapter
from zope.interface import implementer
from zope.interface import Interface


@implementer(IValue)
@adapter(
Interface, # IContentListingMarker in the original
Interface, # IRequest in the original
Interface, # IForm in the original
IImageRelationList,
IContentBrowserWidget,
)
class RelatedImageContentbrowserPatternOptions:
"""Adapter class for custon pattern options"""

def __init__(self, context, request, form, field, widget):
self.context = context
self.request = request
self.form = form
self.field = field
self.widget = widget

def get(self):
return {
"recentlyUsed": True,
"selectableTypes": api.portal.get_registry_record("plone.image_objects"),
"upload": True,
}
23 changes: 16 additions & 7 deletions src/cs_dynamicpages/behaviors/related_image.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# from plone.app.z3cform.widgets.contentbrowser import ContentBrowserFieldWidget
"""
See https://community.plone.org/t/customizing-contentbrowser-pattern-options/22812
for some context

"""

from cs_dynamicpages import _
from plone.autoform import directives as form
from plone.autoform.interfaces import IFormFieldProvider
Expand All @@ -25,6 +30,15 @@
)


class IImageRelationList(Interface):
pass


@implementer(IImageRelationList)
class ImageRelationList(RelationList):
pass


class IRelatedImageMarker(Interface):
pass

Expand All @@ -33,7 +47,7 @@ class IRelatedImageMarker(Interface):
class IRelatedImage(model.Schema):
""" """

related_image = RelationList(
related_image = ImageRelationList(
title=_("Related image"),
description=_("Select the related image that will be shown in this row"),
default=[],
Expand All @@ -46,11 +60,6 @@ class IRelatedImage(model.Schema):
"related_image",
RelatedImageFieldWidget,
vocabulary="plone.app.vocabularies.Catalog",
pattern_options={
"recentlyUsed": True,
"selectableTypes": ["Image"],
"upload": True,
},
)
image_position = schema.Choice(
title=_("Image position"),
Expand Down
1 change: 1 addition & 0 deletions src/cs_dynamicpages/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@


<include package=".views" />
<include package=".adapters" />



Expand Down
98 changes: 98 additions & 0 deletions src/cs_dynamicpages/tests/test_adapter_patterns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from cs_dynamicpages.adapters.patterns import RelatedImageContentbrowserPatternOptions
from cs_dynamicpages.behaviors.related_image import IImageRelationList
from cs_dynamicpages.testing import CS_DYNAMICPAGES_INTEGRATION_TESTING
from plone import api
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID


try:
from plone.app.z3cform.interfaces import IContentBrowserWidget
except ImportError:
from plone.app.z3cform.interfaces import (
IRelatedItemsWidget as IContentBrowserWidget,
)

from z3c.form.interfaces import IValue
from zope.component import getMultiAdapter
from zope.interface import implementer
from zope.interface import Interface

import unittest


@implementer(Interface)
class DummyContext:
pass


@implementer(Interface)
class DummyRequest:
pass


@implementer(Interface)
class DummyForm:
pass


@implementer(IImageRelationList)
class DummyField:
pass


@implementer(IContentBrowserWidget)
class DummyWidget:
pass


class RelatedImageContentbrowserPatternOptionsTest(unittest.TestCase):
layer = CS_DYNAMICPAGES_INTEGRATION_TESTING

def setUp(self):
"""Custom shared utility setup for tests."""
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])

def test_adapter_registration(self):
context = DummyContext()
request = DummyRequest()
form = DummyForm()
field = DummyField()
widget = DummyWidget()

adapter = getMultiAdapter(
(context, request, form, field, widget), IValue, name="pattern_options"
)
self.assertIsInstance(adapter, RelatedImageContentbrowserPatternOptions)

def test_adapter_get(self):
context = DummyContext()
request = DummyRequest()
form = DummyForm()
field = DummyField()
widget = DummyWidget()

adapter = getMultiAdapter(
(context, request, form, field, widget), IValue, name="pattern_options"
)

api.portal.set_registry_record("plone.image_objects", ["Image"])
self.assertEqual(
adapter.get(),
{
"recentlyUsed": True,
"selectableTypes": ["Image"],
"upload": True,
},
)

api.portal.set_registry_record("plone.image_objects", ["Image", "CustomImage"])
self.assertEqual(
adapter.get(),
{
"recentlyUsed": True,
"selectableTypes": ["Image", "CustomImage"],
"upload": True,
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from cs_dynamicpages.testing import CS_DYNAMICPAGES_FUNCTIONAL_TESTING
from plone import api
from plone.app.testing import setRoles
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
from plone.app.testing import TEST_USER_ID
from plone.testing.zope import Browser

import transaction
import unittest


class RelatedImageFunctionalTest(unittest.TestCase):
layer = CS_DYNAMICPAGES_FUNCTIONAL_TESTING

def setUp(self):
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])

# Create a document and apply the behavior to be able to test the form
self.portal.invokeFactory("Document", "doc1", title="Doc 1")
self.doc1 = self.portal["doc1"]

# Apply the behavior to Document type
fti = api.portal.get_tool("portal_types").getTypeInfo("Document")
behaviors = list(fti.behaviors)
behaviors.append("cs_dynamicpages.related_image")
fti.behaviors = tuple(behaviors)

transaction.commit()

self.browser = Browser(self.layer["app"])
self.browser.handleErrors = False
self.browser.addHeader(
"Authorization", f"Basic {SITE_OWNER_NAME}:{SITE_OWNER_PASSWORD}"
)

def test_related_image_pattern_options_in_browser(self):
# We set the registry record
api.portal.set_registry_record("plone.image_objects", ["Image", "CustomImage"])
transaction.commit()

# Open the edit form of the document
self.browser.open(self.doc1.absolute_url() + "/edit")

# The pattern options should be rendered in the HTML for the related_image field
try:
self.assertIn("data-pat-contentbrowser", self.browser.contents)
except AssertionError:
self.assertIn("data-pat-relateditems", self.browser.contents)

self.assertIn(
"&quot;selectableTypes&quot;: [&quot;Image&quot;, &quot;CustomImage&quot;]",
self.browser.contents,
)

# We change the registry record
api.portal.set_registry_record("plone.image_objects", ["Image"])
transaction.commit()

# Open the edit form again
self.browser.open(self.doc1.absolute_url() + "/edit")

# The pattern options should be updated
self.assertIn(
"&quot;selectableTypes&quot;: [&quot;Image&quot;]", self.browser.contents
)
Loading