issue #2560 person page in the gallery, links from the avatars

This commit is contained in:
Linty committed 2026-10-29 17:37:02 +01:00
1 parent 8e818c9af4
commit d4c4db36f3
8 files changed
+180 -53

No files matched your search

+30
View File
@@ -327,6 +327,7 @@ function make_section_in_url($params)
$section_of = array(
'category' => 'categories',
'tags' => 'tags',
'person' => 'people',
'list' => 'list',
'search' => 'search',
);
@@ -429,6 +430,16 @@ function make_section_in_url($params)
break;
}
case 'people' :
{
$section_string.= '/people/'.$params['person']['id'];
if (!empty($params['person']['url_name']))
{
$section_string.= '-'.$params['person']['url_name'];
}
break;
}
case 'search' :
{
$section_string.= '/search/'.$params['search'];
@@ -623,6 +634,25 @@ function parse_section_url( $tokens, &$next_token)
page_not_found(l10n('Requested tag does not exist'), get_root_url().'tags.php' );
}
}
elseif ( 'people' == @$tokens[$next_token] )
{
$next_token++;
if (!isset($tokens[$next_token]) or !preg_match('/^(\d+)(?:-.*)?$/', $tokens[$next_token], $matches))
{
bad_request('a person id is required');
}
$next_token++;
$person = get_person_by_id($matches[1]);
if (!can_see_people() or empty($person) or 'true' != $person['is_visible'])
{
page_not_found(l10n('Requested person does not exist'), get_root_url());
}
$page['section'] = 'people';
$page['person'] = $person;
}
elseif ( 'favorites' == @$tokens[$next_token] )
{
$page['section'] = 'favorites';
+46
View File
@@ -357,6 +357,47 @@ else
);
}
// +-----------------------------------------------------------------------+
// | people section |
// +-----------------------------------------------------------------------+
else if ($page['section'] == 'people')
{
$query = '
SELECT id
FROM '.IMAGES_TABLE.'
INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
WHERE id IN (
SELECT image_id
FROM '.IMAGE_PERSON_TABLE.'
WHERE person_id = '.$page['person']['id'].'
)
'.get_sql_condition_FandF(
array(
'forbidden_categories' => 'category_id',
'visible_categories' => 'category_id',
'visible_images' => 'id'
),
' AND'
).'
GROUP BY id
'.$conf['order_by'].'
;';
$items = query2array($query, null, 'id');
if (count($items) == 0)
{
page_not_found(l10n('Requested person does not exist'), get_root_url());
}
$page = array_merge(
$page,
array(
'title' => l10n('People').$conf['level_separator']
.'<a href="'.duplicate_index_url(array('start'=>0)).'">'.$page['person']['name'].'</a>',
'items' => $items,
)
);
}
// +-----------------------------------------------------------------------+
// | search section |
// +-----------------------------------------------------------------------+
else if ($page['section'] == 'search')
@@ -692,6 +733,11 @@ elseif (isset($page['tags']))
}
}
elseif (isset($page['person']))
{
array_push($page['body_classes'], 'person-'.$page['person']['id']);
$page['body_data']['person_id'] = $page['person']['id'];
}
elseif (isset($page['search']))
{
array_push($page['body_classes'], 'search-'.$page['search']);
+2
View File
@@ -536,3 +536,5 @@ $lang['Verification successful! You can now choose a new password.'] = 'Verifica
$lang['If your account exists, a verification code has been sent to your email address.'] = 'If your account exists, a verification code has been sent to your email address.';
$lang['People'] = 'People';
$lang['Click to highlight on the photo'] = 'Click to highlight on the photo';
$lang['Requested person does not exist'] = 'Requested person does not exist';
$lang['See all the photos'] = 'See all the photos';
+2
View File
@@ -535,3 +535,5 @@ $lang['Verification successful! You can now choose a new password.'] = 'Vérific
$lang['If your account exists, a verification code has been sent to your email address.'] = 'Si votre compte existe, un code de vérification a été envoyé à votre adresse email.';
$lang['People'] = 'Personnes';
$lang['Click to highlight on the photo'] = 'Cliquer pour repérer sur la photo';
$lang['Requested person does not exist'] = 'La personne demandée n\'existe pas';
$lang['See all the photos'] = 'Voir toutes ses photos';
+1
View File
@@ -932,6 +932,7 @@ if (!empty($display_info['people']) and can_see_people())
{
$people[$i]['face'] = get_person_face_background($person);
$people[$i]['initial'] = mb_strtoupper(mb_substr($person['name'], 0, 1));
$people[$i]['URL'] = make_index_url(array('person' => $person));
}
$template->assign('related_people', $people);
}
+51 -14
View File
@@ -5,9 +5,12 @@
padding: 3px 0;
}
.people-avatar {
.people-person {
position: relative;
display: inline-block;
}
.people-avatar {
display: block;
width: 36px;
height: 36px;
border: 3px solid #ffffff;
@@ -16,29 +19,26 @@
background-color: #cccccc;
background-repeat: no-repeat;
cursor: pointer;
text-decoration: none;
}
.people-avatar:focus {
outline: none;
}
.people-avatar:hover,
.people-avatar:focus,
.people-avatar-selected {
.people-avatar:focus-visible,
.people-person-selected .people-avatar {
border-color: #FFA646;
}
.people-avatar-empty {
cursor: default;
.people-avatar-empty,
.people-avatar-empty:hover {
color: #555555;
font-weight: bold;
font-size: 16px;
line-height: 36px;
text-align: center;
}
.people-avatar-empty:hover {
border-color: #ffffff;
text-decoration: none;
}
.people-tooltip {
@@ -57,16 +57,53 @@
text-align: left;
}
.people-tooltip::before {
content: '';
position: absolute;
left: 0;
right: 0;
top: -8px;
height: 8px;
}
.people-tooltip b,
.people-tooltip i {
.people-tooltip i,
.people-tooltip a {
display: block;
}
.people-avatar:hover .people-tooltip,
.people-avatar:focus .people-tooltip {
.people-tooltip a,
.people-tooltip a:hover {
margin-top: 4px;
color: #a34a00;
font-weight: bold;
text-decoration: underline;
}
.people-person:focus-within .people-tooltip {
display: block;
}
@media (hover: hover) {
.people-person:hover .people-avatar {
border-color: #FFA646;
}
.people-person:hover .people-tooltip {
display: block;
}
}
@media (hover: none) {
.people-person-selected .people-tooltip {
display: block;
}
.people-tooltip i {
display: none;
}
}
.people-frame {
position: absolute;
z-index: 50;
+36 -32
View File
@@ -1,15 +1,15 @@
jQuery(function($) {
const $avatars = $('.people-avatar[data-box]');
if (!$avatars.length) {
const $people = $('.people-person');
if (!$people.length) {
return;
}
const $frame = $('<div class="people-frame"><span class="people-frame-name"></span></div>').hide().appendTo('body');
let $selected = null;
function show_frame($avatar) {
function show_frame($person) {
const img = document.getElementById('theMainImage');
if (!img || img.hasAttribute('data-src')) {
if (!$person || !$person.data('box') || !img || img.hasAttribute('data-src')) {
$frame.hide();
return;
}
@@ -20,8 +20,8 @@ jQuery(function($) {
return;
}
const box = String($avatar.data('box')).split(',').map(Number);
const scale = rect.width / Number($avatar.data('width'));
const box = String($person.data('box')).split(',').map(Number);
const scale = rect.width / Number($person.data('width'));
$frame.css({
left: rect.left + window.scrollX + box[0] * scale,
@@ -29,43 +29,47 @@ jQuery(function($) {
width: (box[2] - box[0]) * scale,
height: (box[3] - box[1]) * scale,
});
$frame.find('.people-frame-name').text($avatar.data('name'));
$frame.find('.people-frame-name').text($person.data('name'));
$frame.show();
}
function refresh_frame() {
if ($selected) {
show_frame($selected);
}
else {
$frame.hide();
}
show_frame($selected);
}
$avatars
.on('mouseenter focus', function() {
function select_person($person) {
$people.removeClass('people-person-selected');
$selected = $person;
if ($selected) {
$selected.addClass('people-person-selected');
}
refresh_frame();
}
$people
.on('mouseenter', function() {
show_frame($(this));
})
.on('mouseleave blur', refresh_frame)
.on('click keydown', function(e) {
if ('keydown' == e.type && 'Enter' != e.key && ' ' != e.key) {
return;
}
e.preventDefault();
.on('mouseleave', refresh_frame);
const $avatar = $(this);
$avatars.removeClass('people-avatar-selected');
$people.find('.people-avatar').on('click', function(e) {
if (e.ctrlKey || e.metaKey || e.shiftKey) {
return;
}
e.preventDefault();
if ($selected && $selected.is($avatar)) {
$selected = null;
}
else {
$selected = $avatar;
$avatar.addClass('people-avatar-selected');
}
const $person = $(this).closest('.people-person');
select_person($selected && $selected.is($person) ? null : $person);
if (e.detail) {
$(this).trigger('blur');
}
});
show_frame($avatar);
});
$(document).on('click', function(e) {
if ($selected && !$(e.target).closest('.people-person').length) {
select_person(null);
}
});
$(window).on('resize', refresh_frame);
$('#theMainImage').on('load', refresh_frame);
+12 -7
View File
@@ -222,13 +222,18 @@ y.callService(
<dt>{'People'|@translate}</dt>
<dd><div class="people-avatars">
{foreach from=$related_people item=person}
{if isset($person.face)}
<span class="people-avatar" tabindex="0" data-name="{$person.name|escape:html}" data-box="{$person.box_x1},{$person.box_y1},{$person.box_x2},{$person.box_y2}" data-width="{$person.image_width}" style="background-image:url('{$current.selected_derivative->get_url()}');background-size:{$person.face.size}% auto;background-position:{$person.face.x}% {$person.face.y}%;">
{else}
<span class="people-avatar people-avatar-empty">{$person.initial}
{/if}
<span class="people-tooltip"><b>{$person.name}</b>{if isset($person.face)}<i>{'Click to highlight on the photo'|@translate}</i>{/if}</span>
</span>
<div class="people-person"{if isset($person.face)} data-name="{$person.name|escape:html}" data-box="{$person.box_x1},{$person.box_y1},{$person.box_x2},{$person.box_y2}" data-width="{$person.image_width}"{/if}>
{if isset($person.face)}
<a class="people-avatar" href="{$person.URL}" style="background-image:url('{$current.selected_derivative->get_url()}');background-size:{$person.face.size}% auto;background-position:{$person.face.x}% {$person.face.y}%;"></a>
{else}
<a class="people-avatar people-avatar-empty" href="{$person.URL}">{$person.initial}</a>
{/if}
<div class="people-tooltip">
<b>{$person.name}</b>
{if isset($person.face)}<i>{'Click to highlight on the photo'|@translate}</i>{/if}
<a href="{$person.URL}">{'See all the photos'|@translate}</a>
</div>
</div>
{/foreach}
</div></dd>
</div>