feat: Enhance FaceAI functionality and improve login process
All checks were successful
Publish FaceAI Container / publish (push) Successful in 4m43s

- Added a retry mechanism for page navigation in `live-site-test-utils.js` to handle transient errors during login.
- Introduced a new function `performLiveLoginRequest` to handle login requests via API, improving the login flow.
- Updated the login process to utilize the new API request method, ensuring a more robust authentication.
- Implemented new utility functions in `rus-ecom-240621.js` for managing FaceAI state and filtering.
- Created `faceai_photo_lookup.jsp` to handle photo lookups, returning JSON responses for better integration with the frontend.
- Updated `faceai_return.php` to redirect users with appropriate parameters after FaceAI processing.
- Modified `fotoCR.jsp` and `fotoCR-en.jsp` to include FaceAI photo IDs in the image elements for better tracking.
- Enhanced the UI to display the number of matched photos dynamically based on FaceAI results.
This commit is contained in:
MaddoScientisto 2026-04-19 14:18:00 +02:00
commit bba8026b7c
17 changed files with 1077 additions and 95 deletions

View file

@ -251,6 +251,439 @@ function initFaceAiErrorModal() {
clearFaceAiErrorState();
}
function stripFaceAiStateFromUrl(url) {
var fallbackUrl = window.location.href;
if (typeof URL === "undefined") {
return url || fallbackUrl;
}
try {
var cleanUrl = new URL(url || fallbackUrl, window.location.href);
cleanUrl.searchParams.delete("faceaiError");
cleanUrl.searchParams.delete("faceaiErrorTitle");
cleanUrl.searchParams.delete("faceaiErrorMessage");
cleanUrl.searchParams.delete("faceaiMatchSource");
cleanUrl.searchParams.delete("faceaiMatchCount");
cleanUrl.searchParams.delete("faceaiPhotoIds");
return cleanUrl.toString();
} catch (error) {
return url || fallbackUrl;
}
}
function getFaceAiMatchState() {
if (typeof URLSearchParams === "undefined") {
return null;
}
var params = new URLSearchParams(window.location.search || "");
var rawIds = params.get("faceaiPhotoIds") || "";
if (!rawIds) {
return null;
}
var photoIds = rawIds.split(",").map(function(value) {
return String(value || "").trim();
}).filter(function(value) {
return value.length > 0;
});
if (!photoIds.length) {
return null;
}
var photoIdSet = {};
for (var index = 0; index < photoIds.length; index += 1) {
photoIdSet[photoIds[index]] = true;
}
var parsedCount = parseInt(params.get("faceaiMatchCount"), 10);
return {
photoIds: photoIds,
photoIdSet: photoIdSet,
matchCount: isNaN(parsedCount) ? photoIds.length : parsedCount,
clearUrl: stripFaceAiStateFromUrl(window.location.href)
};
}
function getFaceAiFilterCopy() {
var lang = String(getCurrentLangValue() || "it").toLowerCase();
if (lang.indexOf("en") === 0) {
return {
bannerTitle: "Face ID filter active",
bannerText: "Showing <strong>{count}</strong> matched photos on the normal race page.",
clearText: "Show all race photos",
emptyText: "No matched FaceAI photos are available in this current race view."
};
}
return {
bannerTitle: "Filtro Face ID attivo",
bannerText: "Mostro <strong>{count}</strong> foto corrispondenti nella normale pagina gara.",
clearText: "Mostra tutte le foto della gara",
emptyText: "Nessuna foto FaceAI corrispondente e disponibile in questa vista della gara."
};
}
function updateFaceAiLegacyCount(visibleCount) {
var countValue = $("#faceAiPhotoCountValue");
if (!countValue.length) {
return;
}
countValue.text(String(visibleCount));
}
function escapeFaceAiAttribute(value) {
return String(value || "").replace(/&/g, "&amp;").replace(/"/g, "&quot;");
}
function isFaceAiNumericPhotoId(value) {
return /^\d+$/.test(String(value || "").trim());
}
function getFaceAiLookupEndpoint() {
return "faceai_photo_lookup.jsp";
}
function getFaceAiGalleryLayoutOptions() {
var config = window.faceAiConfig || {};
if (config.galleryMode === "compact") {
return null;
}
return {
rowHeight: 150,
margins: 8
};
}
function refreshFaceAiLegacyGalleryLayout(gallery) {
var options;
if (!gallery || !gallery.length || typeof $.fn.justifiedGallery !== "function") {
return;
}
if (gallery.data("jg.controller")) {
gallery.justifiedGallery("destroy");
}
options = getFaceAiGalleryLayoutOptions();
if (options) {
gallery.justifiedGallery(options);
return;
}
gallery.justifiedGallery();
gallery.justifiedGallery("norewind");
return;
}
function normalizeFaceAiLookupToken(value) {
return String(value || "")
.toUpperCase()
.replace(/\\+/g, "/")
.replace(/\s+/g, "_")
.replace(/[^A-Z0-9._/-]+/g, "")
.replace(/^_+|_+$/g, "");
}
function collectFaceAiCheckpointTokens(value) {
var normalized = normalizeFaceAiLookupToken(value);
var tokens = {};
var current = normalized;
while (current) {
tokens[current] = true;
current = current.replace(/^\d+\./, "");
if (tokens[current]) {
break;
}
}
current = normalized.replace(/^\d+\./, "");
while (current) {
tokens[current] = true;
if (current.indexOf("_") === -1) {
break;
}
current = current.replace(/_[^_]+$/, "");
}
return tokens;
}
function findFaceAiPointIdsForCheckpoint(checkpointLabel) {
var field = $("#id_puntoFoto");
var lookupTokens = collectFaceAiCheckpointTokens(checkpointLabel);
var ids = [];
if (!field.length || !Object.keys(lookupTokens).length) {
return ids;
}
field.find("option").each(function() {
var option = $(this);
var value = String(option.val() || "").trim();
var optionTokens;
var token;
if (!/^\d+$/.test(value)) {
return;
}
optionTokens = collectFaceAiCheckpointTokens(option.text());
for (token in optionTokens) {
if (optionTokens.hasOwnProperty(token) && lookupTokens[token]) {
ids.push(value);
return;
}
}
});
return ids;
}
function getFaceAiPhotoLookupData(photoKey) {
var value = String(photoKey || "").trim();
var normalizedPath = value.replace(/\\+/g, "/");
var segments = normalizedPath.split("/");
var fileName = segments.length ? String(segments[segments.length - 1] || "").trim() : "";
var checkpointLabel = segments.length > 1 ? String(segments[0] || "").trim() : "";
var raceId = String($("#id_gara").val() || "").trim();
var puntoFotoIds = checkpointLabel ? findFaceAiPointIdsForCheckpoint(checkpointLabel) : [];
return {
photoKey: value,
request: {
photoId: value,
normalizedPhotoId: normalizedPath,
fileName: fileName,
raceId: raceId,
checkpointLabel: checkpointLabel,
puntoFotoIds: puntoFotoIds.join(",")
}
};
}
function hideFaceAiLegacyPagination() {
$("nav[aria-label='paginatore']").hide();
$("#pageRow").closest(".col-md-3").hide();
}
function renderFaceAiLegacyBanner(state) {
var copy = getFaceAiFilterCopy();
var banner = $("#faceAiFilterBanner");
var message = copy.bannerText.replace("{count}", String(state.visibleCount));
if (!banner.length) {
var bannerHtml = ''
+ '<div class="col-12" id="faceAiFilterBannerWrap">'
+ '<div id="faceAiFilterBanner" class="alert alert-warning d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-3" role="status">'
+ '<div class="mb-2 mb-md-0">'
+ '<strong id="faceAiFilterBannerTitle"></strong> '
+ '<span id="faceAiFilterBannerText"></span>'
+ '</div>'
+ '<button type="button" id="faceAiClearFilterButton" class="btn btn-sm btn-outline-dark"></button>'
+ '</div>'
+ '</div>';
var insertTarget = $("#faceAiResultsSummary").closest(".col-md-4").parent();
if (insertTarget.length) {
insertTarget.before(bannerHtml);
} else {
$(".container.my-3 .row.mb-5").first().prepend(bannerHtml);
}
banner = $("#faceAiFilterBanner");
$(document).off("click.faceAiClearFilter", "#faceAiClearFilterButton");
$(document).on("click.faceAiClearFilter", "#faceAiClearFilterButton", function() {
window.location.href = state.clearUrl;
});
}
$("#faceAiFilterBannerTitle").text(copy.bannerTitle);
$("#faceAiFilterBannerText").html(message);
$("#faceAiClearFilterButton").text(copy.clearText);
$("#faceAiEmptyResultsMessage").remove();
if (state.visibleCount > 0) {
return;
}
var emptyMessage = '<div class="col-12" id="faceAiEmptyResultsMessage"><div class="alert alert-light border mb-3">' + faceAiEscapeHtml(copy.emptyText) + '</div></div>';
var gallery = $("#demo");
if (gallery.length) {
gallery.closest(".col-md-10").before(emptyMessage);
}
}
function buildFaceAiLegacyPhotoCard(photoKey, legacyId, imageSrc) {
var safePhotoKey = escapeFaceAiAttribute(photoKey);
var safeLegacyId = escapeFaceAiAttribute(legacyId);
var safeImageSrc = escapeFaceAiAttribute(imageSrc);
var captionLabel = String(getCurrentLangValue() || "it").toLowerCase().indexOf("en") === 0 ? "Photo ID" : "ID foto";
return $(
'<a href="javascript:mostraFoto(' + safeLegacyId + ')" data-faceai-photo-id="' + safePhotoKey + '" data-faceai-legacy-id="' + safeLegacyId + '">' +
'<img src="' + safeImageSrc + '" alt="" class="thumb" />' +
'<div class="caption">' + captionLabel + ': ' + faceAiEscapeHtml(photoKey) + '</div>' +
'</a>'
);
}
function extractFaceAiImageSrc(htmlPayload) {
var parsedNodes = $.parseHTML(htmlPayload || "", document, true) || [];
var wrapper = $("<div></div>").append(parsedNodes);
var image = wrapper.find("img").first();
if (!image.length) {
return "";
}
return image.attr("src") || "";
}
function fetchFaceAiLegacyPhotoCard(photoKey) {
var lookupData = getFaceAiPhotoLookupData(photoKey);
return $.getJSON(getFaceAiLookupEndpoint(), lookupData.request).then(function(payload) {
if (!payload || !payload.found || !payload.legacyId || !payload.thumbSrc) {
return null;
}
return buildFaceAiLegacyPhotoCard(payload.photoId || lookupData.photoKey, payload.legacyId, payload.thumbSrc);
}, function() {
if (!isFaceAiNumericPhotoId(photoKey)) {
return null;
}
return $.get("Foto2.abl?cmd=mostraFoto&id_foto=" + encodeURIComponent(photoKey)).then(function(htmlPayload) {
var imageSrc = extractFaceAiImageSrc(htmlPayload);
if (!imageSrc) {
return null;
}
return buildFaceAiLegacyPhotoCard(photoKey, photoKey, imageSrc);
}, function() {
return null;
});
});
}
function cloneFaceAiExistingPhotoCard(item) {
if (!item || !item.length) {
return null;
}
var clone = item.clone(true, true);
clone.attr("data-faceai-photo-id", item.attr("data-faceai-photo-id") || "");
clone.attr("data-faceai-legacy-id", item.attr("data-faceai-legacy-id") || "");
return clone;
}
function collectFaceAiExistingPhotoCards(gallery, matchState) {
var cardsById = {};
gallery.find("[data-faceai-photo-id]").each(function() {
var item = $(this);
var photoId = String(item.attr("data-faceai-photo-id") || "").trim();
if (!photoId || !matchState.photoIdSet[photoId] || cardsById[photoId]) {
return;
}
cardsById[photoId] = cloneFaceAiExistingPhotoCard(item);
});
return cardsById;
}
function finalizeFaceAiLegacyGallery(gallery, matchState, cards) {
var visibleCards = [];
var index;
var activeRequestId = window.faceAiLegacyGalleryRequestId || 0;
if (matchState.requestId !== activeRequestId) {
return;
}
gallery.empty();
for (index = 0; index < cards.length; index += 1) {
if (!cards[index] || !cards[index].length) {
continue;
}
visibleCards.push(cards[index]);
gallery.append(cards[index]);
}
matchState.visibleCount = visibleCards.length;
window.faceAiMatchState = matchState;
updateFaceAiLegacyCount(matchState.visibleCount);
renderFaceAiLegacyBanner(matchState);
refreshFaceAiLegacyGalleryLayout(gallery);
$(document).trigger("faceai:gallery-ready", [matchState]);
logFaceAiDebug("Applied legacy FaceAI filter", {
matchCount: matchState.matchCount,
visibleCount: matchState.visibleCount,
photoIds: matchState.photoIds
});
}
function loadFaceAiLegacyGallery(gallery, matchState) {
var existingCards = collectFaceAiExistingPhotoCards(gallery, matchState);
var orderedCards = [];
var index;
updateFaceAiLegacyCount(0);
gallery.empty().append('<div class="faceai-loading text-center w-100 py-4">FaceAI loading...</div>');
for (index = 0; index < matchState.photoIds.length; index += 1) {
(function(photoId) {
if (existingCards[photoId]) {
orderedCards.push($.Deferred().resolve(existingCards[photoId]).promise());
return;
}
orderedCards.push(fetchFaceAiLegacyPhotoCard(photoId));
}(matchState.photoIds[index]));
}
$.when.apply($, orderedCards).then(function() {
var resolvedCards = orderedCards.length === 1 ? [arguments[0]] : Array.prototype.slice.call(arguments);
finalizeFaceAiLegacyGallery(gallery, matchState, resolvedCards);
}, function() {
finalizeFaceAiLegacyGallery(gallery, matchState, []);
});
}
function prepareFaceAiLegacyRacePage() {
var matchState = getFaceAiMatchState();
var gallery = $("#demo");
var preparationKey;
if (!matchState || !gallery.length) {
return null;
}
preparationKey = window.location.pathname + "?" + window.location.search;
if (window.faceAiLegacyPreparationKey === preparationKey) {
return window.faceAiMatchState || matchState;
}
window.faceAiLegacyPreparationKey = preparationKey;
window.faceAiLegacyGalleryRequestId = (window.faceAiLegacyGalleryRequestId || 0) + 1;
matchState.requestId = window.faceAiLegacyGalleryRequestId;
matchState.visibleCount = 0;
hideFaceAiLegacyPagination();
renderFaceAiLegacyBanner(matchState);
loadFaceAiLegacyGallery(gallery, matchState);
return matchState;
}
function buildFaceAiLaunchUrl() {
var raceId = $("#id_gara").val() || "";
var raceSlug = $("#garaDesc").val() || "";
@ -261,7 +694,7 @@ function buildFaceAiLaunchUrl() {
var raceStorageRelativeDir = $("#faceAiRaceStorageRelativeDir").val() || [raceYear, raceMonthFolder, raceFolder].filter(Boolean).join("/");
var lang = getCurrentLangValue();
var handoffUrl = (window.faceAiSimulator && window.faceAiSimulator.handoffUrl) || "faceai_handoff.php";
var returnUrl = (window.faceAiSimulator && window.faceAiSimulator.returnUrl) || window.location.href;
var returnUrl = stripFaceAiStateFromUrl((window.faceAiSimulator && window.faceAiSimulator.returnUrl) || window.location.href);
var query = [
"raceId=" + encodeURIComponent(raceId),
"raceSlug=" + encodeURIComponent(raceSlug),
@ -558,6 +991,7 @@ function goPage()
$(function() {
clearLegacyLoadingState();
prepareFaceAiLegacyRacePage();
initFaceAiRaceSearchButton();
initFaceAiErrorModal();
logFaceAiDebug("Legacy race page ready");