move functions to appropriate file location for files/view support js, commented them better, removed some dead code

This commit is contained in:
2025-10-11 12:13:44 +11:00
parent 3a053bea49
commit e4bf9606b9
2 changed files with 228 additions and 226 deletions

View File

@@ -11,14 +11,6 @@ function getPageFigures(res, viewingIdx)
drawPageOfFigures() drawPageOfFigures()
} }
// function called when we get another page from inside the viewer
function getPageViewer(res, viewingIdx)
{
document.viewing=document.entries[viewingIdx]
// update viewing, arrows and image/video too
ViewImageOrVideo()
}
// grab all selected thumbnails and return a <div> containing the thumbnails // grab all selected thumbnails and return a <div> containing the thumbnails
// with extra yr and date attached as attributes so we can set the default // with extra yr and date attached as attributes so we can set the default
// dir name for a move directory - not used in del, but no harm to include them // dir name for a move directory - not used in del, but no harm to include them
@@ -326,76 +318,72 @@ function NoSel() {
/** /**
* Renders a group header or entry based on the object and options. * Renders a group header or entry based on the object and options.
* @param {Object} obj - The object containing file/directory details. * obj - The object containing file/directory details.
* @param {Object} last - Tracks the last printed group (e.g., { printed: null }). * last - Tracks the last printed group (e.g., { printed: null }).
* @param {Object} ecnt - Entry counter (e.g., { val: 0 }). * ecnt - Entry counter (e.g., { val: 0 }).
* @returns {string} - Generated HTML string. * returns {string} - Generated HTML string.
*/ */
function addFigure( obj, last, ecnt) function addFigure( obj, last, ecnt)
{ {
let html = ""; let html = "";
// Grouping logic // Grouping logic
if (OPT.grouping === "Day") { if (OPT.grouping === "Day") {
if (last.printed !== obj.file_details.day) { if (last.printed !== obj.file_details.day) {
html += `<div class="row ps-3"><h6>Day: ${obj.file_details.day} of ${obj.file_details.month}/${obj.file_details.year}</h6></div>`; html += `<div class="row ps-3"><h6>Day: ${obj.file_details.day} of ${obj.file_details.month}/${obj.file_details.year}</h6></div>`;
last.printed = obj.file_details.day; last.printed = obj.file_details.day;
}
} else if (OPT.grouping === "Week") {
if (last.printed !== obj.file_details.woy) {
html += `<div class="row ps-3"><h6>Week #: ${obj.file_details.woy} of ${obj.file_details.year}</h6></div>`;
last.printed = obj.file_details.woy;
}
} else if (OPT.grouping === "Month") {
if (last.printed !== obj.file_details.month) {
html += `<div class="row ps-3"><h6>Month: ${obj.file_details.month} of ${obj.file_details.year}</h6></div>`;
last.printed = obj.file_details.month;
}
} }
} else if (OPT.grouping === "Week") {
if (last.printed !== obj.file_details.woy) {
html += `<div class="row ps-3"><h6>Week #: ${obj.file_details.woy} of ${obj.file_details.year}</h6></div>`;
last.printed = obj.file_details.woy;
}
} else if (OPT.grouping === "Month") {
if (last.printed !== obj.file_details.month) {
html += `<div class="row ps-3"><h6>Month: ${obj.file_details.month} of ${obj.file_details.year}</h6></div>`;
last.printed = obj.file_details.month;
}
}
// Image/Video/Unknown entry // Image/Video/Unknown entry
if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") { if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") {
if (!OPT.folders || isTopLevelFolder(obj.in_dir.in_path.path_prefix + '/' + obj.in_dir.rel_path + '/' + obj.name, OPT.cwd)) { const pathType = obj.in_dir.in_path.type.name;
const pathType = obj.in_dir.in_path.type.name; const size = obj.file_details.size_mb;
const size = obj.file_details.size_mb; const hash = obj.file_details.hash;
const hash = obj.file_details.hash; const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`;
const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`; const fname = obj.name;
const fname = obj.name; const yr = obj.file_details.year;
const yr = obj.file_details.year; const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`;
const date = `${yr}${String(obj.file_details.month).padStart(2, '0')}${String(obj.file_details.day).padStart(2, '0')}`; const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`;
const prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`; const type = obj.type.name;
const type = obj.type.name;
html += ` html += `
<figure id="${obj.id}" ecnt="${ecnt}" class="col col-auto g-0 figure entry m-1" <figure id="${obj.id}" ecnt="${ecnt}" class="col col-auto g-0 figure entry m-1"
path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}" path_type="${pathType}" size="${size}" hash="${hash}" in_dir="${inDir}"
fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}"> fname="${fname}" yr="${yr}" date="${date}" pretty_date="${prettyDate}" type="${type}">
${renderMedia(obj)} ${renderMedia(obj)}
</figure> </figure>
`; `;
} }
} // Directory entry
// Directory entry else if (obj.type.name === "Directory" && OPT.folders) {
else if (obj.type.name === "Directory" && OPT.folders) { const dirname = obj.dir_details.rel_path.length
const dirname = obj.dir_details.rel_path.length ? `${obj.dir_details.in_path.path_prefix}/${obj.dir_details.rel_path}`
? `${obj.dir_details.in_path.path_prefix}/${obj.dir_details.rel_path}` : obj.dir_details.in_path.path_prefix;
: obj.dir_details.in_path.path_prefix;
if (isTopLevelFolder(dirname, OPT.cwd)) { html += `
html += ` <figure class="col col-auto g-0 dir entry m-1" id="${obj.id}" ecnt="${ecnt}" dir="${dirname}" type="Directory">
<figure class="col col-auto g-0 dir entry m-1" id="${obj.id}" ecnt="${ecnt}" dir="${dirname}" type="Directory"> <svg class="svg" width="${OPT.size - 22}" height="${OPT.size - 22}" fill="currentColor">
<svg class="svg" width="${OPT.size - 22}" height="${OPT.size - 22}" fill="currentColor">
<use xlink:href="/internal/icons.svg#Directory"></use> <use xlink:href="/internal/icons.svg#Directory"></use>
</svg> </svg>
<figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption> <figcaption class="svg_cap figure-caption text-center text-wrap text-break">${obj.name}</figcaption>
</figure> </figure>
`; `;
html += `<script>f=$('#${obj.id}'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>`; html += `<script>f=$('#${obj.id}'); w=f.find('svg').width(); f.find('figcaption').width(w);</script>`;
} }
}
$('#figures').append( html ) $('#figures').append( html )
return return
} }
// Helper function to render media (image/video/unknown) // Helper function to render media (image/video/unknown)
@@ -441,12 +429,6 @@ function renderMedia(obj) {
return mediaHtml; return mediaHtml;
} }
// Helper: Check if path is a top-level folder of cwd
function isTopLevelFolder(path, cwd) {
// Implement your logic here
return true; // Placeholder
}
// Helper: Get location icon (placeholder) // Helper: Get location icon (placeholder)
function getLocationIcon(obj) { function getLocationIcon(obj) {
return ICON[obj.in_dir.in_path.type.name] return ICON[obj.in_dir.in_path.type.name]
@@ -530,6 +512,7 @@ function drawPageOfFigures()
$(".back").click( function(e) { getDirEntries(this.id,true) } ) $(".back").click( function(e) { getDirEntries(this.id,true) } )
} }
// emtpy out file_list_div, and repopulate it with new page of content
function getPageFileList(res, viewingIdx) function getPageFileList(res, viewingIdx)
{ {
$('#file_list_div').empty() $('#file_list_div').empty()
@@ -731,116 +714,6 @@ function changeSize()
$('.svg_cap').width(sz); $('.svg_cap').width(sz);
} }
function getPreviousEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex > 0) {
currentIndex--;
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex=currentIndex-(pageOffset*OPT.how_many)
// pref page, load it
if( oldPageOffset != pageOffset )
// pref page is pageOffset+1 now
getPage(pageOffset+1,getPageViewer,currentIndex)
else
document.viewing=document.entries[currentIndex]
}
}
function getNextEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex < entryList.length - 1) {
currentIndex++
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex=currentIndex-(pageOffset*OPT.how_many)
// next page, load it
if( oldPageOffset != pageOffset )
// next page is pageOffset+1 now
getPage(pageOffset+1,getPageViewer,currentIndex)
else
document.viewing=document.entries[currentIndex]
}
}
function entryIsAtStart() {
return document.viewing.id === entryList[0];
}
function entryIsAtEnd() {
return document.viewing.id === entryList[entryList.length - 1];
}
function setEntryById(id) {
var currentIndex = entryList.indexOf(parseInt(id));
// if we are on a different page, adjust as document.entries only has <= how_many
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex = currentIndex-(pageOffset*OPT.how_many)
document.viewing=document.entries[currentIndex]
}
function setDisabledForViewingNextPrevBttons()
{
$('#la').attr('disabled', entryIsAtStart());
$('#ra').attr('disabled', entryIsAtEnd());
}
function addViewerKeyHandler() {
// allow a keypress on the viewer_div
$(document).keydown(function(event) {
// if dbox is visible, dont process this hot-key, we are inputting text
// into inputs instead
if( $("#dbox").is(':visible') )
return
switch (event.key)
{
case "Left": // IE/Edge specific value
case "ArrowLeft":
if( $('#la').prop('disabled') == false )
$('#la').click()
break;
case "Right": // IE/Edge specific value
case "ArrowRight":
if( $('#ra').prop('disabled') == false )
$('#ra').click()
break;
case "d":
$('#distance').click()
break;
case "f":
$('#faces').click()
break;
case "n":
$('#fname_toggle').click()
break;
case "F":
fullscreen=!document.fullscreen
ViewImageOrVideo()
break;
case "l":
JoblogSearch()
break;
case "Delete":
$('#del').click()
default:
return; // Quit when this doesn't handle the key event.
}
});
}
$(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() });
function dblClickToViewEntry(id) {
$('#files_div').addClass('d-none')
$('#viewer_div').removeClass('d-none')
setEntryById( id )
ViewImageOrVideo()
}
// different context menu on files // different context menu on files
$.contextMenu({ $.contextMenu({
selector: '.entry', selector: '.entry',
@@ -924,33 +797,5 @@ $.contextMenu({
} }
}); });
// quick function that allows us to go out of the viewer and back, the viewercomes from files_ip/sp // finally, for files_ip/files_sp/files_rbp - set click inside document (NOT an entry) to remove seln
// so just redraw the page with drawPageOfFigures() as we have all the data $(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() });
function goOutOfViewer()
{
// if this returns -1, we have used arrows to go onto a new page(s)
if( getPageNumberForId( $('#figures').find('.figure').first().prop('id') ) == -1 )
drawPageOfFigures()
// hide viewer div, then show files_div
$('#viewer_div').addClass('d-none')
$('#files_div').removeClass('d-none')
}
// left arrow onclick handler to go to prev image from inside the viewer
function prevImageInViewer()
{
getPreviousEntry()
setDisabledForViewingNextPrevBttons()
ViewImageOrVideo()
}
// right arrow onclick handler to go to next image from inside the viewer
function nextImageInViewer()
{
getNextEntry()
setDisabledForViewingNextPrevBttons()
ViewImageOrVideo()
}

View File

@@ -25,6 +25,8 @@ function NewHeight()
return im.height*gap / (im.width/window.innerWidth) return im.height*gap / (im.width/window.innerWidth)
} }
// draw 'str' as a label above the bounding box of the face (with a white
// transparent background to enhance readability of str)
function DrawLabelOnFace(str) function DrawLabelOnFace(str)
{ {
// finish face box, need to clear out new settings for // transparent backed-name tag // finish face box, need to clear out new settings for // transparent backed-name tag
@@ -195,6 +197,8 @@ function ViewImageOrVideo()
var offsetX,offsetY; var offsetX,offsetY;
// find the edge of the canvas, so when we have a PAGE event with x,y we can see
// where we clicked in it (PAGE.x - canvas.x to see where in canvas, etc)
function reOffset() function reOffset()
{ {
var BB=$('#canvas').get(0).getBoundingClientRect(); var BB=$('#canvas').get(0).getBoundingClientRect();
@@ -202,23 +206,27 @@ function reOffset()
offsetY=BB.top; offsetY=BB.top;
} }
window.onscroll=function(e){ reOffset(); } // when we are ready,
window.onresize=function(e){ reOffset(); }
$(document).ready( function() $(document).ready( function()
{ {
var cw=$('#canvas').width; var cw=$('#canvas').width;
var ch=$('#canvas').height; var ch=$('#canvas').height;
reOffset(); reOffset();
// if we scroll or resize the window, the canvas moves on the page, reset the offsets
window.onscroll=function(e){ reOffset(); } window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); } window.onresize=function(e){ reOffset(); }
// clicking in the viewer canvas gets its own handlers to handle faces (or not)
$.contextMenu({ $.contextMenu({
selector: '#canvas', selector: '#canvas',
trigger: 'left', trigger: 'left',
// trigger: 'none', // trigger: 'none',
hideOnSecondTrigger: true, hideOnSecondTrigger: true,
// go through each face, and add appropriate 'left-click' menu.
// e.g if known face, say name, offer add refimg to person, etc.
// this is a bit complex, the item_list var has a key (which is what we
// will do if we are chosen from the menu), and data to process the action
build: function($triggerElement, e) { build: function($triggerElement, e) {
reOffset(); reOffset();
// get mouse position relative to the canvas (left-click uses page*) // get mouse position relative to the canvas (left-click uses page*)
@@ -273,18 +281,10 @@ $(document).ready( function()
} ) } )
} ); } );
// quick wrapper function to make calling this ajax code simpler in SearchForPerson // POST to the server to force a match for this face to person_id
// FIXME: could I not pass person_id, and use // ...[item[key].which_face].refimg.person.id
function OverrideForceMatch( person_id, key ) function OverrideForceMatch( person_id, key )
{ {
// we have type_id passed in, so dig the NMO out, and use that below (its really just for name, but in case we change that in the DB)
for( el in NMO )
{
if( NMO[el].id == item[key].type_id )
{
fm_idx=el
break
}
}
ofm='&person_id='+person_id+'&face_id='+item[key].id ofm='&person_id='+person_id+'&face_id='+item[key].id
$.ajax({ type: 'POST', data: ofm, url: '/add_force_match_override', success: function(data) { $.ajax({ type: 'POST', data: ofm, url: '/add_force_match_override', success: function(data) {
document.viewing.file_details.faces[item[key].which_face].ffmo=[] document.viewing.file_details.faces[item[key].which_face].ffmo=[]
@@ -373,6 +373,7 @@ function SearchForPerson(content, key, face_id, face_pos, type_id)
return false return false
} }
// if we force a match, this func allows us to POST to the server to remove the override
function RemoveOverrideForceMatch(face_pos) function RemoveOverrideForceMatch(face_pos)
{ {
if( document.viewing.file_details.faces[face_pos].ffmo.length ) if( document.viewing.file_details.faces[face_pos].ffmo.length )
@@ -394,6 +395,7 @@ function RemoveOverrideForceMatch(face_pos)
return false return false
} }
// if we force NO match, this func allows us to POST to the server to remove the override
function RemoveOverrideNoMatch(face_pos, type_id) function RemoveOverrideNoMatch(face_pos, type_id)
{ {
d='&face_id='+document.viewing.file_details.faces[face_pos].id+'&type_id='+type_id d='&face_id='+document.viewing.file_details.faces[face_pos].id+'&type_id='+type_id
@@ -409,6 +411,7 @@ function RemoveOverrideNoMatch(face_pos, type_id)
return false return false
} }
// POST to the server to force NO match for this face
function AddNoMatchOverride(type_id, face_id, face_pos, type_id) function AddNoMatchOverride(type_id, face_id, face_pos, type_id)
{ {
d='&type_id='+type_id+'&face_id='+face_id d='&type_id='+type_id+'&face_id='+face_id
@@ -423,6 +426,9 @@ function AddNoMatchOverride(type_id, face_id, face_pos, type_id)
} ) } )
} }
// generate html for the appropriate content to search for a person when adding
// override DBox. has a button that when clicked calls SeachForPerson() which
// POSTs to the server, and fills in the 'search_person_results' div with content
function AddSearch( content, key, face_pos ) function AddSearch( content, key, face_pos )
{ {
html='<h5>search for existing person:</h5>' html='<h5>search for existing person:</h5>'
@@ -506,7 +512,6 @@ function FaceDBox(key, item)
func='AddRefimgTo('+item[key]['person_id']+',\''+key+'\'' func='AddRefimgTo('+item[key]['person_id']+',\''+key+'\''
func_sn=func+ ', true )' func_sn=func+ ', true )'
func_ao=func+ ', false )' func_ao=func+ ', false )'
div+=`<script>console.log( "AddExistingFaceAsRefimgToMatchedPerson()" )</script>`
div+="Confirm you wish to add this face as a reference image for " + item[key]['who'] div+="Confirm you wish to add this face as a reference image for " + item[key]['who']
div+= '<div class="col">' + item[key]['who'] + '</div><div class="col input-group">' div+= '<div class="col">' + item[key]['who'] + '</div><div class="col input-group">'
div+= '<button onClick="'+func_sn+'" class="btn btn-success py-1 input-group-prepend">Add & search now</button>&nbsp;' div+= '<button onClick="'+func_sn+'" class="btn btn-success py-1 input-group-prepend">Add & search now</button>&nbsp;'
@@ -565,7 +570,159 @@ function JoblogSearch()
}) })
} }
// helper func to resert the src on the video div
function setVideoSource(newSrc) { function setVideoSource(newSrc) {
$('#videoSource').attr('src', newSrc); $('#videoSource').attr('src', newSrc);
$('#video')[0].load(); $('#video')[0].load();
} }
// function called when we get another page from inside the viewer
function getPageViewer(res, viewingIdx)
{
document.viewing=document.entries[viewingIdx]
// update viewing, arrows and image/video too
ViewImageOrVideo()
}
// handler used when we double click an entry to show it in the viewer
function dblClickToViewEntry(id) {
$('#files_div').addClass('d-none')
$('#viewer_div').removeClass('d-none')
setEntryById( id )
ViewImageOrVideo()
}
// quick function that allows us to go out of the viewer and back, the viewercomes from files_ip/sp
// so just redraw the page with drawPageOfFigures() as we have all the data
function goOutOfViewer()
{
// if this returns -1, we have used arrows to go onto a new page(s)
if( getPageNumberForId( $('#figures').find('.figure').first().prop('id') ) == -1 )
drawPageOfFigures()
// hide viewer div, then show files_div
$('#viewer_div').addClass('d-none')
$('#files_div').removeClass('d-none')
}
// change the viewer to the previous entry (handle page change too)
function getPreviousEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex > 0) {
currentIndex--;
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex=currentIndex-(pageOffset*OPT.how_many)
// pref page, load it
if( oldPageOffset != pageOffset )
// pref page is pageOffset+1 now
getPage(pageOffset+1,getPageViewer,currentIndex)
else
document.viewing=document.entries[currentIndex]
}
}
// change the viewer to the next entry (handle page change too)
function getNextEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex < entryList.length - 1) {
currentIndex++
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex=currentIndex-(pageOffset*OPT.how_many)
// next page, load it
if( oldPageOffset != pageOffset )
// next page is pageOffset+1 now
getPage(pageOffset+1,getPageViewer,currentIndex)
else
document.viewing=document.entries[currentIndex]
}
}
// check if we are viewing the very first entry (helps to disable la)
function entryIsAtStart() {
return document.viewing.id === entryList[0];
}
// check if we are viewing the very last entry (helps to disable ra)
function entryIsAtEnd() {
return document.viewing.id === entryList[entryList.length - 1];
}
// helper func to ensure document.viewing is the right entry from document.entries array
function setEntryById(id) {
var currentIndex = entryList.indexOf(parseInt(id));
// if we are on a different page, adjust as document.entries only has <= how_many
pageOffset=Math.floor(currentIndex / OPT.how_many)
currentIndex = currentIndex-(pageOffset*OPT.how_many)
document.viewing=document.entries[currentIndex]
}
// disable la button if we are viewing first entry and/or ra button if we are viewing last entry
function setDisabledForViewingNextPrevBttons()
{
$('#la').attr('disabled', entryIsAtStart());
$('#ra').attr('disabled', entryIsAtEnd());
}
// when we go into the view, the keybindings are set here for items like 'f' for face box/name
function addViewerKeyHandler() {
// allow a keypress on the viewer_div
$(document).keydown(function(event) {
// if dbox is visible, dont process this hot-key, we are inputting text into inputs instead
if( $("#dbox").is(':visible') )
return
switch (event.key)
{
case "Left": // IE/Edge specific value
case "ArrowLeft":
if( $('#la').prop('disabled') == false )
$('#la').click()
break;
case "Right": // IE/Edge specific value
case "ArrowRight":
if( $('#ra').prop('disabled') == false )
$('#ra').click()
break;
case "d":
$('#distance').click()
break;
case "f":
$('#faces').click()
break;
case "n":
$('#fname_toggle').click()
break;
case "F":
fullscreen=!document.fullscreen
ViewImageOrVideo()
break;
case "l":
JoblogSearch()
break;
case "Delete":
$('#del').click()
default:
return; // Quit when this doesn't handle the key event.
}
});
}
// left arrow onclick handler to go to prev image from inside the viewer
function prevImageInViewer()
{
getPreviousEntry()
setDisabledForViewingNextPrevBttons()
ViewImageOrVideo()
}
// right arrow onclick handler to go to next image from inside the viewer
function nextImageInViewer()
{
getNextEntry()
setDisabledForViewingNextPrevBttons()
ViewImageOrVideo()
}