From 40f55afa6ffd42dc5910bbd68310c216a3500b4e Mon Sep 17 00:00:00 2001 From: Sachin Kumar <69066918+sachin9058@users.noreply.github.com> Date: Thu, 8 Oct 2026 21:32:36 +0530 Subject: [PATCH] Fetch Wikidata preview thumbnails at a fixed height (#7433) --- .../javascripts/index_modules/element.js | 61 +++++++++++++++---- app/controllers/application_controller.rb | 5 +- config/settings.yml | 2 +- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/index_modules/element.js b/app/assets/javascripts/index_modules/element.js index 777a1cab0..79f75e18e 100644 --- a/app/assets/javascripts/index_modules/element.js +++ b/app/assets/javascripts/index_modules/element.js @@ -62,6 +62,10 @@ function previewWikidataValue($btn) { const items = $btn.data("qids"); if (!items?.length) return; $btn.prop("disabled", true); + const fetchOptions = { + headers: { "Api-User-Agent": "OSM-TagPreview (https://github.com/openstreetmap/openstreetmap-website)" }, + signal: abortController?.signal + }; fetch(OSM.WIKIDATA_API_URL + "?" + new URLSearchParams({ action: "wbgetentities", format: "json", @@ -71,10 +75,7 @@ function previewWikidataValue($btn) { languages: languagesToRequest.join("|"), languagefallback: 1, sitefilter: wikisToRequest.join("|") - }), { - headers: { "Api-User-Agent": "OSM-TagPreview (https://github.com/openstreetmap/openstreetmap-website)" }, - signal: abortController?.signal - }) + }), fetchOptions) .then(response => response.ok ? response.json() : Promise.reject(response)) .then(({ entities }) => { if (!entities) return Promise.reject(entities); @@ -85,7 +86,7 @@ function previewWikidataValue($btn) { .filter(qid => entities[qid]) .map(qid => getLocalizedResponse(entities[qid])) .filter(data => data.label || data.icon || data.description || data.article) - .map(data => renderWikidataResponse(data, $btn.siblings(`a[href*="wikidata.org/entity/${data.qid}"]`))) + .map(data => renderWikidataResponse(data, $btn.siblings(`a[href*="wikidata.org/entity/${data.qid}"]`), fetchOptions)) ); }) .catch(() => $btn.prop("disabled", false)); @@ -112,20 +113,22 @@ function getLocalizedResponse(entity) { return data; } -function renderWikidataResponse({ icon, label, article, description }, $link) { +function renderWikidataResponse({ icon, label, article, description }, $link, fetchOptions) { const localeName = new Intl.DisplayNames(OSM.preferred_languages, { type: "language" }); const cell = $("") .attr("colspan", 2) .addClass("bg-body-tertiary"); if (icon && OSM.WIKIMEDIA_COMMONS_URL) { - let src = OSM.WIKIMEDIA_COMMONS_URL + "Special:Redirect/file/" + encodeURIComponent(icon) + "?mobileaction=toggle_view_desktop"; - if (!icon.endsWith(".svg")) src += "&width=128"; - $("") - .attr("href", OSM.WIKIMEDIA_COMMONS_URL + "File:" + encodeURIComponent(icon) + `?uselang=${OSM.i18n.locale}`) - .append($("").attr({ src, height: "32" })) - .addClass("float-end mb-1 ms-2") - .appendTo(cell); + fetchCommonsThumbnail(icon, fetchOptions) + .then(imageAttributes => { + $("") + .attr("href", OSM.WIKIMEDIA_COMMONS_URL + "/wiki/File:" + encodeURIComponent(icon) + `?uselang=${OSM.i18n.locale}`) + .append($("").attr(imageAttributes)) + .addClass("float-end mb-1 ms-2") + .prependTo(cell); + }) + .catch(() => {}); } if (label) { const link = $link.clone() @@ -164,3 +167,35 @@ function renderWikidataResponse({ icon, label, article, description }, $link) { } return $("").append(cell); } + +function fetchCommonsThumbnail(filename, fetchOptions) { + const isVectorImage = filename.toLowerCase().endsWith(".svg"); + return fetch(OSM.WIKIMEDIA_COMMONS_URL + "/w/api.php?" + new URLSearchParams({ + action: "query", + format: "json", + origin: "*", + prop: "imageinfo", + titles: "File:" + filename, + iiprop: "url|thumburls", + iiurlheight: "32" + }), fetchOptions) + .then(response => response.ok ? response.json() : Promise.reject(response)) + .then(({ query }) => { + const page = Object.values(query.pages)[0]; + const imageInfo = page.imageinfo?.[0]; + const imageUrl = isVectorImage ? imageInfo?.url : imageInfo?.thumburl; + if (!imageUrl) return Promise.reject(page); + + const imageAttributes = { src: imageUrl, height: "32", alt: filename }; + if (!isVectorImage) { + const thumbUrls = Object.entries(imageInfo.thumburls ?? {}); + if (thumbUrls.length) { + imageAttributes.srcset = thumbUrls + .map(([width, thumbnail]) => `${thumbnail.url} ${width}w`) + .join(", "); + imageAttributes.sizes = `${imageInfo.thumbwidth}px`; + } + } + return imageAttributes; + }); +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3e6fa3a0a..784c6c14d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -253,9 +253,10 @@ class ApplicationController < ActionController::Base policy = request.content_security_policy.clone policy.connect_src(*policy.connect_src, "http://127.0.0.1:8111", "https://vector.openstreetmap.org", "https://api.maptiler.com", "https://tile.thunderforest.com", "https://render.openstreetmap.org", Settings.nominatim_url, Settings.overpass_url, - Settings.fossgis_osrm_url, Settings.graphhopper_url, Settings.fossgis_valhalla_url, Settings.wikidata_api_url) + Settings.fossgis_osrm_url, Settings.graphhopper_url, Settings.fossgis_valhalla_url, Settings.wikidata_api_url, + Settings.wikimedia_commons_url) policy.form_action(*policy.form_action, "render.openstreetmap.org", "tile.thunderforest.com") - policy.img_src(*policy.img_src, Settings.wikimedia_commons_url, "upload.wikimedia.org") + policy.img_src(*policy.img_src, Settings.wikimedia_commons_url, "upload.wikimedia.org", "thumb.wikimedia.org") policy.script_src(*policy.script_src, :wasm_unsafe_eval) policy.style_src(*policy.style_src, :unsafe_inline) diff --git a/config/settings.yml b/config/settings.yml index 34f36d086..4d04dd948 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -140,7 +140,7 @@ fossgis_osrm_url: "https://routing.openstreetmap.de/" fossgis_valhalla_url: "https://valhalla1.openstreetmap.de/route" # Endpoints for Wikimedia integration wikidata_api_url: "https://www.wikidata.org/w/api.php" -wikimedia_commons_url: "https://commons.wikimedia.org/wiki/" +wikimedia_commons_url: "https://commons.wikimedia.org" # URL to donation form donation_url: "https://supporting.openstreetmap.org/donate/" # Linkification rules -- 2.47.3