From 3a1e28e381bff1a7155e32b6402fde80b5928988 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 21 Jul 2025 17:46:06 -0500 Subject: [PATCH 01/22] fix: inaccurate text picture template name (#967) * fix: inaccurate text picture template name * fix: show value if old template is in use --- taccsite_cms/settings.py | 3 +- .../no_link_to_ext_image/picture.html | 30 ++----------------- .../no_link_to_image/picture.html | 28 +++++++++++++++++ 3 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index ed6927309..335f094a8 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -580,7 +580,8 @@ def get_subdirs_as_module_names(path): ('center', _('Align center')), ] DJANGOCMS_PICTURE_TEMPLATES = [ - ('no_link_to_ext_image', _('Do not link to external image')), + ('no_link_to_image', _('Do not link to image to itself')), + ('no_link_to_ext_image', _('Do not link to image to itself (DEPRECATED)')), ] # FILE UPLOAD VALUES MUST BE SET! diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html index 479af2ce9..02d1d1e97 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html @@ -1,28 +1,2 @@ -{% extends "djangocms_picture/default/picture.html" %} -{# Do not let instance.external_picture trigger picture_link templating #} -{% comment %} -App djangocms_picture assumes external image must be linked to, -but we want to allow external image to be displayed without link. -{% endcomment %} -{# FAQ: picture_link is instance link_url or link_page_id or external_picture #} -{# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L269-L276 #} - -{# So picture with external image is not wrapped in a link #} -{% block picture_link_start %} - {% if instance.link_url or instance.link_page_id %} - {% block picture_link %} - {{ block.super }} - {% endblock %} - {% endif %} -{% endblock %} - -{# So picture attributes can be added to picture with external image #} -{% block picture_attributes %} - {% if not instance.caption_text and not instance.link_url and not instance.link_page_id and not instance.child_plugin_instances %} - {{ instance.attributes_str }} - {% endif %} -{% endblock %} - -{# So picture with external image is not wrapped in a link #} -{% block picture_link_end %} -{% endblock %} +{# backwards-compatibility for old name #} +{% extends "../no_link_to_image/picture.html" %} diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html new file mode 100644 index 000000000..479af2ce9 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html @@ -0,0 +1,28 @@ +{% extends "djangocms_picture/default/picture.html" %} +{# Do not let instance.external_picture trigger picture_link templating #} +{% comment %} +App djangocms_picture assumes external image must be linked to, +but we want to allow external image to be displayed without link. +{% endcomment %} +{# FAQ: picture_link is instance link_url or link_page_id or external_picture #} +{# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L269-L276 #} + +{# So picture with external image is not wrapped in a link #} +{% block picture_link_start %} + {% if instance.link_url or instance.link_page_id %} + {% block picture_link %} + {{ block.super }} + {% endblock %} + {% endif %} +{% endblock %} + +{# So picture attributes can be added to picture with external image #} +{% block picture_attributes %} + {% if not instance.caption_text and not instance.link_url and not instance.link_page_id and not instance.child_plugin_instances %} + {{ instance.attributes_str }} + {% endif %} +{% endblock %} + +{# So picture with external image is not wrapped in a link #} +{% block picture_link_end %} +{% endblock %} From 893a434c0b07933fcf446be4dcec4002eff90726 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 21 Jul 2025 20:41:47 -0500 Subject: [PATCH 02/22] refactor: no_link_to_image --- taccsite_cms/settings.py | 4 ++-- .../djangocms_picture/no_link_to_ext_image/picture.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 335f094a8..1b8c026c0 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -580,8 +580,8 @@ def get_subdirs_as_module_names(path): ('center', _('Align center')), ] DJANGOCMS_PICTURE_TEMPLATES = [ - ('no_link_to_image', _('Do not link to image to itself')), - ('no_link_to_ext_image', _('Do not link to image to itself (DEPRECATED)')), + ('no_link_to_image', _('Do not link image to itself')), + ('no_link_to_ext_image', _('Do not link image to itself (DEPRECATED)')), ] # FILE UPLOAD VALUES MUST BE SET! diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html index 02d1d1e97..55b62f679 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html @@ -1,2 +1,2 @@ -{# backwards-compatibility for old name #} -{% extends "../no_link_to_image/picture.html" %} +{# backwards-compatibility for old name #} +{% extends "djangocms_picture/no_link_to_image/picture.html" %} From 91cc70c7712f15b0531f99f01ecd02e2e99efd32 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:13:57 -0500 Subject: [PATCH 03/22] docs: simplify no_link_to_image/picture.html notes --- .../djangocms_picture/no_link_to_image/picture.html | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html index 479af2ce9..c56826db6 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html @@ -1,11 +1,6 @@ {% extends "djangocms_picture/default/picture.html" %} -{# Do not let instance.external_picture trigger picture_link templating #} -{% comment %} -App djangocms_picture assumes external image must be linked to, -but we want to allow external image to be displayed without link. -{% endcomment %} -{# FAQ: picture_link is instance link_url or link_page_id or external_picture #} -{# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/models.py#L269-L276 #} +{# To allow image to be rendered without a link #} +{# FAQ: App djangocms_picture assumes that an image, if not explicitely linked, must link to itself. But sometimes, we want an image to just be an image, unlinked. #} {# So picture with external image is not wrapped in a link #} {% block picture_link_start %} From 8cbb4a9a0b46a5574fb750ebecd37c742083f07b Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:15:17 -0500 Subject: [PATCH 04/22] docs: clarify no_link_to_image/picture.html notes --- .../djangocms_picture/no_link_to_image/picture.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html index c56826db6..1aa0ed869 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html @@ -2,7 +2,7 @@ {# To allow image to be rendered without a link #} {# FAQ: App djangocms_picture assumes that an image, if not explicitely linked, must link to itself. But sometimes, we want an image to just be an image, unlinked. #} -{# So picture with external image is not wrapped in a link #} +{# So picture is not wrapped in a link #} {% block picture_link_start %} {% if instance.link_url or instance.link_page_id %} {% block picture_link %} @@ -11,13 +11,13 @@ {% endif %} {% endblock %} -{# So picture attributes can be added to picture with external image #} +{# So picture attributes are added to unlinked picture #} {% block picture_attributes %} {% if not instance.caption_text and not instance.link_url and not instance.link_page_id and not instance.child_plugin_instances %} {{ instance.attributes_str }} {% endif %} {% endblock %} -{# So picture with external image is not wrapped in a link #} +{# So picture is not wrapped in a link #} {% block picture_link_end %} {% endblock %} From 6d7b730ed4a8a8f25c1876c30252ecc96f00910e Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:40:05 -0500 Subject: [PATCH 05/22] docs: djangocms_picture template indentation --- .../templates/djangocms_picture/default/picture.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/taccsite_cms/templates/djangocms_picture/default/picture.html b/taccsite_cms/templates/djangocms_picture/default/picture.html index 15f50ab31..a06dc8093 100644 --- a/taccsite_cms/templates/djangocms_picture/default/picture.html +++ b/taccsite_cms/templates/djangocms_picture/default/picture.html @@ -19,9 +19,9 @@ {{ instance.attributes_str }} {# /TACC #} {{ instance.link_attributes_str }}> -{# TACC (allow link to be conditional): #} -{% endblock %} -{# /TACC #} + {# TACC (allow link to be conditional): #} + {% endblock %} + {# /TACC #} {% endif %} {# TACC (allow link to be conditional): #} {% endblock %} From 7f3ec2106a6dbb0fec209c4946d9c892f50be856 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Fri, 25 Jul 2025 13:15:37 -0500 Subject: [PATCH 06/22] feat: support core-styles u-image-zoom (#968) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support core-styles u-image-zoom * feat: support core-styles u-image-zoom via script * Revert "feat: support core-styles u-image-zoom via script" This reverts commit 2a15a75f5cdd718ec4191d656cf200172fdeaba1. * feat: support zoom_effect + no_link_to_image * refactor: only load css once from multiple tries * refactor: extract link & figure start to templates * refactor: rebuild zoom templates to strip classes * feat: template tag `strip_class_attribute` * fix: strip_class_attribute munges data-class test * fix: template name/path typo * fix: all picture template bugs i think * docs: add help_text to Picture template field * feat: overwrite bs4 picture plugin validation * fix: strip_class_attr… regex munges `data-class` * test: highlight unsupported figure image zoom * fix: u-image-zoom-- class not added * fix: sometimes span missing & class in wrong spot * fix: core-styles zoom bug * enhance: clearer debuging ui * refactor: template logic → custom view context * Revert "refactor: template logic → custom view context" This reverts commit a12356870decb3341347a74f7d8d985ffd309f22. --- taccsite_cms/apps.py | 4 + .../cms_plugins.py | 23 ---- taccsite_cms/djangocms_picture/extend.py | 107 ++++++++++++++++++ taccsite_cms/settings.py | 3 +- .../djangocms_picture/default/picture.html | 36 +++--- .../default/picture_link_start.html | 18 +++ .../no_link_to_image/picture.html | 7 +- .../zoom_effect/picture.html | 24 ++++ .../zoom_effect/zoom_asset.html | 7 ++ .../zoom_effect/zoom_wrapper_end.html | 1 + .../zoom_effect/zoom_wrapper_start.html | 1 + .../zoom_effect_no_link_to_image/picture.html | 30 +++++ .../test/css-image-picture-block.html | 74 ++++++++++++ .../templatetags/strip_class_attribute.py | 22 ++++ 14 files changed, 315 insertions(+), 42 deletions(-) delete mode 100644 taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py create mode 100644 taccsite_cms/djangocms_picture/extend.py create mode 100644 taccsite_cms/templates/djangocms_picture/default/picture_link_start.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html create mode 100644 taccsite_cms/templates/snippets/test/css-image-picture-block.html create mode 100644 taccsite_cms/templatetags/strip_class_attribute.py diff --git a/taccsite_cms/apps.py b/taccsite_cms/apps.py index f3bdc022a..64d8e4bde 100644 --- a/taccsite_cms/apps.py +++ b/taccsite_cms/apps.py @@ -1,7 +1,10 @@ import logging + from django.apps import AppConfig from django.db.models.signals import post_migrate +from .djangocms_picture.extend import extendPicturePlugin + logger = logging.getLogger(f"portal.{__name__}") class TaccsiteCmsConfig(AppConfig): @@ -10,6 +13,7 @@ class TaccsiteCmsConfig(AppConfig): def ready(self): post_migrate.connect(self.create_groups, sender=self) + extendPicturePlugin() def create_groups(self, sender, **kwargs): from django.contrib.auth.models import Group diff --git a/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py b/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py deleted file mode 100644 index 3edf41136..000000000 --- a/taccsite_cms/contrib/bootstrap4_djangocms_picture/cms_plugins.py +++ /dev/null @@ -1,23 +0,0 @@ -# To support generic Image plugin without uninstalling Bootstrap's -# FAQ: Bootstrap Image plugin has features not desirable in TACC plugins -# FAQ: We must not break sites that already use Bootstrap Image plugin -try: - from django.utils.translation import gettext as _ - - from cms.plugin_pool import plugin_pool - - from djangocms_picture.cms_plugins import PicturePlugin - from djangocms_bootstrap4.contrib.bootstrap4_picture.cms_plugins import Bootstrap4PicturePlugin - - # To clairfy for users how this plugin differs from Generic > Image - Bootstrap4PicturePlugin.name = _('Picture / Image (Responsive)') - - # To re-register generic Picture plugin - # SEE: https://github.com/django-cms/djangocms-bootstrap4/blob/master/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py#L54 - plugin_pool.register_plugin(PicturePlugin) - -# To avoid server crash if Boostrap plugin is not registered -# CAVEAT: If import statement fails for reason other than Bootstrap presence, -# then that failure, and the failure of this plugin, is silent -except ImportError: - pass diff --git a/taccsite_cms/djangocms_picture/extend.py b/taccsite_cms/djangocms_picture/extend.py new file mode 100644 index 000000000..6e93159e9 --- /dev/null +++ b/taccsite_cms/djangocms_picture/extend.py @@ -0,0 +1,107 @@ +import logging + +logger = logging.getLogger(f"django.{__name__}") + +def extendPicturePlugin(): + from django.core.exceptions import ValidationError + from django.utils.translation import gettext_lazy as _ + + from cms.plugin_pool import plugin_pool + + from djangocms_link.cms_plugins import LinkPlugin + + ZOOM_TEMPLATE_NAME_PREFIX = 'zoom' + ZOOM_TEMPLATE_LABEL = 'Zoom image on hover' + ZOOM_TEMPLATE_NOTE = _('The "%(zoom_template_label)s" templates only have effect if Image either has a Link or is within a Link.') % {"zoom_template_label": ZOOM_TEMPLATE_LABEL} + ZOOM_TEMPLATE_ERROR = _(' "%(zoom_template_label)s" templates require Image to either have a Link or be within a Link.') % {"zoom_template_label": ZOOM_TEMPLATE_LABEL} + + logger.info("Extending PicturePlugin (and Bootstrap4PicturePlugin)...") + + def add_help_text(form_instance): + """Adds help text for: 'Template' field""" + + if 'template' in form_instance.fields: + form_instance.fields['template'].help_text += _(' %(ZOOM_TEMPLATE_NOTE)s') % {"ZOOM_TEMPLATE_NOTE": ZOOM_TEMPLATE_NOTE} + + + def validate_zoom_template(instance): + """Validates: 'Template' field choice 'Zoom image …'""" + + errors = {} + + has_picture_link = bool(instance.link_url or instance.link_page_id) + use_zoom_template = ZOOM_TEMPLATE_NAME_PREFIX in instance.template + parent_plugin = instance.parent.get_plugin_instance()[0] if instance.parent else None + is_in_link = isinstance(parent_plugin, LinkPlugin) if parent_plugin else False + + logger.info(f'validate_zoom_template: %s', { + 'link': instance.link_url or instance.link_page_id, + 'has_picture_link' : has_picture_link, + 'use_zoom_template' : use_zoom_template, + 'is_in_link': is_in_link, + }) + + if (use_zoom_template and not has_picture_link and not is_in_link ): + errors['template'] = ZOOM_TEMPLATE_ERROR + + if errors: + raise ValidationError(errors) + + + # djangocms_picture + from djangocms_picture.cms_plugins import PicturePlugin as OriginalPicturePlugin + from djangocms_picture.models import Picture as OriginalPicture + + class PicturePluginForm(OriginalPicturePlugin.form): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + add_help_text(self) + + class PicturePluginModel(OriginalPicture): + class Meta: + proxy = True + + def clean(self): + super().clean() + validate_zoom_template(self) + + class PicturePlugin(OriginalPicturePlugin): + model = PicturePluginModel + form = PicturePluginForm + name = 'Image' + + # To support generic Image plugin without uninstalling Bootstrap's + # FAQ: Had been done cuz Image plugin had percieved use cases, + # but is since not regularly used, but is used, thus maintained + # FAQ: No need to unregister cuz Bootstrap4PicturePlugin does that + # https://github.com/django-cms/djangocms-bootstrap4/blob/3.0.0/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py#L54 + # plugin_pool.unregister_plugin(OriginalPicturePlugin) + plugin_pool.register_plugin(PicturePlugin) + + + # djangocms_bootstrap4: bootstrap4_picture + from djangocms_bootstrap4.contrib.bootstrap4_picture.cms_plugins import Bootstrap4PicturePlugin as OriginalBootstrap4PicturePlugin + from djangocms_bootstrap4.contrib.bootstrap4_picture.models import Bootstrap4Picture as OriginalBootstrap4Picture + + class Bootstrap4PictureForm(OriginalBootstrap4PicturePlugin.form): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + add_help_text(self) + + class Bootstrap4PictureModel(OriginalBootstrap4Picture): + class Meta: + proxy = True + + def clean(self): + super().clean() + validate_zoom_template(self) + + class Bootstrap4PicturePlugin(OriginalBootstrap4PicturePlugin): + model = Bootstrap4PictureModel + form = Bootstrap4PictureForm + name = 'Picture / Image (Responsive)' + + plugin_pool.unregister_plugin(OriginalBootstrap4PicturePlugin) + plugin_pool.register_plugin(Bootstrap4PicturePlugin) + + logger.info("Extended PicturePlugin (and Bootstrap4PicturePlugin).") diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 1b8c026c0..41b59a56c 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -481,7 +481,6 @@ def gettext(s): return s # django CMS Bootstrap # IDEA: Extend Bootstrap apps instead of overwrite 'taccsite_cms.contrib.bootstrap4_djangocms_link', - 'taccsite_cms.contrib.bootstrap4_djangocms_picture', # TACC CMS Plugins 'djangocms_tacc_image_gallery', @@ -582,6 +581,8 @@ def get_subdirs_as_module_names(path): DJANGOCMS_PICTURE_TEMPLATES = [ ('no_link_to_image', _('Do not link image to itself')), ('no_link_to_ext_image', _('Do not link image to itself (DEPRECATED)')), + ('zoom_effect', _('Zoom image on hover')), + ('zoom_effect_no_link_to_image', _('Zoom image on hover & Do not link image to itself')), ] # FILE UPLOAD VALUES MUST BE SET! diff --git a/taccsite_cms/templates/djangocms_picture/default/picture.html b/taccsite_cms/templates/djangocms_picture/default/picture.html index a06dc8093..ddcf3db2b 100644 --- a/taccsite_cms/templates/djangocms_picture/default/picture.html +++ b/taccsite_cms/templates/djangocms_picture/default/picture.html @@ -10,36 +10,34 @@ {% block picture_link_start %} {# /TACC #} {% if picture_link %} - {# TACC (allow link to be conditional): #} - {% block picture_link %} - {# /TACC #} - - {# TACC (allow link to be conditional): #} - {% endblock %} + {% include "djangocms_picture/default/picture_link_start.html" %} {# /TACC #} {% endif %} {# TACC (allow link to be conditional): #} {% endblock %} {# /TACC #} -{# start render figure/figcaption #} +{# TACC (allow figure to be overridden): #} +{% block picture_figure_start %} +{# /TACC #} {# TACC (support children as caption content): #} {# {% if instance.caption_text %} #} {% if instance.caption_text or instance.child_plugin_instances %} {# TACC (assign attributes to parent): #} - {#
#}
{# /TACC #} {% endif %} {# /TACC #} -{# end render figure/figcaption #} +{# TACC (allow figure to be overridden): #} +{% endblock %} +{# /TACC #} +{# TACC (allow image wrapper): #} +{% block picture_wrap_start %} +{% endblock picture_wrap_start %} +{# /TACC #} {# TACC (mimic v3.0.0 to v4.0.0 changes): #} {% localize off %} {# /TACC #} @@ -74,8 +72,14 @@ {# TACC (mimic v3.0.0 to v4.0.0 changes): #} {% endlocalize %} {# /TACC #} +{# TACC (allow_image_wrapper): #} +{% block picture_wrap_end %} +{% endblock picture_wrap_end %} +{# /TACC #} -{# start render figure/figcaption #} +{# TACC (allow figure to be overridden): #} +{% block picture_figure_end %} +{# /TACC #} {# {% if instance.caption_text %} #} {% if instance.caption_text or instance.child_plugin_instances %} {# TACC (support children as caption content): #} @@ -89,7 +93,9 @@ {# /TACC #}
{% endif %} -{# end render figure/figcaption #} +{# TACC (allow figure to be overridden): #} +{% endblock %} +{# /TACC #} {# TACC (allow link to be conditional): #} {% block picture_link_end %} diff --git a/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html b/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html new file mode 100644 index 000000000..fb2c5a0a4 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html @@ -0,0 +1,18 @@ +{# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/templates/djangocms_picture/default/picture.html#L4-L6 #} + +{# @var className #} +{% load strip_class_attribute %} + +
diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html index 1aa0ed869..ad60a5d4c 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html @@ -5,9 +5,7 @@ {# So picture is not wrapped in a link #} {% block picture_link_start %} {% if instance.link_url or instance.link_page_id %} - {% block picture_link %} - {{ block.super }} - {% endblock %} + {% include "djangocms_picture/default/picture_link_start.html" %} {% endif %} {% endblock %} @@ -20,4 +18,7 @@ {# So picture is not wrapped in a link #} {% block picture_link_end %} + {% if instance.link_url or instance.link_page_id %} + + {% endif %} {% endblock %} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html new file mode 100644 index 000000000..993517ec0 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html @@ -0,0 +1,24 @@ +{% extends "djangocms_picture/default/picture.html" %} + +{# Add u-image-zoom class on link if link is present without figure #} +{% block picture_link_start %} + {% if picture_link and not instance.caption_text and not instance.child_plugin_instances %} + {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} + {% include "djangocms_picture/default/picture_link_start.html" with className="u-image-zoom--on-hover" %} + {% else %} + {{ block.super }} + {% endif %} +{% endblock %} + +{# Add u-image-zoom class on image wrapper if no link #} +{% block picture_wrap_start %} + {% if instance.caption_text or instance.child_plugin_instances or not picture_link %} + {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} + {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} + {% endif %} +{% endblock %} +{% block picture_wrap_end %} + {% if instance.caption_text or instance.child_plugin_instances or not picture_link %} + {% include "djangocms_picture/zoom_effect/zoom_wrapper_end.html" %} + {% endif %} +{% endblock %} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html new file mode 100644 index 000000000..230e3e264 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html @@ -0,0 +1,7 @@ +{% load sekizai_tags %} + +{% addtoblock "css" %} + +{% endaddtoblock %} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html new file mode 100644 index 000000000..294567489 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html @@ -0,0 +1 @@ + diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html new file mode 100644 index 000000000..7998a3d33 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html @@ -0,0 +1 @@ + diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html new file mode 100644 index 000000000..c882de1cf --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html @@ -0,0 +1,30 @@ +{% extends "djangocms_picture/no_link_to_image/picture.html" %} + +{# Add u-image-zoom class on link if link is present without figure #} +{% block picture_link_start %} + {% if instance.link_url or instance.link_page_id %} + {% if not instance.caption_text and not instance.child_plugin_instances %} + {% include "djangocms_picture/default/picture_link_start.html" with className="u-image-zoom--on-hover" %} + {% else %} + {{ block.super }} + {% endif %} + {% else %} + {{ block.super }} + {% endif %} +{% endblock %} + +{# Add u-image-zoom class on image wrapper if no link and no figure #} +{% block picture_wrap_start %} + {% if instance.caption_text or instance.child_plugin_instances %} + {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} + {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} + {% elif not instance.link_url and not instance.link_page_id %} + {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} + {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} + {% endif %} +{% endblock %} +{% block picture_wrap_end %} + {% if instance.caption_text or instance.child_plugin_instances or not instance.link_url and not instance.link_page_id %} + {% include "djangocms_picture/zoom_effect/zoom_wrapper_end.html" %} + {% endif %} +{% endblock %} diff --git a/taccsite_cms/templates/snippets/test/css-image-picture-block.html b/taccsite_cms/templates/snippets/test/css-image-picture-block.html new file mode 100644 index 000000000..78e4b70df --- /dev/null +++ b/taccsite_cms/templates/snippets/test/css-image-picture-block.html @@ -0,0 +1,74 @@ + diff --git a/taccsite_cms/templatetags/strip_class_attribute.py b/taccsite_cms/templatetags/strip_class_attribute.py new file mode 100644 index 000000000..24a55b428 --- /dev/null +++ b/taccsite_cms/templatetags/strip_class_attribute.py @@ -0,0 +1,22 @@ +from django import template +import re + +register = template.Library() + +@register.filter +def strip_class_attribute(attributes_str): + """ + Remove class attribute from an HTML attributes string. + Usage: {{ instance.attributes_str|strip_class_attribute|safe }} + """ + if not attributes_str: + return "" + + # To remove `class="…"` or anything equivalent + pattern = r'(? Date: Fri, 25 Jul 2025 20:36:57 -0500 Subject: [PATCH 07/22] refactor!: djangocms_picture extension (#969) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support core-styles u-image-zoom * feat: support core-styles u-image-zoom via script * Revert "feat: support core-styles u-image-zoom via script" This reverts commit 2a15a75f5cdd718ec4191d656cf200172fdeaba1. * feat: support zoom_effect + no_link_to_image * refactor: only load css once from multiple tries * refactor: extract link & figure start to templates * refactor: rebuild zoom templates to strip classes * feat: template tag `strip_class_attribute` * fix: strip_class_attribute munges data-class test * fix: template name/path typo * fix: all picture template bugs i think * docs: add help_text to Picture template field * feat: overwrite bs4 picture plugin validation * fix: strip_class_attr… regex munges `data-class` * test: highlight unsupported figure image zoom * fix: u-image-zoom-- class not added * fix: sometimes span missing & class in wrong spot * fix: core-styles zoom bug * enhance: clearer debuging ui * refactor: template logic → custom view context * Revert "refactor: template logic → custom view context" This reverts commit a12356870decb3341347a74f7d8d985ffd309f22. * refactor: template logic → custom view context * fix: bad/old path to zoom asset * refactor: move css snippet to stylehseet * refactor: rename test stylesheet * fix: test stylesheet too specific * fix: a lot, and simplify * refactor!: revert template names * fix: final bugs * chore: remove excess new line * refactor: simplify templates and update comments --- taccsite_cms/djangocms_picture/extend.py | 99 +++++++++++++++---- taccsite_cms/settings.py | 5 +- .../site_cms/css/test/djangocms-picture.css} | 4 +- .../djangocms_picture/default/picture.html | 81 +++++++-------- .../default/picture_link_start.html | 18 ---- .../{zoom_effect => default}/zoom_asset.html | 0 .../no_link_to_ext_image/picture.html | 8 +- .../no_link_to_image/picture.html | 26 +---- .../zoom_effect/picture.html | 25 +---- .../zoom_effect/zoom_wrapper_end.html | 1 - .../zoom_effect/zoom_wrapper_start.html | 1 - .../picture.html | 5 + .../zoom_effect_no_link_to_image/picture.html | 30 ------ 13 files changed, 142 insertions(+), 161 deletions(-) rename taccsite_cms/{templates/snippets/test/css-image-picture-block.html => static/site_cms/css/test/djangocms-picture.css} (94%) delete mode 100644 taccsite_cms/templates/djangocms_picture/default/picture_link_start.html rename taccsite_cms/templates/djangocms_picture/{zoom_effect => default}/zoom_asset.html (100%) delete mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html delete mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html create mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_ext_image/picture.html delete mode 100644 taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html diff --git a/taccsite_cms/djangocms_picture/extend.py b/taccsite_cms/djangocms_picture/extend.py index 6e93159e9..2d2292b38 100644 --- a/taccsite_cms/djangocms_picture/extend.py +++ b/taccsite_cms/djangocms_picture/extend.py @@ -1,7 +1,3 @@ -import logging - -logger = logging.getLogger(f"django.{__name__}") - def extendPicturePlugin(): from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ @@ -10,12 +6,12 @@ def extendPicturePlugin(): from djangocms_link.cms_plugins import LinkPlugin - ZOOM_TEMPLATE_NAME_PREFIX = 'zoom' + ZOOM_TEMPLATE_NAME = 'zoom_effect' ZOOM_TEMPLATE_LABEL = 'Zoom image on hover' ZOOM_TEMPLATE_NOTE = _('The "%(zoom_template_label)s" templates only have effect if Image either has a Link or is within a Link.') % {"zoom_template_label": ZOOM_TEMPLATE_LABEL} ZOOM_TEMPLATE_ERROR = _(' "%(zoom_template_label)s" templates require Image to either have a Link or be within a Link.') % {"zoom_template_label": ZOOM_TEMPLATE_LABEL} - logger.info("Extending PicturePlugin (and Bootstrap4PicturePlugin)...") + LINK_TEMPLATE_NAME = 'no_link_to_ext_image' def add_help_text(form_instance): """Adds help text for: 'Template' field""" @@ -23,30 +19,83 @@ def add_help_text(form_instance): if 'template' in form_instance.fields: form_instance.fields['template'].help_text += _(' %(ZOOM_TEMPLATE_NOTE)s') % {"ZOOM_TEMPLATE_NOTE": ZOOM_TEMPLATE_NOTE} + def whether_to_render_link(instance): + has_explicit_link = bool(instance.link_url or instance.link_page_id) + # FAQ: The djangocms_picture has "feature" such that an image with + # "External image" URL will automatically link to that resource + has_implicit_link = bool(instance.get_link()) and not has_explicit_link + + allow_implicit_link = not LINK_TEMPLATE_NAME in instance.template + + if has_explicit_link or (has_implicit_link and allow_implicit_link): + return True + + return False def validate_zoom_template(instance): """Validates: 'Template' field choice 'Zoom image …'""" errors = {} - has_picture_link = bool(instance.link_url or instance.link_page_id) - use_zoom_template = ZOOM_TEMPLATE_NAME_PREFIX in instance.template + would_render_link = whether_to_render_link(instance) + should_add_zoom_effect = ZOOM_TEMPLATE_NAME in instance.template parent_plugin = instance.parent.get_plugin_instance()[0] if instance.parent else None is_in_link = isinstance(parent_plugin, LinkPlugin) if parent_plugin else False - logger.info(f'validate_zoom_template: %s', { - 'link': instance.link_url or instance.link_page_id, - 'has_picture_link' : has_picture_link, - 'use_zoom_template' : use_zoom_template, - 'is_in_link': is_in_link, - }) - - if (use_zoom_template and not has_picture_link and not is_in_link ): + if (should_add_zoom_effect and not would_render_link and not is_in_link): errors['template'] = ZOOM_TEMPLATE_ERROR if errors: raise ValidationError(errors) + def get_more_context_variables(instance): + """ + Calculate boolean context variables to simplify template logic. + Returns a dictionary of context variables. + """ + # Link (set 1) + has_explicit_link = bool(instance.get_link()) + parent_plugin = instance.parent.get_plugin_instance()[0] if instance.parent else None + is_in_link_plugin = isinstance(parent_plugin, LinkPlugin) if parent_plugin else False + has_any_link = has_explicit_link or is_in_link_plugin + + # Figure/Caption + has_caption_text = bool(instance.caption_text) + has_child_plugins = bool(instance.child_plugin_instances) + has_figure_content = has_caption_text or has_child_plugins + + # Template + is_zoom_template = ZOOM_TEMPLATE_NAME in instance.template + + # Link (set 2) + should_render_link = whether_to_render_link(instance) + + # Zoom Effect + should_add_zoom_effect = is_zoom_template + should_wrap_image_for_zoom = ( + should_add_zoom_effect and + (has_figure_content or not should_render_link) + ) + should_add_zoom_class_to_link = ( + should_add_zoom_effect and + should_render_link and + not has_figure_content + ) + + # Attributes + should_add_attributes_to_image = ( + not has_figure_content and + not should_render_link + ) + + return { + 'should_render_link': should_render_link, + 'has_figure_content': has_figure_content, + 'should_wrap_image_for_zoom': should_wrap_image_for_zoom, + 'should_add_zoom_class_to_link': should_add_zoom_class_to_link, + 'should_add_attributes_to_image': should_add_attributes_to_image, + } + # djangocms_picture from djangocms_picture.cms_plugins import PicturePlugin as OriginalPicturePlugin @@ -70,6 +119,14 @@ class PicturePlugin(OriginalPicturePlugin): form = PicturePluginForm name = 'Image' + def render(self, context, instance, placeholder): + context = super().render(context, instance, placeholder) + + more_context = get_more_context_variables(instance) + context.update(more_context) + + return context + # To support generic Image plugin without uninstalling Bootstrap's # FAQ: Had been done cuz Image plugin had percieved use cases, # but is since not regularly used, but is used, thus maintained @@ -101,7 +158,13 @@ class Bootstrap4PicturePlugin(OriginalBootstrap4PicturePlugin): form = Bootstrap4PictureForm name = 'Picture / Image (Responsive)' + def render(self, context, instance, placeholder): + context = super().render(context, instance, placeholder) + + more_context = get_more_context_variables(instance) + context.update(more_context) + + return context + plugin_pool.unregister_plugin(OriginalBootstrap4PicturePlugin) plugin_pool.register_plugin(Bootstrap4PicturePlugin) - - logger.info("Extended PicturePlugin (and Bootstrap4PicturePlugin).") diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 41b59a56c..852854c10 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -579,10 +579,9 @@ def get_subdirs_as_module_names(path): ('center', _('Align center')), ] DJANGOCMS_PICTURE_TEMPLATES = [ - ('no_link_to_image', _('Do not link image to itself')), - ('no_link_to_ext_image', _('Do not link image to itself (DEPRECATED)')), + ('no_link_to_ext_image', _('Do not link to "External image"')), ('zoom_effect', _('Zoom image on hover')), - ('zoom_effect_no_link_to_image', _('Zoom image on hover & Do not link image to itself')), + ('zoom_effect_no_link_to_ext_image', _('Zoom image on hover & Do not link to "External image"')), ] # FILE UPLOAD VALUES MUST BE SET! diff --git a/taccsite_cms/templates/snippets/test/css-image-picture-block.html b/taccsite_cms/static/site_cms/css/test/djangocms-picture.css similarity index 94% rename from taccsite_cms/templates/snippets/test/css-image-picture-block.html rename to taccsite_cms/static/site_cms/css/test/djangocms-picture.css index 78e4b70df..0a91e3675 100644 --- a/taccsite_cms/templates/snippets/test/css-image-picture-block.html +++ b/taccsite_cms/static/site_cms/css/test/djangocms-picture.css @@ -1,5 +1,4 @@ - diff --git a/taccsite_cms/templates/djangocms_picture/default/picture.html b/taccsite_cms/templates/djangocms_picture/default/picture.html index ddcf3db2b..a62fd6e3f 100644 --- a/taccsite_cms/templates/djangocms_picture/default/picture.html +++ b/taccsite_cms/templates/djangocms_picture/default/picture.html @@ -1,42 +1,53 @@ {# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/templates/djangocms_picture/default/picture.html #} -{# TACC (mimic v3.0.0 to v4.0.0 changes): #} {# TACC (support children as caption content): #} +{# TACC (mimic v3.0.0 to v4.0.0 changes): #} +{# TACC (support image zoom): #} {# {% load thumbnail %} #} -{% load thumbnail l10n cms_tags %} +{% load thumbnail l10n cms_tags strip_class_attribute %} +{# /TACC #} {# /TACC #} {# /TACC #} -{# TACC (allow link to be conditional): #} -{% block picture_link_start %} +{# TACC (support custom condition): #} +{% if should_render_link %} {# /TACC #} -{% if picture_link %} - {# TACC (assign attributes to parent): #} - {% include "djangocms_picture/default/picture_link_start.html" %} + {# TACC (support image zoom): #} + {% if should_add_zoom_class_to_link %} + {% include "djangocms_picture/default/zoom_asset.html" %} + {% endif %} {# /TACC #} + {% endif %} -{# TACC (allow link to be conditional): #} -{% endblock %} -{# /TACC #} -{# TACC (allow figure to be overridden): #} -{% block picture_figure_start %} -{# /TACC #} + {# TACC (support children as caption content): #} -{# {% if instance.caption_text %} #} -{% if instance.caption_text or instance.child_plugin_instances %} +{% if has_figure_content %} +{# /TACC #} {# TACC (assign attributes to parent): #}
{# /TACC #} {% endif %} -{# /TACC #} -{# TACC (allow figure to be overridden): #} -{% endblock %} -{# /TACC #} -{# TACC (allow image wrapper): #} -{% block picture_wrap_start %} -{% endblock picture_wrap_start %} +{# TACC (support image zoom): #} +{% if should_wrap_image_for_zoom %} + {% include "djangocms_picture/default/zoom_asset.html" %} + +{% endif %} {# /TACC #} {# TACC (mimic v3.0.0 to v4.0.0 changes): #} {% localize off %} @@ -62,7 +73,7 @@ {# TACC (allow link to be conditional): #} {% block picture_attributes %} {# TACC (assign attributes to parent): #} - {% if not instance.caption_text and not picture_link and not instance.child_plugin_instances %} + {% if should_add_attributes_to_image %} {{ instance.attributes_str }} {% endif %} {# /TACC #} @@ -72,16 +83,15 @@ {# TACC (mimic v3.0.0 to v4.0.0 changes): #} {% endlocalize %} {# /TACC #} -{# TACC (allow_image_wrapper): #} -{% block picture_wrap_end %} -{% endblock picture_wrap_end %} +{# TACC (support image zoom): #} + {% if should_wrap_image_for_zoom %} + + {% endif %} {# /TACC #} -{# TACC (allow figure to be overridden): #} -{% block picture_figure_end %} +{# TACC (support custom condition): #} +{% if has_figure_content %} {# /TACC #} -{# {% if instance.caption_text %} #} -{% if instance.caption_text or instance.child_plugin_instances %} {# TACC (support children as caption content): #} {#
{{ instance.caption_text }}
#}
@@ -93,19 +103,12 @@ {# /TACC #}
{% endif %} -{# TACC (allow figure to be overridden): #} -{% endblock %} -{# /TACC #} -{# TACC (allow link to be conditional): #} -{% block picture_link_end %} +{# TACC (support custom condition): #} +{% if should_render_link %} {# /TACC #} -{% if picture_link %}
{% endif %} -{# TACC (allow link to be conditional): #} -{% endblock %} -{# /TACC #} {% comment %} # https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img diff --git a/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html b/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html deleted file mode 100644 index fb2c5a0a4..000000000 --- a/taccsite_cms/templates/djangocms_picture/default/picture_link_start.html +++ /dev/null @@ -1,18 +0,0 @@ -{# https://github.com/django-cms/djangocms-picture/blob/3.0.0/djangocms_picture/templates/djangocms_picture/default/picture.html#L4-L6 #} - -{# @var className #} -{% load strip_class_attribute %} - - diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html b/taccsite_cms/templates/djangocms_picture/default/zoom_asset.html similarity index 100% rename from taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_asset.html rename to taccsite_cms/templates/djangocms_picture/default/zoom_asset.html diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html index 55b62f679..d9e697407 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_ext_image/picture.html @@ -1,2 +1,6 @@ -{# backwards-compatibility for old name #} -{% extends "djangocms_picture/no_link_to_image/picture.html" %} +{% extends "djangocms_picture/default/picture.html" %} + +{# To allow "External image" to be rendered without a link #} +{# FAQ: Template exists to avoid adding a new model field #} +{# FAQ: Default template uses custom boolean context variables for logic #} +{# FAQ: App djangocms_picture assumes that an image, if not explicitely linked, must link to itself. But sometimes, we want an image to just be an image, unlinked. #} diff --git a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html index ad60a5d4c..5ab79b9f9 100644 --- a/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html +++ b/taccsite_cms/templates/djangocms_picture/no_link_to_image/picture.html @@ -1,24 +1,2 @@ -{% extends "djangocms_picture/default/picture.html" %} -{# To allow image to be rendered without a link #} -{# FAQ: App djangocms_picture assumes that an image, if not explicitely linked, must link to itself. But sometimes, we want an image to just be an image, unlinked. #} - -{# So picture is not wrapped in a link #} -{% block picture_link_start %} - {% if instance.link_url or instance.link_page_id %} - {% include "djangocms_picture/default/picture_link_start.html" %} - {% endif %} -{% endblock %} - -{# So picture attributes are added to unlinked picture #} -{% block picture_attributes %} - {% if not instance.caption_text and not instance.link_url and not instance.link_page_id and not instance.child_plugin_instances %} - {{ instance.attributes_str }} - {% endif %} -{% endblock %} - -{# So picture is not wrapped in a link #} -{% block picture_link_end %} - {% if instance.link_url or instance.link_page_id %} - - {% endif %} -{% endblock %} +{# backwards-compatibility for temporary name #} +{% extends "djangocms_picture/no_link_to_ext_image/picture.html" %} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html index 993517ec0..f1f398d5c 100644 --- a/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect/picture.html @@ -1,24 +1,5 @@ {% extends "djangocms_picture/default/picture.html" %} -{# Add u-image-zoom class on link if link is present without figure #} -{% block picture_link_start %} - {% if picture_link and not instance.caption_text and not instance.child_plugin_instances %} - {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} - {% include "djangocms_picture/default/picture_link_start.html" with className="u-image-zoom--on-hover" %} - {% else %} - {{ block.super }} - {% endif %} -{% endblock %} - -{# Add u-image-zoom class on image wrapper if no link #} -{% block picture_wrap_start %} - {% if instance.caption_text or instance.child_plugin_instances or not picture_link %} - {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} - {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} - {% endif %} -{% endblock %} -{% block picture_wrap_end %} - {% if instance.caption_text or instance.child_plugin_instances or not picture_link %} - {% include "djangocms_picture/zoom_effect/zoom_wrapper_end.html" %} - {% endif %} -{% endblock %} +{# To zoom image on hover #} +{# FAQ: Template exists to avoid adding a new model field #} +{# FAQ: Default template uses custom boolean context variables for logic #} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html deleted file mode 100644 index 294567489..000000000 --- a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_end.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html b/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html deleted file mode 100644 index 7998a3d33..000000000 --- a/taccsite_cms/templates/djangocms_picture/zoom_effect/zoom_wrapper_start.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_ext_image/picture.html b/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_ext_image/picture.html new file mode 100644 index 000000000..e94d37638 --- /dev/null +++ b/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_ext_image/picture.html @@ -0,0 +1,5 @@ +{% extends "djangocms_picture/default/picture.html" %} + +{# To combine `zoom_effect` and `no_link_to_image` %} +{# SEE: taccsite_cms/templates/djangocms_picture/zoom_effect #} +{# SEE: taccsite_cms/templates/djangocms_picture/no_link_to_image #} diff --git a/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html b/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html deleted file mode 100644 index c882de1cf..000000000 --- a/taccsite_cms/templates/djangocms_picture/zoom_effect_no_link_to_image/picture.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "djangocms_picture/no_link_to_image/picture.html" %} - -{# Add u-image-zoom class on link if link is present without figure #} -{% block picture_link_start %} - {% if instance.link_url or instance.link_page_id %} - {% if not instance.caption_text and not instance.child_plugin_instances %} - {% include "djangocms_picture/default/picture_link_start.html" with className="u-image-zoom--on-hover" %} - {% else %} - {{ block.super }} - {% endif %} - {% else %} - {{ block.super }} - {% endif %} -{% endblock %} - -{# Add u-image-zoom class on image wrapper if no link and no figure #} -{% block picture_wrap_start %} - {% if instance.caption_text or instance.child_plugin_instances %} - {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} - {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} - {% elif not instance.link_url and not instance.link_page_id %} - {% include "djangocms_picture/zoom_effect/zoom_asset.html" %} - {% include "djangocms_picture/zoom_effect/zoom_wrapper_start.html" %} - {% endif %} -{% endblock %} -{% block picture_wrap_end %} - {% if instance.caption_text or instance.child_plugin_instances or not instance.link_url and not instance.link_page_id %} - {% include "djangocms_picture/zoom_effect/zoom_wrapper_end.html" %} - {% endif %} -{% endblock %} From 478ffb5ee6f501192141a00ebe9ca2d7488849b2 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Fri, 25 Jul 2025 20:53:41 -0500 Subject: [PATCH 08/22] chore(README): new line (to get new main commit) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ad87d3e02..2e4eadb85 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ To contribute, first read [How to Contirbute][Contributing]. | `python manage.py collectstatic` | [django](https://docs.djangoproject.com/en/3.2/howto/static-files/) | `python manage.py createsuperuser` | [django cms](https://docs.django-cms.org/en/release-3.8.x/how_to/install.html#admin-user), [django](https://docs.djangoproject.com/en/3.2/ref/django-admin/#createsuperuser) + [Camino]: https://github.com/TACC/Camino From df14ad6e76fe344ee263eb05e00435f7aa05fa8b Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:00:32 -0500 Subject: [PATCH 09/22] refactor: u-image-zoom via core-styles (#970) * deps: core-styles v2.46.1 * refactor: u-image-zoom via core-styles --- package-lock.json | 14 +++++++------- package.json | 2 +- .../djangocms_picture/default/picture.html | 6 ------ .../djangocms_picture/default/zoom_asset.html | 7 ------- 4 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 taccsite_cms/templates/djangocms_picture/default/zoom_asset.html diff --git a/package-lock.json b/package-lock.json index a0472cd77..776bd2ca7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "minimist": "^1.2.6" }, "devDependencies": { - "@tacc/core-styles": "^2.45.0" + "@tacc/core-styles": "^2.46.1" }, "engines": { "node": ">=16", @@ -1132,9 +1132,9 @@ } }, "node_modules/@tacc/core-styles": { - "version": "2.45.0", - "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.45.0.tgz", - "integrity": "sha512-ujck0rgUFb+vo42Qr5MRUfF8KHnIAEjHsRuh9dhBaeo6mrRhyjBCq+JgGryjQxOiCnFFM8yuYrJlUPsCaSEGCA==", + "version": "2.46.1", + "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.1.tgz", + "integrity": "sha512-ln6ihKWtMTwDxQKmBL1H/2P2+mLut1h2n/KziKUlpQ7+PEaBFHaC1XFE8FuROmX+H/aZnpCW8xXALIcUQcErnw==", "dev": true, "license": "MIT", "bin": { @@ -4733,9 +4733,9 @@ } }, "@tacc/core-styles": { - "version": "2.45.0", - "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.45.0.tgz", - "integrity": "sha512-ujck0rgUFb+vo42Qr5MRUfF8KHnIAEjHsRuh9dhBaeo6mrRhyjBCq+JgGryjQxOiCnFFM8yuYrJlUPsCaSEGCA==", + "version": "2.46.1", + "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.1.tgz", + "integrity": "sha512-ln6ihKWtMTwDxQKmBL1H/2P2+mLut1h2n/KziKUlpQ7+PEaBFHaC1XFE8FuROmX+H/aZnpCW8xXALIcUQcErnw==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index efa0c1242..0471f33b1 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,6 @@ }, "homepage": "https://github.com/TACC/Core-CMS", "devDependencies": { - "@tacc/core-styles": "^2.45.0" + "@tacc/core-styles": "^2.46.1" } } diff --git a/taccsite_cms/templates/djangocms_picture/default/picture.html b/taccsite_cms/templates/djangocms_picture/default/picture.html index a62fd6e3f..463006bb3 100644 --- a/taccsite_cms/templates/djangocms_picture/default/picture.html +++ b/taccsite_cms/templates/djangocms_picture/default/picture.html @@ -11,11 +11,6 @@ {# TACC (support custom condition): #} {% if should_render_link %} {# /TACC #} - {# TACC (support image zoom): #} - {% if should_add_zoom_class_to_link %} - {% include "djangocms_picture/default/zoom_asset.html" %} - {% endif %} - {# /TACC #} {% endif %} {# /TACC #} diff --git a/taccsite_cms/templates/djangocms_picture/default/zoom_asset.html b/taccsite_cms/templates/djangocms_picture/default/zoom_asset.html deleted file mode 100644 index 230e3e264..000000000 --- a/taccsite_cms/templates/djangocms_picture/default/zoom_asset.html +++ /dev/null @@ -1,7 +0,0 @@ -{% load sekizai_tags %} - -{% addtoblock "css" %} - -{% endaddtoblock %} From 461ca3eda67471a0255d1f19ae4a1aead1cca37f Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:25:49 -0500 Subject: [PATCH 10/22] chore: v4.36.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7a00eb064..7622670a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tacc-core-cms-backend" -version = "4.35.0" +version = "4.36.0" description = "DjangoCMS backend for the TACC ACI-WMA Core-CMS Codebase." authors = ["TACC-WMA "] From 34acc585a57fe3a9efb3d2ac6591be8b200e973e Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:27:41 -0500 Subject: [PATCH 11/22] fix: u-image-zoom validation (#971) --- taccsite_cms/djangocms_picture/extend.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/taccsite_cms/djangocms_picture/extend.py b/taccsite_cms/djangocms_picture/extend.py index 2d2292b38..52ce32bb5 100644 --- a/taccsite_cms/djangocms_picture/extend.py +++ b/taccsite_cms/djangocms_picture/extend.py @@ -40,7 +40,7 @@ def validate_zoom_template(instance): would_render_link = whether_to_render_link(instance) should_add_zoom_effect = ZOOM_TEMPLATE_NAME in instance.template parent_plugin = instance.parent.get_plugin_instance()[0] if instance.parent else None - is_in_link = isinstance(parent_plugin, LinkPlugin) if parent_plugin else False + is_in_link = instance.parent.plugin_type == 'LinkPlugin' if instance.parent else False if (should_add_zoom_effect and not would_render_link and not is_in_link): errors['template'] = ZOOM_TEMPLATE_ERROR @@ -53,12 +53,6 @@ def get_more_context_variables(instance): Calculate boolean context variables to simplify template logic. Returns a dictionary of context variables. """ - # Link (set 1) - has_explicit_link = bool(instance.get_link()) - parent_plugin = instance.parent.get_plugin_instance()[0] if instance.parent else None - is_in_link_plugin = isinstance(parent_plugin, LinkPlugin) if parent_plugin else False - has_any_link = has_explicit_link or is_in_link_plugin - # Figure/Caption has_caption_text = bool(instance.caption_text) has_child_plugins = bool(instance.child_plugin_instances) @@ -67,7 +61,7 @@ def get_more_context_variables(instance): # Template is_zoom_template = ZOOM_TEMPLATE_NAME in instance.template - # Link (set 2) + # Link should_render_link = whether_to_render_link(instance) # Zoom Effect From b2993c0e10479238b8902702a0ed59a4706d8495 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 28 Jul 2025 15:13:28 -0500 Subject: [PATCH 12/22] fix: space under span.u-image-zoom img (#972) * fix: space under span.u-image-zoom img * deps: core-styles v2.46.2 --- package-lock.json | 14 +++++++------- package.json | 2 +- .../components/django.cms.blog.app.page.css | 9 +++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 776bd2ca7..276eaf0c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "minimist": "^1.2.6" }, "devDependencies": { - "@tacc/core-styles": "^2.46.1" + "@tacc/core-styles": "^2.46.2" }, "engines": { "node": ">=16", @@ -1132,9 +1132,9 @@ } }, "node_modules/@tacc/core-styles": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.1.tgz", - "integrity": "sha512-ln6ihKWtMTwDxQKmBL1H/2P2+mLut1h2n/KziKUlpQ7+PEaBFHaC1XFE8FuROmX+H/aZnpCW8xXALIcUQcErnw==", + "version": "2.46.2", + "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.2.tgz", + "integrity": "sha512-b3MTccuLswbJM19ysX85vHYt6l/hHtvEgR3ZhKZZvoVXPBZjyfhl9zvnOrnQPB5tnLMt59nKdyHo+XcEj67lgA==", "dev": true, "license": "MIT", "bin": { @@ -4733,9 +4733,9 @@ } }, "@tacc/core-styles": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.1.tgz", - "integrity": "sha512-ln6ihKWtMTwDxQKmBL1H/2P2+mLut1h2n/KziKUlpQ7+PEaBFHaC1XFE8FuROmX+H/aZnpCW8xXALIcUQcErnw==", + "version": "2.46.2", + "resolved": "https://registry.npmjs.org/@tacc/core-styles/-/core-styles-2.46.2.tgz", + "integrity": "sha512-b3MTccuLswbJM19ysX85vHYt6l/hHtvEgR3ZhKZZvoVXPBZjyfhl9zvnOrnQPB5tnLMt59nKdyHo+XcEj67lgA==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 0471f33b1..23b32a020 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,6 @@ }, "homepage": "https://github.com/TACC/Core-CMS", "devDependencies": { - "@tacc/core-styles": "^2.46.1" + "@tacc/core-styles": "^2.46.2" } } diff --git a/taccsite_cms/static/site_cms/css/src/_imports/components/django.cms.blog.app.page.css b/taccsite_cms/static/site_cms/css/src/_imports/components/django.cms.blog.app.page.css index 4a6c5ef4f..13dadc8da 100644 --- a/taccsite_cms/static/site_cms/css/src/_imports/components/django.cms.blog.app.page.css +++ b/taccsite_cms/static/site_cms/css/src/_imports/components/django.cms.blog.app.page.css @@ -170,6 +170,15 @@ Styleguide Components.DjangoCMS.Blog.App.Page margin-inline: auto; } +/* To add space under aligned images */ +/* NOTE: All images should be aligned by news editor, + so missing space is considered news editor error */ +:--article-page .blog-content .align-right, +:--article-page .blog-content .align-center, +:--article-page .blog-content .align-left { + margin-bottom: var(--global-space--grid-gap); +} + /* To always align Bootstrap blockquote text left */ /* FAQ: Boostrap, loaded in foundation layer, used !important */ /* TODO: When extending Core-Styles c-news, .blockquote... is only for CMS */ From 86f76fbc1e3cc3da7685a297a4da49dffa279013 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 28 Jul 2025 15:26:34 -0500 Subject: [PATCH 13/22] fix: v4.36.1 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7622670a4..fcd8acad2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tacc-core-cms-backend" -version = "4.36.0" +version = "4.36.1" description = "DjangoCMS backend for the TACC ACI-WMA Core-CMS Codebase." authors = ["TACC-WMA "] From 9d80485d83182b0a23ebce64d6ad0b1f81bc70d9 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:04:55 -0500 Subject: [PATCH 14/22] feat: snippet template to redirect external article (#973) * feat: snippet to redirect external article * fix: load Core-CMS script not tup-ui script --- .../snippets/news/open-external-articles.html | 2 +- .../news/redirect-external-article.html | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 taccsite_cms/templates/snippets/news/redirect-external-article.html diff --git a/taccsite_cms/templates/snippets/news/open-external-articles.html b/taccsite_cms/templates/snippets/news/open-external-articles.html index 99dbafa6d..ca383e8eb 100644 --- a/taccsite_cms/templates/snippets/news/open-external-articles.html +++ b/taccsite_cms/templates/snippets/news/open-external-articles.html @@ -1,7 +1,7 @@ {# To open external news article, instead of internal news article #} {% load static %} - From 6913b383e6a0d78efebad76a5913509b5402c9d2 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:10:59 -0500 Subject: [PATCH 15/22] chore: v4.36.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fcd8acad2..1e23b1301 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tacc-core-cms-backend" -version = "4.36.1" +version = "4.36.2" description = "DjangoCMS backend for the TACC ACI-WMA Core-CMS Codebase." authors = ["TACC-WMA "] From 04a54de5d1890a84e2aeaeeeaac8eda3cacf09ff Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 4 Aug 2025 15:42:36 -0500 Subject: [PATCH 16/22] deps: djangocms-bootstrap4 v3 (#974) --- poetry.lock | 16 ++++++---------- pyproject.toml | 4 +--- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4fd2870f6..9d86b1964 100644 --- a/poetry.lock +++ b/poetry.lock @@ -747,13 +747,15 @@ taggit-helpers = ["django-taggit-helpers"] [[package]] name = "djangocms-bootstrap4" -version = "3.0.1" +version = "3.0.2" description = "Adds Bootstrap 4 components as plugins." optional = false python-versions = "*" groups = ["main"] -files = [] -develop = false +files = [ + {file = "djangocms_bootstrap4-3.0.2-py3-none-any.whl", hash = "sha256:3b7e7eb1b7551cf433bf2bb0f3601d47645203c3bb4ad75ec097eb4bd81a34cf"}, + {file = "djangocms_bootstrap4-3.0.2.tar.gz", hash = "sha256:e931aefadbd22ab00e6cea8b7224da767afea125df15bf0c8a8d5f7872153e64"}, +] [package.dependencies] django-cms = ">=3.7,<4" @@ -767,12 +769,6 @@ djangocms-text-ckeditor = ">=3.1.0" [package.extras] static-ace = ["djangocms-static-ace"] -[package.source] -type = "git" -url = "https://github.com/django-cms/djangocms-bootstrap4.git" -reference = "49983f4" -resolved_reference = "49983f4175ec4a4e2b5076993a893cbdd79c4ab2" - [[package]] name = "djangocms-column" version = "2.0.0" @@ -2502,4 +2498,4 @@ testing = ["func-timeout", "jaraco.itertools"] [metadata] lock-version = "2.1" python-versions = ">=3.11,<4.0" -content-hash = "077910c85e2fda3f3ff38d22d4275d876d2ecef54cd3e21ed2ee744c56771495" +content-hash = "8ef7c041a1522e5e00995677cce04b851ebfd5852399795d29aa902b49526d21" diff --git a/pyproject.toml b/pyproject.toml index 1e23b1301..71f7daf35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,9 +45,7 @@ djangocms-admin-style = "~3.2.6" djangocms-apphook-setup = "0.4.1" djangocms-attributes-field = "2.1.0" djangocms-blog = "^1.2" -# TO get a commit in main (since v3.0.1) to fix Container error -# https://github.com/django-cms/djangocms-bootstrap4/pull/164 -djangocms-bootstrap4 = {git = "https://github.com/django-cms/djangocms-bootstrap4.git", rev = "49983f4"} +djangocms-bootstrap4 = "^3.0" djangocms-column = "^2.0" djangocms-file = "3.0.0" djangocms-forms-maintained = { git = "https://github.com/TACC/djangocms-forms", rev = "6b59ff366495915f06f4d6fac01a2f0aa9efecaf" } From ab22440dbe2bd2687dbe675063aa575bd377d76d Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Mon, 4 Aug 2025 17:53:49 -0500 Subject: [PATCH 17/22] chore: move imports to function that uses them --- taccsite_cms/djangocms_picture/extend.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/taccsite_cms/djangocms_picture/extend.py b/taccsite_cms/djangocms_picture/extend.py index 52ce32bb5..21798b481 100644 --- a/taccsite_cms/djangocms_picture/extend.py +++ b/taccsite_cms/djangocms_picture/extend.py @@ -1,11 +1,8 @@ def extendPicturePlugin(): - from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ from cms.plugin_pool import plugin_pool - from djangocms_link.cms_plugins import LinkPlugin - ZOOM_TEMPLATE_NAME = 'zoom_effect' ZOOM_TEMPLATE_LABEL = 'Zoom image on hover' ZOOM_TEMPLATE_NOTE = _('The "%(zoom_template_label)s" templates only have effect if Image either has a Link or is within a Link.') % {"zoom_template_label": ZOOM_TEMPLATE_LABEL} @@ -34,6 +31,8 @@ def whether_to_render_link(instance): def validate_zoom_template(instance): """Validates: 'Template' field choice 'Zoom image …'""" + from django.core.exceptions import ValidationError + from djangocms_link.cms_plugins import LinkPlugin errors = {} From 4b724369ea0f8b7967ce5bc819f60f660daa4e1e Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Tue, 5 Aug 2025 16:16:31 -0500 Subject: [PATCH 18/22] feat: let custom sites overwrite app templates (#975) --- taccsite_cms/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 852854c10..1c7340c53 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -349,8 +349,10 @@ def gettext(s): return s # FAQ: List custom directory first, so custom templates take precedence # SEE: https://docs.djangoproject.com/en/2.2/topics/templates/#configuration 'DIRS': glob( + # XXX: Strange and from my ignorant implementation os.path.join(BASE_DIR, 'taccsite_custom') ) + [ + os.path.join(BASE_DIR, 'taccsite_custom', 'templates'), os.path.join(BASE_DIR, 'taccsite_cms', 'templates') ], 'OPTIONS': { From 69dcb55836c43bb407706b570ffc35bdf1fd9429 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Fri, 15 Aug 2025 10:39:53 -0500 Subject: [PATCH 19/22] chore: v4.36.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 71f7daf35..a686634eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tacc-core-cms-backend" -version = "4.36.2" +version = "4.36.3" description = "DjangoCMS backend for the TACC ACI-WMA Core-CMS Codebase." authors = ["TACC-WMA "] From 4a457ca65ac2024af360016be0171f5ecf6cf84f Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Thu, 4 Sep 2025 10:06:52 -0700 Subject: [PATCH 20/22] feat: new custom django command for devs (#728) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: command, find plugins within TextPlugin ⚠️ ⚠️ INCOMPLETE. DOES NOT WORK. SEE `get_parent_text_plugins`. * feat: command, find pages with given plugin ⚠️ ⚠️ UNTESTED & UNPOLISHED AS DJANGO COMMAND. * fix: find_pages_with_plugins tested on Texascale prod ad-hoc by copy/pasting and asking AI for help * chore: delete unused unfinished plugin * doc: find_pages_with_plugins * refactor: rename command --- taccsite_cms/management/commands/README.md | 16 ++++++++++++ .../management/commands/list_plugin_pages.py | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 taccsite_cms/management/commands/list_plugin_pages.py diff --git a/taccsite_cms/management/commands/README.md b/taccsite_cms/management/commands/README.md index d2416238d..e28094462 100644 --- a/taccsite_cms/management/commands/README.md +++ b/taccsite_cms/management/commands/README.md @@ -2,6 +2,7 @@ - [How to Use](#how-to-use) - [List Pages Using Each Template](#list-pages-using-each-template) +- [List Pages Using Plugins](#list-pages-using-plugins) - [Set Groups & Permissions](#set-groups--permissions) - [Reference](#reference) @@ -25,6 +26,21 @@ Usage: python manage.py list_page_templates ``` +## List Pages Using Plugins + +This command lists all pages that use a specific plugin instance (given a plugin instance ID), along with the page's path. + +Usage: +```sh +python manage.py list_plugin_pages [ ...] +``` + +Example: +```sh +python manage.py list_plugin_pages 42 99 +``` + + ## Set Groups & Permissions Every file in [`group_perms/`](./group_perms) represents a group. Each group's intended usage is described at the top of its file. Permissions are set via function calls in each file.[^1] diff --git a/taccsite_cms/management/commands/list_plugin_pages.py b/taccsite_cms/management/commands/list_plugin_pages.py new file mode 100644 index 000000000..8ae1b244d --- /dev/null +++ b/taccsite_cms/management/commands/list_plugin_pages.py @@ -0,0 +1,25 @@ +from django.core.management import BaseCommand +from django.apps import apps + +class Command(BaseCommand): + help = 'Finds the page that uses a specific plugin instance by its ID' + + def add_arguments(self, parser): + parser.add_argument('plugin_instance_ids', nargs='+', type=str) + + def handle(self, *args, **options): + for plugin_instance_id in options['plugin_instance_ids']: + page = self.find_page_using_plugin_instance(plugin_instance_id) + if page: + self.stdout.write(f'Plugin instance ID {plugin_instance_id} is used on page: {page.get_path()}') + else: + self.stdout.write(f'No page found using plugin instance ID {plugin_instance_id}') + + def find_page_using_plugin_instance(self, plugin_instance_id): + try: + CMSPlugin = apps.get_model('cms', 'CMSPlugin') + plugin_instance = CMSPlugin.objects.get(id=plugin_instance_id) + page = plugin_instance.placeholder.page if plugin_instance.placeholder else None + return page + except CMSPlugin.DoesNotExist: + return None From 6661622aa1861a2cdf331acbbc099fe297d69e7f Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Fri, 5 Sep 2025 16:46:11 -0500 Subject: [PATCH 21/22] docs: we do not use Core-CMS-Resources --- taccsite_custom/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_custom/README.md b/taccsite_custom/README.md index 0e7464193..df4ae0d5f 100644 --- a/taccsite_custom/README.md +++ b/taccsite_custom/README.md @@ -9,4 +9,4 @@ A functional placeholder directory into which the original remaining custom inst — add unique files and functionality. This directory has special logic and support in `settings.py`. > [!NOTE] -> This directory is a vestige of archived [Core CMS Resources](https://github.com/TACC/Core-CMS-Resources/tree/151ef91f) and we may re-evaluate whether to continue to use it. +> This directory is a vestige of archived [Core CMS Resources](https://github.com/TACC/Core-CMS-Resources/tree/151ef91f). From e0646422d0aeaee5f927c149cfa0af04538472d0 Mon Sep 17 00:00:00 2001 From: Wesley B <62723358+wesleyboar@users.noreply.github.com> Date: Fri, 5 Sep 2025 19:50:13 -0500 Subject: [PATCH 22/22] fix: allow short template paths in custom CMS apps Moving `taccsite_custom/*/` before `taccsite_cms` allows those custom apps to load CMS_TEMPLATES from themself before looking in Core-CMS. This should fix long-standing unintuitive template inheritance. --- taccsite_cms/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taccsite_cms/settings.py b/taccsite_cms/settings.py index 1c7340c53..ba9a3ecc6 100644 --- a/taccsite_cms/settings.py +++ b/taccsite_cms/settings.py @@ -524,9 +524,9 @@ def get_subdirs_as_module_names(path): # Append CMS project paths as module names to INSTALLED_APPS # FAQ: This automatically looks into `/taccsite_custom` and creates an "App" for each directory within CUSTOM_CMS_DIR = os.path.join(BASE_DIR, 'taccsite_custom') - INSTALLED_APPS_APPEND = get_subdirs_as_module_names(CUSTOM_CMS_DIR) -INSTALLED_APPS = INSTALLED_APPS + INSTALLED_APPS_APPEND +CORE_CMS_INDEX = INSTALLED_APPS.index('taccsite_cms') +INSTALLED_APPS[CORE_CMS_INDEX:CORE_CMS_INDEX] = INSTALLED_APPS_APPEND MIGRATION_MODULES = {} LANGUAGE_CODE = 'en'