From c14683fe37fabe06082f43e8bf67debc4cca7297 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Tue, 21 Jul 2026 14:24:59 +0200 Subject: Render asset credit inside the gallery lightbox correctly GLightbox's own selector-based description feature never actually resolved a selector in three different attempts -- literal text, then a resolved-but-empty div, then apparently not firing at all against the installed (unversioned) build. Replaced with a small afterSlideLoad handler that reads a plain data-credit-selector attribute and copies the real element's HTML into the slide's description area directly, depending only on GLightbox handing back a real DOM node per slide -- a much smaller contract than trusting its own caption-resolution feature. Renamed the credit div's class from glightbox-desc, since that name is reserved by the library's own bundled CSS (display: none !important) and can't be reliably overridden from here. Also: distinguishes the credit line and the "N Bilder" caption from ordinary body text (italic, muted, matching .author_and_date's existing convention), and makes the lightbox's caption card follow the site's light/dark toggle via Canvas/CanvasText, since the library's bundled theme never adapts to it on its own. --- app/controllers/related_assets_controller.rb | 1 + app/helpers/content_helper.rb | 6 +++++- app/models/asset.rb | 4 ++++ app/views/content/_asset_credits.html.erb | 6 ++---- app/views/content/_headline_image.html.erb | 15 +++++++++------ app/views/nodes/edit.html.erb | 1 + public/javascripts/admin_interface.js | 6 +++++- public/javascripts/public.js | 21 ++++++++++++++++++++- public/javascripts/related_assets.js | 1 + public/stylesheets/ccc.css | 26 +++++++++++++++++++++++--- 10 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/controllers/related_assets_controller.rb b/app/controllers/related_assets_controller.rb index da82cde..2fefaf7 100644 --- a/app/controllers/related_assets_controller.rb +++ b/app/controllers/related_assets_controller.rb @@ -26,6 +26,7 @@ class RelatedAssetsController < ApplicationController id: related.id, asset_id: asset.id, name: asset.name, + has_credit: asset.has_credit?, thumb_url: asset.upload.url(:thumb), large_url: asset.upload.url(:large), original_url: asset.upload.url, diff --git a/app/helpers/content_helper.rb b/app/helpers/content_helper.rb index 5b67259..b3c6bad 100644 --- a/app/helpers/content_helper.rb +++ b/app/helpers/content_helper.rb @@ -153,7 +153,7 @@ module ContentHelper def asset_credit(asset) return nil unless asset - return nil if asset.creator.blank? && asset.source_url.blank? && asset.license_key.blank? + return nil unless asset.has_credit? license = AssetLicense.find(asset.license_key) @@ -173,4 +173,8 @@ module ContentHelper full = license_text ? safe_join([attribution, license_text], ", ") : attribution safe_join([full, "."]) end + + def glightbox_data(image, title) + "title: #{title.to_s.tr(';', ',')};" + end end diff --git a/app/models/asset.rb b/app/models/asset.rb index 8bea1b3..4a295d8 100644 --- a/app/models/asset.rb +++ b/app/models/asset.rb @@ -15,4 +15,8 @@ class Asset < ApplicationRecord def image? IMAGE_CONTENT_TYPES.include?(upload_content_type) end + + def has_credit? + creator.present? || source_url.present? || license_key.present? + end end diff --git a/app/views/content/_asset_credits.html.erb b/app/views/content/_asset_credits.html.erb index 85739d0..5959abd 100644 --- a/app/views/content/_asset_credits.html.erb +++ b/app/views/content/_asset_credits.html.erb @@ -1,11 +1,9 @@ <% if @page.assets.images.any? %>
<% @page.assets.images.each do |image| %> - <% credit = asset_credit(image) %> - <% next unless credit %>
"> - <%= credit %> + class="asset_credit_block<%= " headline_credit" if image == @headline_asset %>"> + <%= asset_credit(image) %>
<% end %>
diff --git a/app/views/content/_headline_image.html.erb b/app/views/content/_headline_image.html.erb index c764d22..e7b821b 100644 --- a/app/views/content/_headline_image.html.erb +++ b/app/views/content/_headline_image.html.erb @@ -5,8 +5,9 @@ image_tag(@headline_asset.upload.url(:headline)), @headline_asset.upload.url, :class => "glightbox", - :data => { :gallery => "page-#{@page.node.id}", :title => @headline_asset.name, - :description => "#credit_for_asset_#{@headline_asset.id}" } + :data => { :gallery => "page-#{@page.node.id}", + :glightbox => glightbox_data(@headline_asset, @headline_asset.name), + :"credit-selector" => (@headline_asset.has_credit? ? "#credit_for_asset_#{@headline_asset.id}" : nil) } ) %> <% if gallery_images.size > 1 %>
<%= "#{gallery_images.size} #{t(:images)}" %>
@@ -15,14 +16,16 @@ <%= link_to "#{gallery_images.size} #{t(:images)}, #{t(:open_gallery)}", gallery_images.first.upload.url, :class => "glightbox right", - :data => { :gallery => "page-#{@page.node.id}", :title => gallery_images.first.name, - :description => "#credit_for_asset_#{gallery_images.first.id}" } %> + :data => { :gallery => "page-#{@page.node.id}", + :glightbox => glightbox_data(gallery_images.first, gallery_images.first.name), + :"credit-selector" => (gallery_images.first.has_credit? ? "#credit_for_asset_#{gallery_images.first.id}" : nil) } %> <% end %> <% gallery_images.each do |image| %> <% next if image == @headline_asset %> <% next if !@headline_asset && image == gallery_images.first %> <%= link_to "", image.upload.url, :class => "glightbox", :style => "display: none", - :data => { :gallery => "page-#{@page.node.id}", :title => image.name, - :description => "#credit_for_asset_#{image.id}" } %> + :data => { :gallery => "page-#{@page.node.id}", + :glightbox => glightbox_data(image, image.name), + :"credit-selector" => (image.has_credit? ? "#credit_for_asset_#{image.id}" : nil) } %> <% end %> diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb index da682f0..07b42d4 100644 --- a/app/views/nodes/edit.html.erb +++ b/app/views/nodes/edit.html.erb @@ -86,6 +86,7 @@ data-large-url="<%= related.asset.upload.url(:large) %>" data-original-url="<%= related.asset.upload.url %>" data-name="<%= related.asset.name %>" + data-has-credit="<%= related.asset.has_credit? %>" data-headline="<%= related.headline? %>" class="<%= "is_headline" if related.headline? %>"> <%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %> diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js index 7fb1dc2..f378c46 100644 --- a/public/javascripts/admin_interface.js +++ b/public/javascripts/admin_interface.js @@ -282,6 +282,7 @@ cccms = { large: $(this).data('large-url'), original: $(this).data('original-url'), name: $(this).data('name'), + hasCredit: $(this).data('has-credit') === true, headline: $(this).data('headline') === true }; }).get(); @@ -320,8 +321,11 @@ cccms = { : 'inline-image inline-image--half inline-image--' + placement; var esc = cccms.inline_images.escape_attr; + var titleForGlightbox = (item.name || '').replace(/;/g, ','); + var glightboxOpts = 'title: ' + esc(titleForGlightbox) + + (item.hasCredit ? '; description: #credit_for_asset_' + esc(item.id) : '') + ';'; var html = '' + + ' data-glightbox="' + glightboxOpts + '">' + '' + esc(item.name) + ''; cccms.inline_images.editor.insertContent(html); diff --git a/public/javascripts/public.js b/public/javascripts/public.js index a9250ca..7f38f66 100644 --- a/public/javascripts/public.js +++ b/public/javascripts/public.js @@ -1,6 +1,25 @@ document.addEventListener('DOMContentLoaded', function(){ - GLightbox({ selector: '.glightbox' }); + GLightbox({ + selector: '.glightbox', + afterSlideLoad: function(slideData) { + var trigger = document.querySelectorAll('.glightbox')[slideData.index]; + var selector = trigger && trigger.dataset.creditSelector; + if (!selector) return; + + var source = document.querySelector(selector); + var container = slideData.slide.querySelector('.gdesc-inner'); + if (!source || !container) return; + + var target = container.querySelector('.gslide-desc'); + if (!target) { + target = document.createElement('div'); + target.className = 'gslide-desc'; + container.appendChild(target); + } + target.innerHTML = source.innerHTML; + } + }); document.getElementById("light-mode").addEventListener("change", () => { if (document.getElementById("light-mode").checked) diff --git a/public/javascripts/related_assets.js b/public/javascripts/related_assets.js index cc07d86..c6c6a19 100644 --- a/public/javascripts/related_assets.js +++ b/public/javascripts/related_assets.js @@ -87,6 +87,7 @@ related_assets = { var item = $($("#related_asset_template").html().trim()); item.attr("data-url", related.url); item.attr("data-asset-id", related.asset_id); + item.attr("data-has-credit", related.has_credit); item.attr("data-large-url", related.large_url); item.attr("data-original-url", related.original_url); item.attr("data-name", related.name); diff --git a/public/stylesheets/ccc.css b/public/stylesheets/ccc.css index 8358d06..9654594 100644 --- a/public/stylesheets/ccc.css +++ b/public/stylesheets/ccc.css @@ -727,7 +727,6 @@ div.teaser_ruler { min-width: 0; } - .inline-image--full { width: 100%; margin: 1rem 0; @@ -748,10 +747,31 @@ div.teaser_ruler { margin-left: 1rem; } -#asset_credits .glightbox-desc { +#asset_credits .asset_credit_block { display: none; } -#asset_credits .headline_credit { +#asset_credits .asset_credit_block.headline_credit { display: block; } + +#asset_credits { + border-top: dotted 1px silver; +} + +#asset_credits, +.right { + font-style: italic; + font-family: Georgia; + font-size: 0.9rem; + color: color-mix(in srgb, CanvasText, #808080); +} + +.glightbox-clean .gslide-description { + background: Canvas !important; +} + +.glightbox-clean .gslide-title, +.glightbox-clean .gslide-desc { + color: CanvasText !important; +} -- cgit v1.3