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 += `
-
-
+ ${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()
+
+}