From e4bf9606b9d5e956906b1d0b8a9747d94e85fa38 Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Sat, 11 Oct 2025 12:13:44 +1100 Subject: [PATCH] move functions to appropriate file location for files/view support js, commented them better, removed some dead code --- internal/js/files_support.js | 269 ++++++++--------------------------- internal/js/view_support.js | 185 ++++++++++++++++++++++-- 2 files changed, 228 insertions(+), 226 deletions(-) diff --git a/internal/js/files_support.js b/internal/js/files_support.js index 9230e18..78fe650 100644 --- a/internal/js/files_support.js +++ b/internal/js/files_support.js @@ -11,14 +11,6 @@ function getPageFigures(res, viewingIdx) 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
containing the thumbnails // 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 @@ -326,76 +318,72 @@ function NoSel() { /** * Renders a group header or entry based on the object and options. - * @param {Object} obj - The object containing file/directory details. - * @param {Object} last - Tracks the last printed group (e.g., { printed: null }). - * @param {Object} ecnt - Entry counter (e.g., { val: 0 }). - * @returns {string} - Generated HTML string. + * obj - The object containing file/directory details. + * last - Tracks the last printed group (e.g., { printed: null }). + * ecnt - Entry counter (e.g., { val: 0 }). + * returns {string} - Generated HTML string. */ function addFigure( obj, last, ecnt) { - let html = ""; + let html = ""; - // Grouping logic - if (OPT.grouping === "Day") { - if (last.printed !== obj.file_details.day) { - html += `
Day: ${obj.file_details.day} of ${obj.file_details.month}/${obj.file_details.year}
`; - last.printed = obj.file_details.day; + // Grouping logic + if (OPT.grouping === "Day") { + if (last.printed !== obj.file_details.day) { + html += `
Day: ${obj.file_details.day} of ${obj.file_details.month}/${obj.file_details.year}
`; + last.printed = obj.file_details.day; + } + } else if (OPT.grouping === "Week") { + if (last.printed !== obj.file_details.woy) { + html += `
Week #: ${obj.file_details.woy} of ${obj.file_details.year}
`; + last.printed = obj.file_details.woy; + } + } else if (OPT.grouping === "Month") { + if (last.printed !== obj.file_details.month) { + html += `
Month: ${obj.file_details.month} of ${obj.file_details.year}
`; + last.printed = obj.file_details.month; + } } - } else if (OPT.grouping === "Week") { - if (last.printed !== obj.file_details.woy) { - html += `
Week #: ${obj.file_details.woy} of ${obj.file_details.year}
`; - last.printed = obj.file_details.woy; - } - } else if (OPT.grouping === "Month") { - if (last.printed !== obj.file_details.month) { - html += `
Month: ${obj.file_details.month} of ${obj.file_details.year}
`; - last.printed = obj.file_details.month; - } - } - // Image/Video/Unknown entry - 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 size = obj.file_details.size_mb; - const hash = obj.file_details.hash; - const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`; - const fname = obj.name; - 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 prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`; - const type = obj.type.name; + // Image/Video/Unknown entry + if (obj.type.name === "Image" || obj.type.name === "Video" || obj.type.name === "Unknown") { + const pathType = obj.in_dir.in_path.type.name; + const size = obj.file_details.size_mb; + const hash = obj.file_details.hash; + const inDir = `${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}`; + const fname = obj.name; + 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 prettyDate = `${obj.file_details.day}/${obj.file_details.month}/${obj.file_details.year}`; + const type = obj.type.name; - html += ` -
- ${renderMedia(obj)} -
- `; + html += ` +
+ ${renderMedia(obj)} +
+ `; } - } - // Directory entry - else if (obj.type.name === "Directory" && OPT.folders) { - 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; + // Directory entry + else if (obj.type.name === "Directory" && OPT.folders) { + 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; - if (isTopLevelFolder(dirname, OPT.cwd)) { - html += ` -
- + html += ` +
+ - -
${obj.name}
-
- `; - html += ``; +
+
${obj.name}
+
+ `; + html += ``; } - } - $('#figures').append( html ) - return + $('#figures').append( html ) + return } // Helper function to render media (image/video/unknown) @@ -441,12 +429,6 @@ function renderMedia(obj) { 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) function getLocationIcon(obj) { return ICON[obj.in_dir.in_path.type.name] @@ -530,6 +512,7 @@ function drawPageOfFigures() $(".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) { $('#file_list_div').empty() @@ -731,116 +714,6 @@ function changeSize() $('.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 $.contextMenu({ 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 -// 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') -} - - -// 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() - -} +// finally, for files_ip/files_sp/files_rbp - set click inside document (NOT an entry) to remove seln +$(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() }); diff --git a/internal/js/view_support.js b/internal/js/view_support.js index c2559e0..82cbd8b 100644 --- a/internal/js/view_support.js +++ b/internal/js/view_support.js @@ -25,6 +25,8 @@ function NewHeight() 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) { // finish face box, need to clear out new settings for // transparent backed-name tag @@ -195,6 +197,8 @@ function ViewImageOrVideo() 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() { var BB=$('#canvas').get(0).getBoundingClientRect(); @@ -202,23 +206,27 @@ function reOffset() offsetY=BB.top; } -window.onscroll=function(e){ reOffset(); } -window.onresize=function(e){ reOffset(); } - +// when we are ready, $(document).ready( function() { var cw=$('#canvas').width; var ch=$('#canvas').height; reOffset(); + // if we scroll or resize the window, the canvas moves on the page, reset the offsets window.onscroll=function(e){ reOffset(); } window.onresize=function(e){ reOffset(); } + // clicking in the viewer canvas gets its own handlers to handle faces (or not) $.contextMenu({ selector: '#canvas', trigger: 'left', // trigger: 'none', 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) { reOffset(); // 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 ) { - // 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 $.ajax({ type: 'POST', data: ofm, url: '/add_force_match_override', success: function(data) { 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 } +// if we force a match, this func allows us to POST to the server to remove the override function RemoveOverrideForceMatch(face_pos) { if( document.viewing.file_details.faces[face_pos].ffmo.length ) @@ -394,6 +395,7 @@ function RemoveOverrideForceMatch(face_pos) 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) { 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 } +// POST to the server to force NO match for this face function AddNoMatchOverride(type_id, face_id, face_pos, type_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 ) { html='
search for existing person:
' @@ -506,7 +512,6 @@ function FaceDBox(key, item) func='AddRefimgTo('+item[key]['person_id']+',\''+key+'\'' func_sn=func+ ', true )' func_ao=func+ ', false )' - div+=`` div+="Confirm you wish to add this face as a reference image for " + item[key]['who'] div+= '
' + item[key]['who'] + '
' div+= ' ' @@ -565,7 +570,159 @@ function JoblogSearch() }) } +// helper func to resert the src on the video div function setVideoSource(newSrc) { $('#videoSource').attr('src', newSrc); $('#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() + +}