Files
photoassistant/internal/js/view_support.js

729 lines
27 KiB
JavaScript

// image, then use the width of the image (with the specified gap) otherwise
// the height > width, so scale the new width based on height ratio of
// image to window
function NewWidth()
{
w_r=im.width/(window.innerWidth*gap)
h_r=im.height/(window.innerHeight*gap)
if( w_r > h_r )
return window.innerWidth*gap
else
return im.width*gap / (im.height/window.innerHeight)
}
// work out new height for canvas. depending on whether height > width of the
// image, then use the height of the image (with the specified gap) otherwise
// the width > height, so scale the new height based on width ratio of
// image to window
function NewHeight()
{
w_r=im.width/(window.innerWidth*gap)
h_r=im.height/(window.innerHeight*gap)
if( h_r > w_r )
return window.innerHeight*gap
else
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
context.stroke();
context.beginPath()
context.lineWidth = 0.1
context.font = "30px Arial"
context.globalAlpha = 0.6
bbox = context.measureText(str);
f_h=bbox.fontBoundingBoxAscent
if( bbox.fontBoundingBoxDescent )
f_h += bbox.fontBoundingBoxDescent
f_h -= 8
context.rect( x+w/2-bbox.width/2, y-f_h, bbox.width, f_h )
context.fillStyle="white"
context.fill()
context.stroke();
context.beginPath()
context.globalAlpha = 1.0
context.font = "30px Arial"
context.textAlign = "center"
context.fillStyle = context.strokeStyle
context.fillText(str, x+w/2, y-2)
}
// This draws the image, it can be called on resize events, img.src finishing
// loading or explicitly on page load. Will also deal with all state/toggles
// for items like name, grayscale, etc.
function DrawImg()
{
// another call to this func will occur on load, so skip this one
if( im.width == 0 )
return
canvas.width=NewWidth(im)
canvas.height=NewHeight(im)
// dont let caption be wider than image
$('#img-cap').width(canvas.width)
// actually draw the pixel images to the canvas at the right size
if( grayscale )
context.filter='grayscale(1)'
context.drawImage(im, 0, 0, canvas.width, canvas.height )
// -50 is a straight up hack, no idea why this works, but its good enough for me
if( throbber )
$('#throbber').attr('style', 'display:show; position:absolute; left:'+canvas.width/2+'px; top:'+(canvas.height/2-50)+'px' )
else
$('#throbber').hide();
// show (or not) the whole figcaption with fname in it - based on state of fname_toggle
if( $('#fname_toggle').prop('checked' ) )
{
// reset fname for new image (if navigated left/right to get here)
$('.figcaption').show()
}
else
$('.figcaption').hide()
// if we have faces, the enable the toggles, otherwise disable them and reset model select too
if( document.viewing.file_details.faces.length )
{
$('#faces').attr('disabled', false)
$('#distance').attr('disabled', false)
// first face is good enough as whole file has to have used same model
$('#model').val( document.viewing.file_details.faces[0].facefile_lnk.model_used )
}
else
{
$('#faces').attr('disabled', true)
$('#distance').attr('disabled', true)
// if no faces, then model is N/A (always 1st element - or 0 in select)
$('#model').val(0)
}
// okay, we want faces drawn so lets do it
if( $('#faces').prop('checked') && document.viewing.file_details.faces )
{
faces=document.viewing.file_details.faces
// draw rect on each face
for( i=0; i<faces.length; i++ )
{
x = faces[i].face_left / ( im.width/canvas.width )
y = faces[i].face_top / ( im.height/canvas.height )
w = faces[i].w / ( im.width/canvas.width )
h = faces[i].h / ( im.height/canvas.height )
context.beginPath()
context.rect( x, y, w, h )
context.lineWidth = 2
// this face has an override so diff colour
if( faces[i].fnmo.length || faces[i].ffmo.length )
{
context.strokeStyle = 'blue'
if( faces[i].ffmo.length )
DrawLabelOnFace( faces[i].ffmo[0].person.tag )
else
DrawLabelOnFace( faces[i].fnmo[0].type.name )
}
else
{
context.strokeStyle = 'green'
if( faces[i].refimg )
{
str=faces[i].refimg.person.tag
if( $('#distance').prop('checked') )
str += "("+faces[i].refimg_lnk.face_distance.toFixed(2)+")"
DrawLabelOnFace( str )
}
}
context.stroke();
}
}
}
// resize a video based when event calls this -- TODO: is this right for ratios
// where vid is different w/h ratio?
function ResizeVideo()
{
$('#video').height(window.innerHeight*gap)
}
// change faces being shown or not (if not showing faces, then cant set distance on anyway)
// and a face or not, needs to redraw the image to add/remove green box, etc.
function FaceToggle()
{
$('#distance').prop('disabled', function(i, v) { return !v; });
DrawImg()
}
// func to set show/hide the image or video div, and set the URL appropriately
// also deals with fullsecreen if needed
function ViewImageOrVideo()
{
// can happen if no content to display
if( ! document.viewing ) return
if( document.viewing.type.name == 'Image' )
{
im.src='../' + document.viewing.FullPathOnFS
$('#video_div').hide()
if( $('#fname_toggle').prop('checked' ) )
$('#img-cap').show()
$('#fname_i').html(PrettyFname(document.viewing.FullPathOnFS))
$('#figure').show()
if( fullscreen )
$('#canvas').get(0).requestFullscreen()
else
if( document.fullscreen )
document.exitFullscreen()
}
if( document.viewing.type.name == 'Video' )
{
$('#figure').hide()
$('#video').prop('src', '../' + document.viewing.FullPathOnFS )
$('#fname_v').html(PrettyFname(document.viewing.FullPathOnFS))
if( $('#fname_toggle').prop('checked' ) )
$('#img-cap').hide()
ResizeVideo()
$('#video_div').show()
if( fullscreen )
$('#video').get(0).requestFullscreen()
else
if( document.fullscreen )
document.exitFullscreen()
}
}
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();
offsetX=BB.left;
offsetY=BB.top;
}
// 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*)
var x=parseInt(e.pageX-offsetX);
var y=parseInt(e.pageY-offsetY);
item_list = { not_a_face: { name: "Not a face", which_face: '-1' } }
faces=document.viewing.file_details.faces
for( i=0; i<faces.length; i++ )
{
fx = faces[i].face_left / ( im.width/canvas.width )
fy = faces[i].face_top / ( im.height/canvas.height )
fw = faces[i].w / ( im.width/canvas.width )
fh = faces[i].h / ( im.height/canvas.height )
if( x >= fx && x <= fx+fw && y >= fy && y <= fy+fh )
{
if( faces[i].ffmo.length || faces[i].fnmo.length )
{
item_list['remove_force_match_override']={ 'name': 'Remove override for this face', 'which_face': i, 'id': faces[i].id }
}
else if( faces[i].refimg )
{
item_list['match']={ 'name': faces[i].refimg.person.tag, 'which_face': i, 'id': faces[i].id }
item_list['match_add_refimg']={ 'name': 'Add this as refimg for ' + faces[i].refimg.person.tag,
'person_id': faces[i].refimg.person.id, 'who': faces[i].refimg.person.tag, 'which_face': i, 'id': faces[i].id, }
item_list['wrong_person']={ 'name': 'wrong person', 'which_face': i, 'id': faces[i].id }
}
else
{
item_list['no_match_new_person']={ 'name': 'Add as reference image to NEW person', 'which_face': i, 'id': faces[i].id }
item_list['no_match_new_refimg']={ 'name': 'Add as reference image to EXISTING person', 'which_face': i, 'id': faces[i].id }
for( var el in NMO ) {
item_list['NMO_'+el]={'type_id': NMO[el].id, 'name': 'Override: ' + NMO[el].name, 'which_face': i, 'id': faces[i].id }
}
}
delete item_list['not_a_face']
$('#canvas').prop('menu_item', item_list )
break
}
}
return {
callback: function( key, options) {
if( key == 'not_a_face' ) { return true }
item=$('#canvas').prop( 'menu_item' );
FaceDBox( key, item )
},
items: item_list
};
}
} )
} );
// 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 )
{
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=[]
document.viewing.file_details.faces[item[key].which_face].ffmo[0]={}
document.viewing.file_details.faces[item[key].which_face].ffmo[0].person=data.person
$('#dbox').modal('hide')
$('#faces').prop('checked',true)
DrawImg()
CheckForJobs()
}
} )
}
// function that handles the POSTed data that comes back when we add a
// reference image to a new or existing person (right-click on a face)
// used in success callbacks from CreatePersonAndRefimg() and AddRefimgTo()
function handleAddRefimgData(key, data)
{
document.viewing.file_details.faces[item[key].which_face].refimg=data.refimg
document.viewing.file_details.faces[item[key].which_face].refimg_lnk={}
// if we used this img, for now set distance to 0 - it is an exact match!
document.viewing.file_details.faces[item[key].which_face].refimg_lnk.face_distance=0.0
$('#dbox').modal('hide')
$('#faces').prop('checked',true)
DrawImg()
CheckForJobs()
}
// when we right-click a face and make a new person, this code creates and
// associates the face
function CreatePersonAndRefimg( key )
{
d='&face_id='+item[key].id
+'&tag='+$('#tag').val()
+'&firstname='+$('#firstname').val()
+'&surname='+$('#surname').val()
+'&refimg_data='+item[key].refimg_data
$.ajax({ type: 'POST', data: d, url: '/match_with_create_person',
success: function(data) { handleAddRefimgData(key, data ) },
})
}
// when we right-click a face and connect to an existing person, this connects
// the refimg and associates the face
function AddRefimgTo( person_id, key, search )
{
d='&face_id='+item[key].id+'&person_id='+person_id+'&refimg_data='+item[key].refimg_data+'&search='+search
$.ajax({ type: 'POST', data: d, url: '/add_refimg_to_person',
success: function(data) { handleAddRefimgData(key, data ) },
})
}
// function to facilitate adding a face match override to this "found" person
// uses Ajax to the f/e to get any person matching #stext's content (via any name/tag)
// and displays results in #search_person_results
function SearchForPerson(content, key, face_id, face_pos, type_id)
{
// make URI safe
who = encodeURIComponent( $('#stext').val() )
// call ajax to find ppl
$.ajax({ type: 'POST', data: null, url: '/find_persons/'+ who,
success: function(data) {
for( var el in data ) {
content+='<div class="row">'
var person = data[el];
if( item[key].name == "Override: Manual match to existing person" )
{
func='OverrideForceMatch('+person.id+',\''+key+'\' )'
content+= '<div class="col">' + person.tag + ' (' + person.firstname+' '+person.surname+ ') </div>'
content+= '<button onClick="'+func+'" class="col btn btn-success py-1 input-group-prepend">Add Override</button>'
}
if( key == 'no_match_new_refimg' )
{
func='AddRefimgTo('+person.id+',\''+key+'\''
func_sn=func+ ', true )'
func_ao=func+ ', false )'
content+= '<div class="col">' + person.tag + ' (' + person.firstname+' '+person.surname+ ') </div><div class="col input-group">'
content+= '<button onClick="'+func_sn+'" class="btn btn-success py-1 input-group-prepend">Add & search now</button>&nbsp;'
content+= '<button onClick="'+func_ao+'" class="btn btn-outline-success py-1 input-group-append">Add only</button></div>'
}
content+='</div class="row">'
}
$('#search_person_results').html( content )
}
} )
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 )
who=document.viewing.file_details.faces[face_pos].ffmo[0].person.tag
else
who=document.viewing.file_details.faces[face_pos].refimg.person.tag
d='&face_id='+document.viewing.file_details.faces[face_pos].id+'&person_tag='+who+'&file_eid='+document.viewing.id
$.ajax({ type: 'POST', data: d, url: '/remove_force_match_override',
success: function(data) {
// force/delete the ffmo cleanly
document.viewing.file_details.faces[face_pos].ffmo.length=0
$('#dbox').modal('hide')
DrawImg()
CheckForJobs()
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)
{
d='&face_id='+document.viewing.file_details.faces[face_pos].id+'&type_id='+type_id
$.ajax({ type: 'POST', data: d, url: '/remove_no_match_override',
success: function(data) {
document.viewing.file_details.faces[face_pos].fnmo.length=0
$('#dbox').modal('hide')
DrawImg()
CheckForJobs()
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)
{
d='&type_id='+type_id+'&face_id='+face_id
$.ajax({ type: 'POST', data: d, url: '/add_no_match_override',
success: function(data) {
document.viewing.file_details.faces[face_pos].fnmo[0]=data
$('#dbox').modal('hide')
$('#faces').prop('checked',true)
DrawImg()
CheckForJobs()
}
} )
}
// 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='<h5>search for existing person:</h5>'
html+=`
<div class="input-group mb-3"><input type="text" class="form-control" id="stext" placeholder="tag/name">
<button id="search_person_btn" class="btn btn-outline-success" type="button"
onClick="SearchForPerson( `
html+= "'" + content + "', " + "'" +key+"'" + ', ' + item[key].id + ',' + face_pos + ',' + item[key].type_id
html+=`)">Search</button>
</div>
<div id="search_person_results">
</div>
<script>
$("#stext").keypress(function (e) { if (e.which == 13) { $("#search_person_btn").click(); return false; } } )
</script>`
return html
}
// function that is called when we click on a face in the viewer and we want to
// potentially override the non-match / match... it shows the face, and then
// based on which menu item got us here, shows appropriate text to do next action
function FaceDBox(key, item)
{
face_pos=item[key]['which_face']
div ='<div class="col-6"><p>'
div+='Face position #' + face_pos
// use w-100 to force width to not make face image wider than half the dbox
div+='</p><div class="col-6 w-100"> <img id="face_img" class="w-100"></img></div>'
$.ajax({ type: 'POST', data: null, url: '/get_face_from_image/'+item[key].id,
success: function(img_data) {
item[key].refimg_data=img_data
$('#face_img').prop('src', 'data:image/jpeg;base64,' + img_data )
// used for create_new_person only, so this will do nothing for option menu items
$('#refimg_data').val(img_data)
}
} )
div+='</div><div class="col-6">'
if ( key == 'remove_force_match_override' )
{
if( document.viewing.file_details.faces[face_pos].ffmo.length )
div+='<div class="row col-12">remove this override (force match to: ' + document.viewing.file_details.faces[face_pos].ffmo[0].person.tag + ')</div>'
else
div+='<div class="row col-12">remove this override (' + document.viewing.file_details.faces[face_pos].fnmo[0].type.name + ')</div>'
div+='<div class="row">'
div+='<button class="btn btn-outline-info col-6" type="button" onClick="$(\'#dbox\').modal(\'hide\'); return false">Cancel</button>'
div+='<button class="btn btn-outline-danger col-6" type="button" '
if( document.viewing.file_details.faces[face_pos].ffmo.length )
div+='onClick="RemoveOverrideForceMatch(' +face_pos+ ')">Remove</button>'
else
div+='onClick="RemoveOverrideNoMatch(' +face_pos+','+document.viewing.file_details.faces[face_pos].fnmo[0].type.id+ ')">Remove</button>'
div+='</div>'
}
if ( key == 'no_match_new_person' )
{
div+='<input type="hidden" id="refimg_data" name="refimg_data" value=""></input>'
div+=`
<div class="row col-12">
<label class="col-3" for="tag">Tag (searchable name):</label>
<input class="form-control col" id="tag" name="tag" required="" type="text" value="">
</div>
<div class="row col-12">
<label class="col-3" for="firstname">FirstName(s):</label>
<input class="form-control col" id="firstname" name="firstname" required="" type="text" value="">
</div>
<div class="row col-12">
<label class="col-3" for="surname">Surname:</label>
<input class="form-control col" id="surname" name="surname" required="" type="text" value="">
</div>
<div class="row col-12">
`
div+='<button class="btn btn-primary offset-3 col-2" type="button"'
div+='onClick="CreatePersonAndRefimg(\''+key+'\')">Save</button>'
div+='</div>'
}
if ( key == 'no_match_new_refimg' )
{
div+=AddSearch( 'Click one of the link(s) below to add this face as a reference image to the person:<br><br>', key, face_pos );
}
if ( key == 'match_add_refimg' )
{
func='AddRefimgTo('+item[key]['person_id']+',\''+key+'\''
func_sn=func+ ', true )'
func_ao=func+ ', false )'
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+= '<button onClick="'+func_sn+'" class="btn btn-success py-1 input-group-prepend">Add & search now</button>&nbsp;'
div+= '<button onClick="'+func_ao+'" class="btn btn-outline-success py-1 input-group-append">Add only</button></div>'
}
if ( key == 'wrong_person' )
{
div+='<br>wrong person, so mark this as the wrong person/refimg connection, for face#' + item[key]['which_face']
div+='<br>face db id: ' + item[key]['id']
div += '<br>not yet'
}
if( /NMO_/.test(key) )
{
if( item[key].name == 'Override: Manual match to existing person' )
{
div+=AddSearch( 'Click one of the link(s) below to manually connect this face as once-off connection to the person:<br><br>', key, face_pos );
}
else
{
type_id=item[key].type_id
face_id=item[key].id
div+='<div class="row">'
div+='<button class="btn btn-outline-info col-6" type="button" onClick="$(\'#dbox\').modal(\'hide\'); return false">Cancel</button>'
div+='<button class="btn btn-outline-danger col-6" type="button" '+
'onClick="AddNoMatchOverride('+type_id+','+face_id+','+face_pos+','+type_id+ ')">Apply Override</button>'
div+='</div>'
}
}
div+='</div>'
$('#dbox-title').html(item[key]['name'])
$('#dbox-content').html(div)
$('#dbox').modal('show')
}
// func called to show logs relating to this filename from viewer
// pops results up in a dbox
function JoblogSearch()
{
data="eid="+document.viewing.id
$.ajax({ type: 'POST', data: data, url: '/joblog_search', success: function(res) {
data = JSON.parse(res)
div ='<div><table class="table table-striped table-sm sm-txt">'
div+='<tr><th>Log</th><th>When</th><th>Job</th></tr>'
for( i=0; i<data.length; i++ )
{
div+='<tr><td>' + data[i].log + '</td><td>' + data[i].log_date + '</td><td>'
div+='<a href="/job/' + data[i].id + '">' + data[i].name + ' #:'+data[i].id+'</a></td></tr>'
}
div+='</table></div>'
$('#dbox-title').html("Logs relating to this filename")
$('#dbox-content').html(div)
$('#dbox').modal('show')
}
})
}
// 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()
}