Compare commits
5 Commits
1e421c3f22
...
517b5c6167
| Author | SHA1 | Date | |
|---|---|---|---|
| 517b5c6167 | |||
| 16d28bc02e | |||
| da0019ecdc | |||
| e4bf9606b9 | |||
| 3a053bea49 |
5
TODO
5
TODO
@@ -1,5 +1,10 @@
|
|||||||
###
|
###
|
||||||
|
#
|
||||||
|
# consider how to better version jscript - across all html files, consistently
|
||||||
|
# mtime, didnt work anyway, my phone still wont pick up the change, it was adding any ?v= changed this (once)
|
||||||
|
#
|
||||||
# 4 TEST everything (don't forget keybindings,e.g. delete)
|
# 4 TEST everything (don't forget keybindings,e.g. delete)
|
||||||
|
# going up from folder view shows different order?
|
||||||
#
|
#
|
||||||
# 5 think I killed pa_job_manager without passing an eid to a transform job, shouldn't crash
|
# 5 think I killed pa_job_manager without passing an eid to a transform job, shouldn't crash
|
||||||
# SHOULD JUST get AI to help clean-up and write defensive code here...
|
# SHOULD JUST get AI to help clean-up and write defensive code here...
|
||||||
|
|||||||
26
files.py
26
files.py
@@ -461,7 +461,8 @@ def change_file_opts():
|
|||||||
def file_list_ip():
|
def file_list_ip():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
return render_template("file_list.html", page_title='View File Details (Import Path)', query_data=query_data, OPT=OPT )
|
js_vers = getVersions()
|
||||||
|
return render_template("file_list.html", page_title='View File Details (Import Path)', query_data=query_data, OPT=OPT, js_vers=js_vers )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from import_path(s)
|
# /files -> show thumbnail view of files from import_path(s)
|
||||||
@@ -471,7 +472,8 @@ def file_list_ip():
|
|||||||
def files_ip():
|
def files_ip():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data )
|
js_vers = getVersions()
|
||||||
|
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data, js_vers=js_vers )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from storage_path
|
# /files -> show thumbnail view of files from storage_path
|
||||||
@@ -481,7 +483,8 @@ def files_ip():
|
|||||||
def files_sp():
|
def files_sp():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data )
|
js_vers = getVersions()
|
||||||
|
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data, js_vers=js_vers )
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -492,7 +495,8 @@ def files_sp():
|
|||||||
def files_rbp():
|
def files_rbp():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data )
|
js_vers = getVersions()
|
||||||
|
return render_template("files.html", page_title=f"View Files ({OPT.path_type} Path)", OPT=OPT, query_data=query_data, js_vers=js_vers )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# search -> GET version -> has search_term in the URL and is therefore able to
|
# search -> GET version -> has search_term in the URL and is therefore able to
|
||||||
@@ -771,3 +775,17 @@ def get_existing_paths(dt):
|
|||||||
first_dir=0
|
first_dir=0
|
||||||
ret+= ' ]'
|
ret+= ' ]'
|
||||||
return make_response( ret )
|
return make_response( ret )
|
||||||
|
|
||||||
|
# quick helper func to return timestamps of jscript files
|
||||||
|
# we use this as a quick/hacky way of versioning them
|
||||||
|
def getVersions():
|
||||||
|
js_vers={}
|
||||||
|
js_vers['fs'] = int(os.path.getmtime( "."+url_for( 'internal', filename='js/files_support.js') ))
|
||||||
|
js_vers['vs'] = int(os.path.getmtime( "."+url_for( 'internal', filename='js/view_support.js') ))
|
||||||
|
js_vers['ft'] = int(os.path.getmtime( "."+url_for( 'internal', filename='js/files_transform.js') ))
|
||||||
|
js_vers['ic'] = int(os.path.getmtime( "."+url_for( 'internal', filename='icons.svg') ))
|
||||||
|
js_vers['r180'] = int(os.path.getmtime( "."+url_for( 'internal', filename='rot180.png') ))
|
||||||
|
js_vers['r270'] = int(os.path.getmtime( "."+url_for( 'internal', filename='rot270.png') ))
|
||||||
|
js_vers['r90'] = int(os.path.getmtime( "."+url_for( 'internal', filename='rot90.png') ))
|
||||||
|
js_vers['th'] = int(os.path.getmtime( "."+url_for( 'internal', filename='throbber.gif') ))
|
||||||
|
return js_vers
|
||||||
|
|||||||
@@ -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]
|
||||||
@@ -524,12 +506,13 @@ function drawPageOfFigures()
|
|||||||
else if( OPT.root_eid == 0 )
|
else if( OPT.root_eid == 0 )
|
||||||
$('#figures').append( `<span class="alert alert-danger p-2 col-auto d-flex align-items-center">No files in Path!</span>` )
|
$('#figures').append( `<span class="alert alert-danger p-2 col-auto d-flex align-items-center">No files in Path!</span>` )
|
||||||
$('.figure').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
$('.figure').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
||||||
$('.figure').dblclick( function(e) { dblClickToViewEntry( $(this).attr('id') ); setDisabledForViewingNextPrevBttons(); addViewerKeyHandler() } )
|
$('.figure').dblclick( function(e) { startViewing( $(this).attr('id') ) } )
|
||||||
// for dir, getDirEntries 2nd param is back (or "up" a dir)
|
// for dir, getDirEntries 2nd param is back (or "up" a dir)
|
||||||
$(".dir").click( function(e) { document.back_id=this.id; getDirEntries(this.id,false) } )
|
$(".dir").click( function(e) { document.back_id=this.id; getDirEntries(this.id,false) } )
|
||||||
$(".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',
|
||||||
@@ -906,7 +779,7 @@ $.contextMenu({
|
|||||||
return {
|
return {
|
||||||
callback: function( key, options) {
|
callback: function( key, options) {
|
||||||
if( key == "details" ) { DetailsDBox() }
|
if( key == "details" ) { DetailsDBox() }
|
||||||
if( key == "view" ) { dblClickToViewEntry( $(this).attr('id') ) }
|
if( key == "view" ) { startViewing( $(this).attr('id') ) }
|
||||||
if( key == "move" ) { MoveDBox(move_paths) }
|
if( key == "move" ) { MoveDBox(move_paths) }
|
||||||
if( key == "del" ) { DelDBox('Delete') }
|
if( key == "del" ) { DelDBox('Delete') }
|
||||||
if( key == "undel") { DelDBox('Restore') }
|
if( key == "undel") { DelDBox('Restore') }
|
||||||
@@ -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()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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> '
|
div+= '<button onClick="'+func_sn+'" class="btn btn-success py-1 input-group-prepend">Add & search now</button> '
|
||||||
@@ -565,7 +570,168 @@ 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()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper func to start the viewer - needed as we have a dbl-click & View file
|
||||||
|
// to start the viewer
|
||||||
|
function startViewing(eid)
|
||||||
|
{
|
||||||
|
dblClickToViewEntry( eid );
|
||||||
|
setDisabledForViewingNextPrevBttons();
|
||||||
|
addViewerKeyHandler()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %} {% block main_content %}
|
{% extends "base.html" %} {% block main_content %}
|
||||||
<script src="{{ url_for( 'internal', filename='js/files_support.js')}}"></script>
|
<script src="{{ url_for( 'internal', filename='js/files_support.js')}}?v={{js_vers['fs']}}"></script>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h3 class="offset-2">{{page_title}}</h3>
|
<h3 class="offset-2">{{page_title}}</h3>
|
||||||
@@ -9,11 +9,11 @@
|
|||||||
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"], "changeOPT(getPageFileList); return false", "rounded-end py-1 my-1" )|safe }}
|
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"], "changeOPT(getPageFileList); return false", "rounded-end py-1 my-1" )|safe }}
|
||||||
<div class="mb-1 col my-auto d-flex justify-content-center">
|
<div class="mb-1 col my-auto d-flex justify-content-center">
|
||||||
<button id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary" onClick="prevPage(getPageFileList)">
|
<button id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary" onClick="prevPage(getPageFileList)">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
||||||
<button id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFileList)">
|
<button id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFileList)">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div class="col...">
|
</div class="col...">
|
||||||
</div class="input-group...">
|
</div class="input-group...">
|
||||||
@@ -26,11 +26,11 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-auto d-flex justify-content-center">
|
<div class="col my-auto d-flex justify-content-center">
|
||||||
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFileList)" disabled>
|
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFileList)" disabled>
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
||||||
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFileList)">
|
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFileList)">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div class="col my-auto"> </div class="row">
|
</div class="col my-auto"> </div class="row">
|
||||||
</div class="container-fluid">
|
</div class="container-fluid">
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
{% block main_content %}
|
{% block main_content %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
#la, #ra {
|
||||||
|
padding: 5% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
.norm-txt { font-size: 1.0rem }
|
.norm-txt { font-size: 1.0rem }
|
||||||
.form-check-input:checked {
|
.form-check-input:checked {
|
||||||
background-color: #39C0ED;
|
background-color: #39C0ED;
|
||||||
@@ -15,9 +20,9 @@
|
|||||||
}
|
}
|
||||||
#tst90:hover,#tst90:focus { filter: invert(73%) sepia(27%) saturate(3970%) hue-rotate(146deg) brightness(94%) contrast(100%); }
|
#tst90:hover,#tst90:focus { filter: invert(73%) sepia(27%) saturate(3970%) hue-rotate(146deg) brightness(94%) contrast(100%); }
|
||||||
</style>
|
</style>
|
||||||
<script src="{{ url_for( 'internal', filename='js/files_transform.js')}}"></script>
|
<script src="{{ url_for( 'internal', filename='js/files_transform.js')}}?v={{ js_vers['ft'] }}"></script>
|
||||||
<script src="{{ url_for( 'internal', filename='js/files_support.js')}}"></script>
|
<script src="{{ url_for( 'internal', filename='js/files_support.js')}}?v={{ js_vers['fs'] }}"></script>
|
||||||
<script src="{{ url_for( 'internal', filename='js/view_support.js')}}"></script>
|
<script src="{{ url_for( 'internal', filename='js/view_support.js')}}?v={{ js_vers['vs'] }}"></script>
|
||||||
|
|
||||||
<div id="files_div">
|
<div id="files_div">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@@ -26,13 +31,13 @@
|
|||||||
<div class="my-auto col col-auto">
|
<div class="my-auto col col-auto">
|
||||||
<span class="alert alert-primary py-2">
|
<span class="alert alert-primary py-2">
|
||||||
{% if "files_ip" in request.url %}
|
{% if "files_ip" in request.url %}
|
||||||
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#import"/></svg>
|
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#import"/></svg>
|
||||||
{% set tmp_path=OPT.cwd | replace( "static/Import", "" ) + "/" %}
|
{% set tmp_path=OPT.cwd | replace( "static/Import", "" ) + "/" %}
|
||||||
{% elif "files_sp" in request.url %}
|
{% elif "files_sp" in request.url %}
|
||||||
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#db"/></svg>
|
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#db"/></svg>
|
||||||
{% set tmp_path=OPT.cwd | replace( "static/Storage", "" ) + "/" %}
|
{% set tmp_path=OPT.cwd | replace( "static/Storage", "" ) + "/" %}
|
||||||
{% elif "files_rbp" in request.url %}
|
{% elif "files_rbp" in request.url %}
|
||||||
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#trash"/></svg>
|
<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#trash"/></svg>
|
||||||
{% set tmp_path=OPT.cwd | replace( "static/Bin", "" ) + "/" %}
|
{% set tmp_path=OPT.cwd | replace( "static/Bin", "" ) + "/" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{tmp_path}}</span>
|
{{tmp_path}}</span>
|
||||||
@@ -58,21 +63,21 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="col flex-grow-1 my-auto d-flex justify-content-center w-100">
|
<div class="col flex-grow-1 my-auto d-flex justify-content-center w-100">
|
||||||
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFigures)" disabled>
|
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFigures)" disabled>
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
||||||
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFigures)">
|
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFigures)">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button aria-label="move" id="move" disabled name="move" class="sm-txt btn btn-outline-primary ms-4" onClick="MoveDBox(move_paths); return false;">
|
<button aria-label="move" id="move" disabled name="move" class="sm-txt btn btn-outline-primary ms-4" onClick="MoveDBox(move_paths); return false;">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#folder_plus"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#folder_plus"/></svg>
|
||||||
</button>
|
</button>
|
||||||
{% if "files_rbp" in request.url %}
|
{% if "files_rbp" in request.url %}
|
||||||
<button aria-label="delete" id="del" disabled name="del" class="sm-txt btn btn-outline-success mx-1" onClick="DelDBox('Restore'); return false;">
|
<button aria-label="delete" id="del" disabled name="del" class="sm-txt btn btn-outline-success mx-1" onClick="DelDBox('Restore'); return false;">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#trash-fill"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#trash-fill"/></svg>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button aria-label="delete" id="del" disabled name="del" class="sm-txt btn btn-outline-danger mx-1" onClick="DelDBox('Delete'); return false;">
|
<button aria-label="delete" id="del" disabled name="del" class="sm-txt btn btn-outline-danger mx-1" onClick="DelDBox('Delete'); return false;">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#trash-fill"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#trash-fill"/></svg>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</button>
|
</button>
|
||||||
<button style="visibility:hidden" class="btn btn-outline-secondary" aria-label="shift-key" id="shift-key" onclick="document.fake_shift=1-document.fake_shift; event.stopPropagation(); return false">shift</button>
|
<button style="visibility:hidden" class="btn btn-outline-secondary" aria-label="shift-key" id="shift-key" onclick="document.fake_shift=1-document.fake_shift; event.stopPropagation(); return false">shift</button>
|
||||||
@@ -104,11 +109,11 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col my-auto d-flex justify-content-center">
|
<div class="col my-auto d-flex justify-content-center">
|
||||||
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFigures)" disabled>
|
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage(getPageFigures)" disabled>
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
||||||
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFigures)">
|
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFigures)">
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div class="col my-auto">
|
</div class="col my-auto">
|
||||||
</div class="row">
|
</div class="row">
|
||||||
@@ -116,25 +121,25 @@
|
|||||||
</div id="files_div">
|
</div id="files_div">
|
||||||
<div id="viewer_div" class="d-none">
|
<div id="viewer_div" class="d-none">
|
||||||
<div id="viewer" class="container-fluid">
|
<div id="viewer" class="container-fluid">
|
||||||
<div class="row">
|
<div class="row flex-nowrap">
|
||||||
<!-- Left Buttons Column -->
|
<!-- Left Buttons Column -->
|
||||||
<div class="col-auto d-flex flex-column">
|
<div class="col-auto d-flex flex-column min-width-0">
|
||||||
<!-- Up Button (Small) -->
|
<!-- Up Button (Small) -->
|
||||||
<button title="Back to list" class="btn btn-outline-info btn-sm p-1 mb-1" onclick="goOutOfViewer()">
|
<button title="Back to list" class="btn btn-outline-info btn-sm p-1 mb-1" onclick="goOutOfViewer()">
|
||||||
<svg width="16" height="16" fill="currentColor">
|
<svg width="16" height="16" fill="currentColor">
|
||||||
<use xlink:href="/internal/icons.svg#back"></use>
|
<use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#back"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<!-- Left Button (large/flex-grow-1) -->
|
<!-- Left Button (large/flex-grow-1) -->
|
||||||
<button title="Show previous image" class="btn btn-outline-info px-2 flex-grow-1"
|
<button title="Show previous image" class="btn btn-outline-info px-2 flex-grow-1 overflow-hidden"
|
||||||
style="padding: 10%" id="la" onClick="prevImageInViewer()">
|
style="padding: 10%" id="la" onClick="prevImageInViewer()">
|
||||||
<svg width="16" height="16" fill="currentColor">
|
<svg width="16" height="16" fill="currentColor">
|
||||||
<use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
<use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<figure class="col col-auto border border-info rounded m-0 p-1" id="figure">
|
<figure class="col col-auto border border-info rounded m-0 p-1" id="figure">
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
<img id="throbber" src="{{url_for('internal', filename='throbber.gif')}}" style="display:none;">
|
<img id="throbber" src="{{url_for('internal', filename='throbber.gif')}}?v={{js_vers[th]}}" style="display:none;">
|
||||||
<script>
|
<script>
|
||||||
var im=new Image();
|
var im=new Image();
|
||||||
im.onload=DrawImg
|
im.onload=DrawImg
|
||||||
@@ -152,18 +157,18 @@
|
|||||||
<span id="fname_v"></span></figcaption>
|
<span id="fname_v"></span></figcaption>
|
||||||
</div>
|
</div>
|
||||||
<!-- Right-hand Buttons Column -->
|
<!-- Right-hand Buttons Column -->
|
||||||
<div class="col-auto d-flex flex-column">
|
<div class="col-auto d-flex flex-column min-width-0">
|
||||||
<!-- Up Button (Small) -->
|
<!-- Up Button (Small) -->
|
||||||
<button title="Back to list" class="btn btn-outline-info btn-sm p-1 mb-1" onclick="goOutOfViewer()">
|
<button title="Back to list" class="btn btn-outline-info btn-sm p-1 mb-1" onclick="goOutOfViewer()">
|
||||||
<svg width="16" height="16" fill="currentColor">
|
<svg width="16" height="16" fill="currentColor">
|
||||||
<use xlink:href="/internal/icons.svg#back"></use>
|
<use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#back"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<!-- Right Button (large/flex-grow-1) -->
|
<!-- Right Button (large/flex-grow-1) -->
|
||||||
<button title="Show next image" class="btn btn-outline-info px-2 flex-grow-1"
|
<button title="Show next image" class="btn btn-outline-info px-2 flex-grow-1 overflow-hidden"
|
||||||
style="padding: 10%" id="ra" onClick="nextImageInViewer()">
|
style="padding: 10%" id="ra" onClick="nextImageInViewer()">
|
||||||
<svg width="16" height="16" fill="currentColor">
|
<svg width="16" height="16" fill="currentColor">
|
||||||
<use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div class="row">
|
</div class="row">
|
||||||
@@ -171,7 +176,7 @@
|
|||||||
{# this whole div, just takes up the same space as the left button and is hidden for alignment only #}
|
{# this whole div, just takes up the same space as the left button and is hidden for alignment only #}
|
||||||
<div class="col-auto px-0">
|
<div class="col-auto px-0">
|
||||||
<button class="btn btn-outline-info px-2 invisible" disabled>
|
<button class="btn btn-outline-info px-2 invisible" disabled>
|
||||||
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="col-auto my-auto">Show:</span>
|
<span class="col-auto my-auto">Show:</span>
|
||||||
@@ -194,34 +199,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-auto pt-1">
|
<div class="col col-auto pt-1">
|
||||||
<button class="btn btn-outline-info p-1" title="Rotate by 90 degrees" onClick="Transform(90)">
|
<button class="btn btn-outline-info p-1" title="Rotate by 90 degrees" onClick="Transform(90)">
|
||||||
<img src="{{url_for('internal', filename='rot90.png')}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot90-invert.png')}}'"
|
<img src="{{url_for('internal', filename='rot90.png')}}?v={{js_vers['r90']}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot90-invert.png')}}'"
|
||||||
onMouseOut="this.src='{{url_for('internal', filename='rot90.png')}}'" />
|
onMouseOut="this.src='{{url_for('internal', filename='rot90.png')}}?v={{js_vers['r90']}}'" />
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="Rotate by 180 degrees" onClick="Transform(180)">
|
<button class="btn btn-outline-info p-1" title="Rotate by 180 degrees" onClick="Transform(180)">
|
||||||
<img src="{{url_for('internal', filename='rot180.png')}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot180-invert.png')}}'"
|
<img src="{{url_for('internal', filename='rot180.png')}}?v={{js_vers['r180']}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot180-invert.png')}}'"
|
||||||
onMouseOut="this.src='{{url_for('internal', filename='rot180.png')}}'" />
|
onMouseOut="this.src='{{url_for('internal', filename='rot180.png')}}?v={{js_vers['r180']}}'" />
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="Rotate by 270 degrees" onClick="Transform(270)">
|
<button class="btn btn-outline-info p-1" title="Rotate by 270 degrees" onClick="Transform(270)">
|
||||||
<img src="{{url_for('internal', filename='rot270.png')}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot270-invert.png')}}'"
|
<img src="{{url_for('internal', filename='rot270.png')}}?v={{js_vers['r270']}}" width="32" height="32" onMouseOver="this.src='{{url_for('internal', filename='rot270-invert.png')}}'"
|
||||||
onMouseOut="this.src='{{url_for('internal', filename='rot270.png')}}'" />
|
onMouseOut="this.src='{{url_for('internal', filename='rot270.png')}}?v={{js_vers['r270']}}'" />
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="Flip horizontally" onClick="Transform('fliph')">
|
<button class="btn btn-outline-info p-1" title="Flip horizontally" onClick="Transform('fliph')">
|
||||||
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#flip_h"/></svg>
|
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#flip_h"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="Flip vertically" onClick="Transform('flipv')">
|
<button class="btn btn-outline-info p-1" title="Flip vertically" onClick="Transform('flipv')">
|
||||||
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#flip_v"/></svg>
|
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#flip_v"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="View in Fullscreen mode (hotkey: F)" onClick="fullscreen=true; ViewImageOrVideo()">
|
<button class="btn btn-outline-info p-1" title="View in Fullscreen mode (hotkey: F)" onClick="fullscreen=true; ViewImageOrVideo()">
|
||||||
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#fullscreen"/></svg>
|
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#fullscreen"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="Show logs relating to this filename (hotkey: l)" onClick="JoblogSearch()">
|
<button class="btn btn-outline-info p-1" title="Show logs relating to this filename (hotkey: l)" onClick="JoblogSearch()">
|
||||||
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#log"/></svg>
|
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#log"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-outline-info p-1" title="View Original" onClick="window.location='/'+document.viewing.FullPathOnFS">
|
<button class="btn btn-outline-info p-1" title="View Original" onClick="window.location='/'+document.viewing.FullPathOnFS">
|
||||||
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#download"/></svg>
|
<svg width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#download"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<button id="viewer_del" class="btn btn-outline-danger p-1" title="Delete (hotkey: Del)" onClick="DelDBox('Delete')">
|
<button id="viewer_del" class="btn btn-outline-danger p-1" title="Delete (hotkey: Del)" onClick="DelDBox('Delete')">
|
||||||
<svg id="viewer_bin" width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#trash"/></svg>
|
<svg id="viewer_bin" width="32" height="32" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#trash"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div class="row">
|
</div class="row">
|
||||||
@@ -267,17 +272,17 @@
|
|||||||
s='<span class="alert alert-secondary py-2">'
|
s='<span class="alert alert-secondary py-2">'
|
||||||
if( fname.indexOf( "static/Import" ) == 0 )
|
if( fname.indexOf( "static/Import" ) == 0 )
|
||||||
{
|
{
|
||||||
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#import"/></svg>'
|
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#import"/></svg>'
|
||||||
tmp_path=fname.replace("statuc/Import","" )
|
tmp_path=fname.replace("statuc/Import","" )
|
||||||
}
|
}
|
||||||
if( fname.indexOf( "static/Storage" ) == 0 )
|
if( fname.indexOf( "static/Storage" ) == 0 )
|
||||||
{
|
{
|
||||||
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#db"/></svg>'
|
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#db"/></svg>'
|
||||||
tmp_path=fname.replace("static/Storage","" )
|
tmp_path=fname.replace("static/Storage","" )
|
||||||
}
|
}
|
||||||
if( fname.indexOf( "static/Bin" ) == 0 )
|
if( fname.indexOf( "static/Bin" ) == 0 )
|
||||||
{
|
{
|
||||||
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#trash-fill"/></svg>'
|
s+='<svg width="20" height="20" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}?v={{js_vers['ic']}}#trash-fill"/></svg>'
|
||||||
tmp_path=fname.replace("static/Bin","" )
|
tmp_path=fname.replace("static/Bin","" )
|
||||||
}
|
}
|
||||||
s+=tmp_path+'</span>'
|
s+=tmp_path+'</span>'
|
||||||
|
|||||||
Reference in New Issue
Block a user