moved cFO() to changeOPT() into internal/js, transformed file_list_ip to work with new query_data model, made the Size buttons use modern bootstrap5 radio buttons and work again without the form for all file* routes. Removed a lot of dead code, moved code to resetNextPrev buttons to anytime we getPage, reducing code, handle setting OPT in jscript via a to_dict() for States. Overall, search and file_list_ip now work. Only main thing left is the override code
This commit is contained in:
2
TODO
2
TODO
@@ -1,5 +1,5 @@
|
|||||||
###
|
###
|
||||||
# get search to work
|
# get override data into view
|
||||||
###
|
###
|
||||||
|
|
||||||
### major fix - go to everywhere I call GetEntries(), and redo the logic totally...
|
### major fix - go to everywhere I call GetEntries(), and redo the logic totally...
|
||||||
|
|||||||
451
files.py
451
files.py
@@ -2,7 +2,7 @@ from flask_wtf import FlaskForm
|
|||||||
from flask import request, render_template, redirect, send_from_directory, url_for, jsonify, make_response
|
from flask import request, render_template, redirect, send_from_directory, url_for, jsonify, make_response
|
||||||
from marshmallow import Schema, fields
|
from marshmallow import Schema, fields
|
||||||
from main import db, app, ma
|
from main import db, app, ma
|
||||||
from sqlalchemy import Sequence, text, select
|
from sqlalchemy import Sequence, text, select, union
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
import os
|
import os
|
||||||
@@ -252,173 +252,6 @@ def UpdatePref( pref, OPT ):
|
|||||||
pref.last_used=last_used
|
pref.last_used=last_used
|
||||||
db.session.add(pref)
|
db.session.add(pref)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# GetEntriesInFlatView: func. to retrieve DB entries appropriate for flat view
|
|
||||||
################################################################################
|
|
||||||
def GetEntriesInFlatView( OPT, prefix ):
|
|
||||||
entries=[]
|
|
||||||
num_entries=0
|
|
||||||
|
|
||||||
join = "Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix)"
|
|
||||||
entries = eval( f"{join}.{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
|
||||||
|
|
||||||
if OPT.first_eid == 0 and OPT.offset == 0 and len(entries):
|
|
||||||
OPT.first_eid = entries[0].id
|
|
||||||
|
|
||||||
if OPT.last_eid==0:
|
|
||||||
num_entries = eval( f"{join}.count()" )
|
|
||||||
last_entry = eval( f"{join}.{OPT.last_order}.limit(1).first()" )
|
|
||||||
if last_entry:
|
|
||||||
OPT.last_eid = last_entry.id
|
|
||||||
|
|
||||||
return entries, num_entries
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# GetEntriesInFolderView: func. to retrieve DB entries appropriate for folder view
|
|
||||||
# read inline comments to deal with variations / ordering...
|
|
||||||
################################################################################
|
|
||||||
def GetEntriesInFolderView( OPT, prefix ):
|
|
||||||
entries=[]
|
|
||||||
num_entries=0
|
|
||||||
# okay the root cwd is fake, so treat it specially - its Dir can be found by path with dir.rel_path=''
|
|
||||||
if os.path.dirname(OPT.cwd) == 'static':
|
|
||||||
dir=Entry.query.join(Dir).join(PathDirLink).join(Path).filter(Dir.rel_path=='').filter(Path.path_prefix==prefix).order_by(Entry.name).first()
|
|
||||||
# this can occur if the path in settings does not exist as it wont be in # the DB
|
|
||||||
if not dir:
|
|
||||||
return entries, num_entries
|
|
||||||
# although this is 1 entry, needs to come back via all() to be iterable
|
|
||||||
entries+= Entry.query.filter(Entry.id==dir.id).all()
|
|
||||||
else:
|
|
||||||
rp = OPT.cwd.replace( prefix, '' )
|
|
||||||
# when in subdirs, replacing prefix will leave the first char as /, get rid of it
|
|
||||||
if len(rp) and rp[0] == '/':
|
|
||||||
rp=rp[1:]
|
|
||||||
dir=Entry.query.join(Dir).join(PathDirLink).join(Path).filter(Dir.rel_path==rp).filter(Path.path_prefix==prefix).order_by(Entry.name).first()
|
|
||||||
# this can occur if the path in settings does not exist as it wont be in # the DB
|
|
||||||
if not dir:
|
|
||||||
return entries, 0
|
|
||||||
# dirs cant be sorted by date really, so do best I can for now
|
|
||||||
if OPT.noo == "Z to A" or OPT.noo == "Newest":
|
|
||||||
entries+= Entry.query.join(EntryDirLink).join(FileType).filter(EntryDirLink.dir_eid==dir.id).filter(FileType.name=='Directory').order_by(Entry.name.desc()).all()
|
|
||||||
# just do A to Z / Oldest by default or if no valid option
|
|
||||||
else:
|
|
||||||
entries+= Entry.query.join(EntryDirLink).join(FileType).filter(EntryDirLink.dir_eid==dir.id).filter(FileType.name=='Directory').order_by(Entry.name).all()
|
|
||||||
|
|
||||||
# add any files at the current CWD (based on dir_eid in DB)
|
|
||||||
join="Entry.query.join(File).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir.id)"
|
|
||||||
file_entries= eval( f"{join}.{OPT.order}.offset(OPT.offset).limit(OPT.how_many).all()")
|
|
||||||
|
|
||||||
if OPT.offset == 0 and len(file_entries):
|
|
||||||
OPT.first_eid = file_entries[0].id
|
|
||||||
num_entries = eval( f"{join}.count()" )
|
|
||||||
last_entry = eval( f"{join}.{OPT.last_order}.limit(1).first()" )
|
|
||||||
if last_entry:
|
|
||||||
OPT.last_eid = last_entry.id
|
|
||||||
|
|
||||||
entries += file_entries;
|
|
||||||
return entries, num_entries
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# GetEntriesInSearchView: func. to retrieve DB entries appropriate for Search view
|
|
||||||
# Defaults search is for any matching filename, contents of any matching dirname
|
|
||||||
# and any match with AI / face for that term. Explicit, only AI match via
|
|
||||||
# AI:<tag> syntax
|
|
||||||
################################################################################
|
|
||||||
def GetEntriesInSearchView( OPT ):
|
|
||||||
search_term=OPT.orig_search_term
|
|
||||||
# turn * wildcard into sql wildcard of %
|
|
||||||
search_term=search_term.replace('*', '%' )
|
|
||||||
if 'AI:' in OPT.orig_search_term:
|
|
||||||
search_term = search_term.replace('AI:','')
|
|
||||||
join=f"Entry.query.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag == search_term)"
|
|
||||||
else:
|
|
||||||
join=f"Entry.query.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag.ilike('%{search_term}%'))"
|
|
||||||
if 'AI:' in OPT.orig_search_term:
|
|
||||||
all_entries = eval( f"{join}.{OPT.order}.offset(OPT.offset).limit(OPT.how_many).all()")
|
|
||||||
else:
|
|
||||||
file_data=eval( f"Entry.query.join(File).filter(Entry.name.ilike('%{search_term}%')).{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
|
||||||
dir_data =eval( f"Entry.query.join(File).join(EntryDirLink).join(Dir).filter(Dir.rel_path.ilike('%{search_term}%')).{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
|
||||||
ai_data =eval( f"{join}.{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()")
|
|
||||||
|
|
||||||
# remove any duplicates from combined data
|
|
||||||
all_entries = []
|
|
||||||
for f in file_data:
|
|
||||||
all_entries.append(f)
|
|
||||||
for d in dir_data:
|
|
||||||
add_it=1
|
|
||||||
for f in file_data:
|
|
||||||
if d.name == f.name:
|
|
||||||
add_it=0
|
|
||||||
break
|
|
||||||
if add_it:
|
|
||||||
all_entries.append(d)
|
|
||||||
for a in ai_data:
|
|
||||||
add_it=1
|
|
||||||
for f in file_data:
|
|
||||||
if a.name == f.name:
|
|
||||||
add_it=0
|
|
||||||
break
|
|
||||||
if add_it:
|
|
||||||
all_entries.append(a)
|
|
||||||
|
|
||||||
# nothing found, just return now
|
|
||||||
if len(all_entries) == 0:
|
|
||||||
OPT.num_entries = 0
|
|
||||||
return []
|
|
||||||
|
|
||||||
# for all searches first_entry is worked out when first_eid not set yet & offset is 0 and we have some entries
|
|
||||||
if OPT.first_eid == 0 and OPT.offset == 0 and len(all_entries):
|
|
||||||
OPT.first_eid = all_entries[0].id
|
|
||||||
if OPT.last_eid == 0:
|
|
||||||
by_fname= f"select e.id from entry e where e.name ilike '%%{search_term}%%'"
|
|
||||||
by_dirname=f"select e.id from entry e, entry_dir_link edl where edl.entry_id = e.id and edl.dir_eid in ( select d.eid from dir d where d.rel_path ilike '%%{search_term}%%' )"
|
|
||||||
by_ai =f"select e.id from entry e, face_file_link ffl, face_refimg_link frl, person_refimg_link prl, person p where e.id = ffl.file_eid and frl.face_id = ffl.face_id and frl.refimg_id = prl.refimg_id and prl.person_id = p.id and p.tag = '{search_term}'"
|
|
||||||
|
|
||||||
if 'AI:' in OPT.orig_search_term:
|
|
||||||
sel_no_order=f"select e.*, f.* from entry e, file f where e.id=f.eid and e.id in ( {by_ai} ) "
|
|
||||||
else:
|
|
||||||
sel_no_order=f"select e.*, f.* from entry e, file f where e.id=f.eid and e.id in ( {by_fname} union {by_dirname} union {by_ai} ) "
|
|
||||||
|
|
||||||
#num_entries
|
|
||||||
num_e_sql = f"select count(1) from ( {by_fname} union {by_dirname} union {by_ai} ) as foo"
|
|
||||||
with db.engine.connect() as conn:
|
|
||||||
OPT.num_entries = conn.execute( text( num_e_sql ) ).first().count
|
|
||||||
|
|
||||||
if OPT.num_entries == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
last_entry_sql= f"{sel_no_order} order by {OPT.last_order_raw} limit 1"
|
|
||||||
with db.engine.connect() as conn:
|
|
||||||
OPT.last_eid = conn.execute( text( last_entry_sql ) ).first().id
|
|
||||||
# store first/last eid into prefs
|
|
||||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type,PA_UserState.orig_ptype==OPT.orig_ptype,PA_UserState.orig_search_term==OPT.orig_search_term).first()
|
|
||||||
UpdatePref( pref, OPT )
|
|
||||||
return all_entries
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# set up "order strings" to use in ORM and raw queries as needed for
|
|
||||||
# GetEntries*Search*, GetEntries*Flat*, GetEntries*Fold*
|
|
||||||
################################################################################
|
|
||||||
def SetOrderStrings( OPT ):
|
|
||||||
if OPT.noo == "Newest":
|
|
||||||
OPT.order="order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc())"
|
|
||||||
OPT.last_order="order_by(File.year,File.month,File.day,Entry.name)"
|
|
||||||
OPT.last_order_raw=f"f.year, f.month, f.day, e.name"
|
|
||||||
elif OPT.noo == "Oldest":
|
|
||||||
OPT.order="order_by(File.year,File.month,File.day,Entry.name)"
|
|
||||||
OPT.last_order="order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc())"
|
|
||||||
OPT.last_order_raw=f"f.year desc, f.month desc, f.day desc, e.name desc"
|
|
||||||
elif OPT.noo == "Z to A":
|
|
||||||
OPT.order="order_by(Entry.name.desc())"
|
|
||||||
OPT.last_order="order_by(Entry.name)"
|
|
||||||
OPT.last_order_raw=f"e.name"
|
|
||||||
else:
|
|
||||||
# A to Z
|
|
||||||
OPT.order="order_by(Entry.name)"
|
|
||||||
OPT.last_order="order_by(Entry.name.desc())"
|
|
||||||
OPT.last_order_raw=f"e.name desc"
|
|
||||||
return
|
return
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -431,9 +264,6 @@ def process_ids():
|
|||||||
data = request.get_json() # Parse JSON body
|
data = request.get_json() # Parse JSON body
|
||||||
ids = data.get('ids', []) # Extract list of ids
|
ids = data.get('ids', []) # Extract list of ids
|
||||||
|
|
||||||
# DDP: debate here, do I get query_id, do I validate whether we are asking
|
|
||||||
# for ids not in the query? OR, dont even make/store/have query?
|
|
||||||
|
|
||||||
# Query DB for matching entries
|
# Query DB for matching entries
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Entry)
|
select(Entry)
|
||||||
@@ -473,23 +303,63 @@ def get_dir_entries():
|
|||||||
|
|
||||||
# get content of dir_id
|
# get content of dir_id
|
||||||
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||||
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
|
||||||
ids=db.session.execute(stmt).scalars().all()
|
ids=db.session.execute(stmt).scalars().all()
|
||||||
entries_schema = EntrySchema(many=True)
|
entries_schema = EntrySchema(many=True)
|
||||||
entries = Entry.query.filter(Entry.id.in_(ids)).all()
|
entries = Entry.query.filter(Entry.id.in_(ids)).all()
|
||||||
return jsonify(entries_schema.dump(entries))
|
return jsonify(entries_schema.dump(entries))
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Call this ONCE on first menu choice of View files, or search box submission
|
# Get all relevant Entry.ids based on search_term passed in and OPT visuals
|
||||||
# create the list of entry ids that matcht the required viewing/list
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
def GetSearchQueryData(OPT):
|
||||||
|
query_data={}
|
||||||
|
query_data['entry_list']=None
|
||||||
|
query_data['root_eid']=0
|
||||||
|
|
||||||
|
search_term = OPT.search_term
|
||||||
|
# turn * wildcard into sql wildcard of %
|
||||||
|
search_term = search_term.replace('*', '%')
|
||||||
|
if 'AI:' in search_term:
|
||||||
|
search_term = search_term.replace('AI:', '')
|
||||||
|
|
||||||
|
# AI searches are for specific ppl/joins in the DB AND we do them for ALL types of searches, define this once
|
||||||
|
ai_query = (
|
||||||
|
select(Entry.id)
|
||||||
|
.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person)
|
||||||
|
.where(Person.tag == search_term)
|
||||||
|
.order_by(*order_map.get(OPT.noo) )
|
||||||
|
)
|
||||||
|
|
||||||
|
if 'AI:' in search_term:
|
||||||
|
all_entries = db.session.execute(ai_query).scalars().all()
|
||||||
|
else:
|
||||||
|
# match name of File
|
||||||
|
file_query = select(Entry.id).join(File).where(Entry.name.ilike(f'%{search_term}%')).order_by(*order_map.get(OPT.noo))
|
||||||
|
# match name of Dir
|
||||||
|
dir_query = select(Entry.id).join(File).join(EntryDirLink).join(Dir).where(Dir.rel_path.ilike(f'%{search_term}%')).order_by(*order_map.get(OPT.noo))
|
||||||
|
|
||||||
|
# Combine ai, file & dir matches with union() to dedup and then order them
|
||||||
|
combined_query = union( file_query, dir_query, ai_query )
|
||||||
|
all_entries = db.session.execute(combined_query).scalars().all()
|
||||||
|
|
||||||
|
query_data['entry_list']=all_entries
|
||||||
|
return query_data
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################################
|
||||||
|
# Get all relevant Entry.ids based on files_ip/files_sp/files_rbp and OPT visuals
|
||||||
|
#################################################################################
|
||||||
def GetQueryData( OPT ):
|
def GetQueryData( OPT ):
|
||||||
query_data={}
|
query_data={}
|
||||||
query_data['entry_list']=None
|
query_data['entry_list']=None
|
||||||
|
|
||||||
# always get the top of the (OPT.prefix) Path's eid and keep it for OPT.folders toggling/use
|
# always get the top of the (OPT.prefix) Path's eid and keep it for OPT.folders toggling/use
|
||||||
dir_stmt=( select(Entry.id).join(Dir).join(PathDirLink).join(Path).
|
dir_stmt=(
|
||||||
filter(Dir.rel_path == '').filter(Path.path_prefix==OPT.prefix) )
|
select(Entry.id)
|
||||||
|
.join(Dir).join(PathDirLink).join(Path)
|
||||||
|
.where(Dir.rel_path == '').where(Path.path_prefix==OPT.prefix)
|
||||||
|
)
|
||||||
# this should return the 1 Dir (that we want to see the content of) - and with only 1, no need to worry about order
|
# this should return the 1 Dir (that we want to see the content of) - and with only 1, no need to worry about order
|
||||||
dir_arr=db.session.execute(dir_stmt).scalars().all()
|
dir_arr=db.session.execute(dir_stmt).scalars().all()
|
||||||
dir_id=dir_arr[0]
|
dir_id=dir_arr[0]
|
||||||
@@ -501,75 +371,28 @@ def GetQueryData( OPT ):
|
|||||||
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||||
else:
|
else:
|
||||||
# get every File that is in the OPT.prefix Path
|
# get every File that is in the OPT.prefix Path
|
||||||
stmt=( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).
|
stmt=(
|
||||||
filter(Path.path_prefix == OPT.prefix) )
|
select(Entry.id)
|
||||||
|
.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path)
|
||||||
|
.where(Path.path_prefix == OPT.prefix)
|
||||||
|
)
|
||||||
|
|
||||||
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
||||||
query_data['entry_list']=db.session.execute(stmt).scalars().all()
|
query_data['entry_list']=db.session.execute(stmt).scalars().all()
|
||||||
|
|
||||||
return query_data
|
return query_data
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# /GetEntries -> helper function that Gets Entries for required files to show
|
|
||||||
# for several routes (ifles_ip, files_sp, files_rbp, search, view_list)
|
|
||||||
################################################################################
|
|
||||||
def GetEntries( OPT ):
|
|
||||||
entries=[]
|
|
||||||
|
|
||||||
SetOrderStrings( OPT )
|
|
||||||
if OPT.path_type == 'Search' or (OPT.path_type == 'View' and OPT.orig_ptype=='Search'):
|
|
||||||
return GetEntriesInSearchView( OPT )
|
|
||||||
|
|
||||||
# if we are a view, then it will be of something else, e.g. a list of
|
|
||||||
# import, storage, or bin images, reset OPT.path_type so that the paths array below works
|
|
||||||
if 'View' in OPT.path_type:
|
|
||||||
eid = OPT.url[6:]
|
|
||||||
OPT.path_type= OPT.orig_ptype
|
|
||||||
|
|
||||||
paths = []
|
|
||||||
if OPT.path_type == 'Storage':
|
|
||||||
path = SettingsSPath()
|
|
||||||
elif OPT.path_type == 'Import':
|
|
||||||
path = SettingsIPath()
|
|
||||||
elif OPT.path_type == 'Bin':
|
|
||||||
path = SettingsRBPath()
|
|
||||||
|
|
||||||
num_entries=0
|
|
||||||
path_cnt=1
|
|
||||||
|
|
||||||
# if we have not set last_eid yet, then we need to 'reset' it during the
|
|
||||||
# path loop below (if we have more than one dir in (say) Import path)
|
|
||||||
if OPT.last_eid == 0 or OPT.folders:
|
|
||||||
update_last_eid = True
|
|
||||||
else:
|
|
||||||
update_last_eid = False
|
|
||||||
prefix = SymlinkName(OPT.path_type,path,path+'/')
|
|
||||||
if OPT.folders:
|
|
||||||
tmp_ents, tmp_num_ents = GetEntriesInFolderView( OPT, prefix )
|
|
||||||
else:
|
|
||||||
tmp_ents, tmp_num_ents = GetEntriesInFlatView( OPT, prefix )
|
|
||||||
entries += tmp_ents
|
|
||||||
num_entries += tmp_num_ents
|
|
||||||
|
|
||||||
if update_last_eid:
|
|
||||||
# find pref... via path_type if we are here
|
|
||||||
OPT.num_entries=num_entries
|
|
||||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type).first()
|
|
||||||
UpdatePref( pref, OPT )
|
|
||||||
|
|
||||||
return entries
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /change_file_opts -> allow sort order, how_many per page, etc. to change, and
|
# /change_file_opts -> allow sort order, how_many per page, etc. to change, and
|
||||||
# then send back the new query_data to update entryList
|
# then send back the new query_data to update entryList
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/change_file_opts", methods=["POST"])
|
@app.route("/change_file_opts", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def change_file_opts2():
|
def change_file_opts():
|
||||||
data = request.get_json() # Parse JSON body
|
data = request.get_json() # Parse JSON body
|
||||||
# allow dot-notation for OPT
|
# allow dot-notation for OPT
|
||||||
OPT = SimpleNamespace(**data)
|
OPT = SimpleNamespace(**data)
|
||||||
if OPT.folders == 'True':
|
if hasattr(OPT, 'folders') and OPT.folders == 'True':
|
||||||
OPT.folders=True
|
OPT.folders=True
|
||||||
else:
|
else:
|
||||||
OPT.folders=False
|
OPT.folders=False
|
||||||
@@ -581,26 +404,20 @@ def change_file_opts2():
|
|||||||
################################################################################
|
################################################################################
|
||||||
# /file_list -> show detailed file list of files from import_path(s)
|
# /file_list -> show detailed file list of files from import_path(s)
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/file_list_ip", methods=["GET", "POST"])
|
@app.route("/file_list_ip", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def file_list_ip():
|
def file_list_ip():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
query_data = GetQueryData( OPT )
|
||||||
if request.method=='POST':
|
return render_template("file_list.html", page_title='View File Details (Import Path)', query_data=query_data, OPT=OPT )
|
||||||
redirect("/file_list_ip")
|
|
||||||
entries=GetEntries( OPT )
|
|
||||||
return render_template("file_list.html", page_title='View File Details (Import Path)', entry_data=entries, OPT=OPT )
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from import_path(s)
|
# /files -> show thumbnail view of files from import_path(s)
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/files_ip", methods=["GET", "POST"])
|
@app.route("/files_ip", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def files_ip():
|
def files_ip():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
|
||||||
if request.method=='POST':
|
|
||||||
redirect("/files_ip")
|
|
||||||
people = Person.query.all()
|
people = Person.query.all()
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
@@ -609,13 +426,10 @@ def files_ip():
|
|||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from storage_path
|
# /files -> show thumbnail view of files from storage_path
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/files_sp", methods=["GET", "POST"])
|
@app.route("/files_sp", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def files_sp():
|
def files_sp():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
|
||||||
if request.method=='POST':
|
|
||||||
redirect("/files_sp")
|
|
||||||
people = Person.query.all()
|
people = Person.query.all()
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
@@ -625,13 +439,10 @@ def files_sp():
|
|||||||
################################################################################
|
################################################################################
|
||||||
# /files -> show thumbnail view of files from recycle_bin_path
|
# /files -> show thumbnail view of files from recycle_bin_path
|
||||||
################################################################################
|
################################################################################
|
||||||
@app.route("/files_rbp", methods=["GET", "POST"])
|
@app.route("/files_rbp", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
def files_rbp():
|
def files_rbp():
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
# now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe
|
|
||||||
if request.method=='POST':
|
|
||||||
redirect("/files_rbp")
|
|
||||||
people = Person.query.all()
|
people = Person.query.all()
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
query_data = GetQueryData( OPT )
|
query_data = GetQueryData( OPT )
|
||||||
@@ -645,19 +456,13 @@ def files_rbp():
|
|||||||
@app.route("/search/<search_term>", methods=["GET", "POST"])
|
@app.route("/search/<search_term>", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def search(search_term):
|
def search(search_term):
|
||||||
# print( f"req={request}" )
|
|
||||||
OPT=States( request )
|
OPT=States( request )
|
||||||
# print( f"OPT={OPT}" )
|
|
||||||
|
|
||||||
# if we posted to get here, its a change in State, so save it to pa_user_state, and go back to the GET version or URL
|
|
||||||
if request.method=="POST":
|
|
||||||
redirect("/search/"+search_term)
|
|
||||||
OPT.search_term = search_term
|
OPT.search_term = search_term
|
||||||
# always show flat results for search to start with
|
OPT.folders = False
|
||||||
OPT.folders=False
|
|
||||||
entries=GetEntries( OPT )
|
query_data=GetSearchQueryData( OPT )
|
||||||
move_paths = MovePathDetails()
|
move_paths = MovePathDetails()
|
||||||
return render_template("files.html", page_title='View Files', search_term=search_term, entry_data=entries, OPT=OPT, move_paths=move_paths )
|
return render_template("files.html", page_title='View Files', search_term=search_term, query_data=query_data, OPT=OPT, move_paths=move_paths )
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# /files/scan_ip -> allows us to force a check for new files
|
# /files/scan_ip -> allows us to force a check for new files
|
||||||
@@ -786,80 +591,8 @@ def move_files():
|
|||||||
return make_response( jsonify( job_id=job.id ) )
|
return make_response( jsonify( job_id=job.id ) )
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@app.route("/view_list", methods=["POST"])
|
@app.route("/view/", methods=["POST"])
|
||||||
def view_list():
|
def view():
|
||||||
OPT=States( request )
|
|
||||||
# Get next/prev set of data - e.g. if next set, then it will use orig_url
|
|
||||||
# to go forward how_many from offset and then use viewer.html to show that
|
|
||||||
# first obj of the new list of entries
|
|
||||||
entries=GetEntries( OPT )
|
|
||||||
# this occurs when we went from the last image on a page (with how_many on
|
|
||||||
# it) and it just happened to also be the last in the DB...
|
|
||||||
if not entries:
|
|
||||||
SetFELog( message="DDP: DONT think this can happen anymore", level="danger", job=None, persistent=True, cant_close=True )
|
|
||||||
|
|
||||||
# undo the skip by how_many and getentries again
|
|
||||||
OPT.offset -= int(OPT.how_many)
|
|
||||||
entries=GetEntries( OPT )
|
|
||||||
# now flag we are at the last in db, to reset current below
|
|
||||||
objs = {}
|
|
||||||
eids=""
|
|
||||||
resp={}
|
|
||||||
resp['objs']={}
|
|
||||||
for e in entries:
|
|
||||||
if not e.file_details:
|
|
||||||
continue
|
|
||||||
eids=eids+f"{e.id},"
|
|
||||||
resp['objs'][e.id]={}
|
|
||||||
resp['objs'][e.id]['url'] = e.FullPathOnFS()
|
|
||||||
resp['objs'][e.id]['name'] = e.name
|
|
||||||
resp['objs'][e.id]['type'] = e.type.name
|
|
||||||
if e.file_details.faces:
|
|
||||||
# model is used for whole file, so set it at that level (based on first face)
|
|
||||||
resp['objs'][e.id]['face_model'] = e.file_details.faces[0].facefile_lnk.model_used
|
|
||||||
resp['objs'][e.id]['faces'] = []
|
|
||||||
|
|
||||||
# put face data back into array format (for js processing)
|
|
||||||
for face in e.file_details.faces:
|
|
||||||
fd= {}
|
|
||||||
fd['x'] = face.face_left
|
|
||||||
fd['y'] = face.face_top
|
|
||||||
fd['w'] = face.w
|
|
||||||
fd['h'] = face.h
|
|
||||||
if face.refimg:
|
|
||||||
fd['pid'] = face.refimg.person.id
|
|
||||||
fd['who'] = face.refimg.person.tag
|
|
||||||
fd['distance'] = round(face.refimg_lnk.face_distance,2)
|
|
||||||
resp['objs'][e.id]['faces'].append(fd)
|
|
||||||
|
|
||||||
eids=eids.rstrip(",")
|
|
||||||
lst = eids.split(',')
|
|
||||||
if 'next' in request.form:
|
|
||||||
OPT.current = int(lst[0])
|
|
||||||
if 'prev' in request.form:
|
|
||||||
OPT.current = int(lst[-1])
|
|
||||||
|
|
||||||
resp['current']=OPT.current
|
|
||||||
# OPT.first_eid can still be 0 IF we have gone past the first page, I could
|
|
||||||
# better set this in states rather than kludge this if... think about it
|
|
||||||
if OPT.first_eid>0:
|
|
||||||
resp['first_eid']=OPT.first_eid
|
|
||||||
resp['last_eid']=OPT.last_eid
|
|
||||||
resp['eids']=eids
|
|
||||||
resp['offset']=OPT.offset
|
|
||||||
# print( f"BUG-DEBUG: /view_list route #1 - OPT={OPT}, eids={eids} ")
|
|
||||||
# save pref to keep the new current value, first/last
|
|
||||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.orig_ptype==OPT.orig_ptype,PA_UserState.view_eid==OPT.view_eid).first()
|
|
||||||
# print( f"BUG-DEBUG: /view_list route #2 - OPT={OPT}, eids={eids} ")
|
|
||||||
UpdatePref( pref, OPT )
|
|
||||||
# print( f"BUG-DEBUG: /view_list route #3 - OPT={OPT}, eids={eids} ")
|
|
||||||
|
|
||||||
return make_response( resp )
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@app.route("/newview/", methods=["POST"])
|
|
||||||
def newview():
|
|
||||||
data = request.get_json() # Parse JSON body
|
data = request.get_json() # Parse JSON body
|
||||||
eid = data.get('eid', 0) # Extract list of ids
|
eid = data.get('eid', 0) # Extract list of ids
|
||||||
|
|
||||||
@@ -882,22 +615,9 @@ def newview():
|
|||||||
data=db.session.execute(stmt).unique().scalars().all()
|
data=db.session.execute(stmt).unique().scalars().all()
|
||||||
return jsonify(entries_schema.dump(data))
|
return jsonify(entries_schema.dump(data))
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# /view/id -> grabs data from DB and views it (GET)
|
####
|
||||||
################################################################################
|
"""
|
||||||
@login_required
|
|
||||||
@app.route("/view/<id>", methods=["GET"])
|
|
||||||
def view(id):
|
|
||||||
OPT=States( request )
|
|
||||||
objs = {}
|
|
||||||
entries=GetEntries( OPT )
|
|
||||||
eids=""
|
|
||||||
for e in entries:
|
|
||||||
objs[e.id]=e
|
|
||||||
eids += f"{e.id},"
|
|
||||||
# if this is a dir, we wont view it with a click anyway, so move on...
|
|
||||||
if not e.file_details:
|
|
||||||
continue
|
|
||||||
# process any overrides
|
# process any overrides
|
||||||
for face in e.file_details.faces:
|
for face in e.file_details.faces:
|
||||||
# now get any relevant override and store it in objs...
|
# now get any relevant override and store it in objs...
|
||||||
@@ -909,20 +629,6 @@ def view(id):
|
|||||||
mo.type = FaceOverrideType.query.filter( FaceOverrideType.name== 'Manual match to existing person' ).first()
|
mo.type = FaceOverrideType.query.filter( FaceOverrideType.name== 'Manual match to existing person' ).first()
|
||||||
face.manual_override=mo
|
face.manual_override=mo
|
||||||
|
|
||||||
eids=eids.rstrip(",")
|
|
||||||
# jic, sometimes we trip this, and rather than show broken pages / destroy
|
|
||||||
if id not in eids:
|
|
||||||
# SetFELog( message=f"ERROR: viewing an id, but its not in eids OPT={OPT}, id={id}, eids={eids}", level="danger", persistent=True, cant_close=False)
|
|
||||||
# msg="Sorry, viewing data is confused, cannot view this image now"
|
|
||||||
# if os.environ['ENV'] == "production":
|
|
||||||
# msg += "Clearing out all states. This means browser back buttons will not work, please start a new tab and try again"
|
|
||||||
# PA_UserState.query.delete()
|
|
||||||
# db.session.commit()
|
|
||||||
# SetFELog( msg, "warning", persistent=True, cant_close=False )
|
|
||||||
# return redirect("/")
|
|
||||||
print( f"id={id}, eids={eids}" )
|
|
||||||
return "200"
|
|
||||||
else:
|
|
||||||
NMO_data = FaceOverrideType.query.all()
|
NMO_data = FaceOverrideType.query.all()
|
||||||
setting = Settings.query.first()
|
setting = Settings.query.first()
|
||||||
imp_path = setting.import_path
|
imp_path = setting.import_path
|
||||||
@@ -930,18 +636,7 @@ def view(id):
|
|||||||
bin_path = setting.recycle_bin_path
|
bin_path = setting.recycle_bin_path
|
||||||
# print( f"BUG-DEBUG: /view/id GET route - OPT={OPT}, eids={eids}, current={int(id)} ")
|
# print( f"BUG-DEBUG: /view/id GET route - OPT={OPT}, eids={eids}, current={int(id)} ")
|
||||||
return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT, NMO_data=NMO_data, imp_path=imp_path, st_path=st_path, bin_path=bin_path )
|
return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT, NMO_data=NMO_data, imp_path=imp_path, st_path=st_path, bin_path=bin_path )
|
||||||
|
"""
|
||||||
##################################################################################
|
|
||||||
# /view/id -> grabs data from DB and views it (POST -> set state, redirect to GET)
|
|
||||||
##################################################################################
|
|
||||||
@app.route("/view/<id>", methods=["POST"])
|
|
||||||
@login_required
|
|
||||||
def view_img_post(id):
|
|
||||||
# set pa_user_states...
|
|
||||||
OPT=States( request )
|
|
||||||
# print( f"BUG-DEBUG: /view/id POST route - OPT={OPT}, id={id} ")
|
|
||||||
# then use back-button friendly URL (and use pa_user_states to view the right image in the right list
|
|
||||||
return redirect( "/view/" + id );
|
|
||||||
|
|
||||||
# route called from front/end - if multiple images are being transformed, each transorm == a separate call
|
# route called from front/end - if multiple images are being transformed, each transorm == a separate call
|
||||||
# to this route (and therefore a separate transorm job. Each reponse allows the f/e to check the
|
# to this route (and therefore a separate transorm job. Each reponse allows the f/e to check the
|
||||||
@@ -1006,14 +701,6 @@ def _jinja2_filter_toplevelfolderof(path, cwd):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# This func creates a new filter in jinja2 to test to hand back the parent path
|
|
||||||
# from a given path
|
|
||||||
################################################################################
|
|
||||||
@app.template_filter('ParentPath')
|
|
||||||
def _jinja2_filter_parentpath(path):
|
|
||||||
return os.path.dirname(path)
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# route to allow the Move Dialog Box to pass a date (YYYYMMDD) and returns a
|
# route to allow the Move Dialog Box to pass a date (YYYYMMDD) and returns a
|
||||||
# json list of existing dir names that could be near it in time. Starting
|
# json list of existing dir names that could be near it in time. Starting
|
||||||
|
|||||||
@@ -351,11 +351,6 @@ function addFigure( obj, last, ecnt)
|
|||||||
last.printed = obj.file_details.month;
|
last.printed = obj.file_details.month;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
{% if not entry_data %}
|
|
||||||
<span class="alert alert-danger p-2 col-auto"> No matches for: '{{search_term}}'</span>
|
|
||||||
{% endif %}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 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") {
|
||||||
@@ -466,9 +461,9 @@ function getDirEntries(dir_id, back)
|
|||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: '/get_dir_entries',
|
url: '/get_dir_entries',
|
||||||
data: JSON.stringify(data), // Stringify the data
|
data: JSON.stringify(data),
|
||||||
contentType: 'application/json', // Set content type
|
contentType: 'application/json',
|
||||||
dataType: 'json', // Expect JSON response
|
dataType: 'json',
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
document.entries=res
|
document.entries=res
|
||||||
// rebuild entryList/pageList as each dir comes with new entries
|
// rebuild entryList/pageList as each dir comes with new entries
|
||||||
@@ -525,6 +520,8 @@ function drawPageOfFigures()
|
|||||||
addFigure( obj, last, ecnt )
|
addFigure( obj, last, ecnt )
|
||||||
ecnt++
|
ecnt++
|
||||||
}
|
}
|
||||||
|
if( document.entries.length == 0 && OPT.search_term != '' )
|
||||||
|
$('#figures').append( `<span class="alert alert-danger p-2 col-auto"> No matches for: '${OPT.search_term}'</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') ) } )
|
$('.figure').dblclick( function(e) { dblClickToViewEntry( $(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)
|
||||||
@@ -532,8 +529,47 @@ function drawPageOfFigures()
|
|||||||
$(".back").click( function(e) { getDirEntries(this.id,true) } )
|
$(".back").click( function(e) { getDirEntries(this.id,true) } )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPageFileList(res, viewingIdx)
|
||||||
|
{
|
||||||
|
$('#file_list_div').empty()
|
||||||
|
html='<table class="table table-striped table-sm col-12">'
|
||||||
|
html+='<thead><tr class="table-primary"><th>Name</th><th>Size (MB)</th><th>Path Prefix</th><th>Hash</th></tr></thead><tbody>'
|
||||||
|
for (const obj of res) {
|
||||||
|
html+=`<tr>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<a href="${obj.in_dir.in_path.path_prefix}/${obj.in_dir.rel_path}/${obj.name}">
|
||||||
|
<img class="img-fluid me-2" style="max-width: 100px;"
|
||||||
|
src="data:image/jpeg;base64,${obj.file_details.thumbnail}"></img>
|
||||||
|
</a>
|
||||||
|
<span>${obj.name}</span>
|
||||||
|
</div>
|
||||||
|
<td>${obj.file_details.size_mb}</td>
|
||||||
|
<td>${obj.in_dir.in_path.path_prefix.replace("static/","")}/${obj.in_dir.rel_path}</td>
|
||||||
|
<td>${obj.file_details.hash}</td>
|
||||||
|
</tr>`
|
||||||
|
}
|
||||||
|
html+='</tbody></table>'
|
||||||
|
$('#file_list_div').append(html)
|
||||||
|
}
|
||||||
|
|
||||||
|
// function called when we get another page from inside the files view
|
||||||
|
function getPageFigures(res, viewingIdx)
|
||||||
|
{
|
||||||
|
// add all the figures to files_div
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
// Function to get the 'page' of entry ids out of entryList
|
// Function to get the 'page' of entry ids out of entryList
|
||||||
function getPage(pageNumber,viewing_idx=0)
|
function getPage(pageNumber, successCallback, viewingIdx=0)
|
||||||
{
|
{
|
||||||
// before we do anything, disabled left/right arrows on viewer to stop
|
// before we do anything, disabled left/right arrows on viewer to stop
|
||||||
// getting another event before we have the data for the page back
|
// getting another event before we have the data for the page back
|
||||||
@@ -546,29 +582,14 @@ function getPage(pageNumber,viewing_idx=0)
|
|||||||
// set up data to send to server to get the entry data for entries in pageList
|
// set up data to send to server to get the entry data for entries in pageList
|
||||||
data={}
|
data={}
|
||||||
data.ids = pageList
|
data.ids = pageList
|
||||||
data.query = 99999
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'POST',
|
type: 'POST', url: '/get_entries_by_ids',
|
||||||
url: '/get_entries_by_ids',
|
data: JSON.stringify(data), contentType: 'application/json',
|
||||||
data: JSON.stringify(data), // Stringify the data
|
dataType: 'json',
|
||||||
contentType: 'application/json', // Set content type
|
success: function(res) { document.entries=res; successCallback(res,viewingIdx); },
|
||||||
dataType: 'json', // Expect JSON response
|
error: function(xhr, status, error) { console.error("Error:", error); } });
|
||||||
success: function(res) {
|
|
||||||
document.entries=res
|
|
||||||
// add all the figures to files_div
|
|
||||||
drawPageOfFigures()
|
|
||||||
// noting we could have been in files_div, or viewer_div, update both jic
|
|
||||||
// and fix viewer_div - update viewing, arrows and image/video too
|
|
||||||
document.viewing=document.entries[viewing_idx]
|
|
||||||
resetNextPrevButtons()
|
resetNextPrevButtons()
|
||||||
ViewImageOrVideo()
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
console.error("Error:", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +632,7 @@ function resetNextPrevButtons()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get list of eids for the next page, also make sure next/prev buttons make sense for page we are on
|
// get list of eids for the next page, also make sure next/prev buttons make sense for page we are on
|
||||||
function nextPage()
|
function nextPage(successCallback)
|
||||||
{
|
{
|
||||||
// pageList[0] is the first entry on this page
|
// pageList[0] is the first entry on this page
|
||||||
const currentPage=getPageNumberForId( pageList[0] )
|
const currentPage=getPageNumberForId( pageList[0] )
|
||||||
@@ -621,13 +642,12 @@ function nextPage()
|
|||||||
console.error( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.how_many + " gives currentPage=" + currentPage + " and we cant go next page?" )
|
console.error( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.how_many + " gives currentPage=" + currentPage + " and we cant go next page?" )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
getPage( currentPage+1 )
|
getPage( currentPage+1, successCallback )
|
||||||
resetNextPrevButtons()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// get list of eids for the prev page, also make sure next/prev buttons make sense for page we are on
|
// get list of eids for the prev page, also make sure next/prev buttons make sense for page we are on
|
||||||
function prevPage()
|
function prevPage(successCallback)
|
||||||
{
|
{
|
||||||
// pageList[0] is the first entry on this page
|
// pageList[0] is the first entry on this page
|
||||||
const currentPage=getPageNumberForId( pageList[0] )
|
const currentPage=getPageNumberForId( pageList[0] )
|
||||||
@@ -637,8 +657,7 @@ function prevPage()
|
|||||||
console.error( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.how_many + " gives currentPage=" + currentPage + " and we cant go prev page?" )
|
console.error( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.how_many + " gives currentPage=" + currentPage + " and we cant go prev page?" )
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
getPage( currentPage-1 )
|
getPage( currentPage-1, successCallback )
|
||||||
resetNextPrevButtons()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,3 +665,45 @@ function isMobile() {
|
|||||||
try{ document.createEvent("TouchEvent"); return true; }
|
try{ document.createEvent("TouchEvent"); return true; }
|
||||||
catch(e){ return false; }
|
catch(e){ return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function changeOPT(successCallback) {
|
||||||
|
OPT.how_many=$('#how_many').val()
|
||||||
|
new_f=$('#folders').val()
|
||||||
|
new_f=( new_f == 'True' )
|
||||||
|
// if change to/from folders, also fix the noo menu
|
||||||
|
if( new_f != OPT.folders )
|
||||||
|
{
|
||||||
|
if( new_f )
|
||||||
|
{
|
||||||
|
$('#noo option:lt(2)').prop('disabled', true);
|
||||||
|
$('#noo').val(OPT.default_folder_noo)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#noo option:lt(2)').prop('disabled', false);
|
||||||
|
$('#noo').val(OPT.default_flat_noo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OPT.noo=$('#noo').val()
|
||||||
|
OPT.folders=new_f
|
||||||
|
OPT.folders=$('#folders').val()
|
||||||
|
OPT.grouping=$('#grouping').val()
|
||||||
|
OPT.size=$('#size').val()
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: '/change_file_opts',
|
||||||
|
data: JSON.stringify(OPT),
|
||||||
|
contentType: 'application/json',
|
||||||
|
success: function(resp) {
|
||||||
|
entryList=resp.query_data.entry_list
|
||||||
|
// put data back into booleans, ints, etc
|
||||||
|
OPT.folders=( OPT.folders == 'True' )
|
||||||
|
OPT.how_many=parseInt(OPT.how_many)
|
||||||
|
$('.how_many_text').html( ` ${OPT.how_many} files ` )
|
||||||
|
OPT.root_eid=parseInt(OPT.root_eid)
|
||||||
|
OPT.size=parseInt(OPT.size)
|
||||||
|
getPage(1,successCallback)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,64 +1,49 @@
|
|||||||
{% extends "base.html" %} {% block main_content %}
|
{% extends "base.html" %} {% block main_content %}
|
||||||
|
<script src="{{ url_for( 'internal', filename='js/files_support.js')}}"></script>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<h3 class="offset-2">{{page_title}}</h3>
|
<h3 class="offset-2">{{page_title}}</h3>
|
||||||
<form id="main_form" method="POST">
|
|
||||||
<input id="offset" type="hidden" name="offset" value="{{OPT.offset}}">
|
|
||||||
<input id="grouping" type="hidden" name="grouping" value="">
|
|
||||||
<input id="folders" type="hidden" name="folders" value="False">
|
|
||||||
<div class="col col-auto">
|
<div class="col col-auto">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "$('#offset').val(0)", "rounded-start py-1 my-1")|safe }}
|
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "changeOPT(getPageFileList); return false", "rounded-start py-1 my-1")|safe }}
|
||||||
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"], "", "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">
|
||||||
{% set prv_disabled="" %}
|
<button id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary" onClick="prevPage(getPageFileList)">
|
||||||
{% if OPT.offset|int == 0 %}
|
|
||||||
{% set prv_disabled="disabled" %}
|
|
||||||
{% endif %}
|
|
||||||
<button id="prev" {{prv_disabled}} name="prev" class="prev sm-txt btn btn-outline-secondary">
|
|
||||||
<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')}}#prev"/></svg>
|
||||||
</button>
|
</button>
|
||||||
<span class="sm-txt my-auto"> {{OPT.how_many}} files </span>
|
<span class="how_many_text sm-txt my-auto"> {{OPT.how_many}} files </span>
|
||||||
{% set nxt_disabled="" %}
|
<button id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage(getPageFileList)">
|
||||||
{% if entry_data|length < OPT.how_many|int %}
|
|
||||||
{% set nxt_disabled="disabled" %}
|
|
||||||
{% endif %}
|
|
||||||
<button id="next" {{nxt_disabled}} name="next" class="next sm-txt btn btn-outline-secondary">
|
|
||||||
<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')}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div class="col...">
|
</div class="col...">
|
||||||
</div class="input-group...">
|
</div class="input-group...">
|
||||||
</div class="col col-auto">
|
</div class="col col-auto">
|
||||||
</form
|
|
||||||
<div class="row">
|
|
||||||
<table class="table table-striped table-sm col-xl-12">
|
|
||||||
<thead><tr class="table-primary"><th>Name</th><th>Size (MB)</th><th>Path Prefix</th><th>Hash</th></tr></thead><tbody>
|
|
||||||
{% for obj in entry_data %}
|
|
||||||
<tr><td>
|
|
||||||
{% if obj.type.name == "Image" or obj.type.name == "Video" %}
|
|
||||||
<figure class="figure" font-size: 24px;>
|
|
||||||
<div style="position:relative; width:100%">
|
|
||||||
{% if obj.type.name=="Image" %}
|
|
||||||
<a href="{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}">
|
|
||||||
{% elif obj.type.name == "Video" %}
|
|
||||||
<a href="{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}">
|
|
||||||
{% endif %}
|
|
||||||
<img class="thumb" style="display:block" height="48" src="data:image/jpeg;base64,{{obj.file_details.thumbnail}}"></img>
|
|
||||||
{% if obj.type.name=="Image" or obj.type.name == "Video" %}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<figcaption class="figure-caption">{{obj.name}}</figcaption>
|
|
||||||
</figure>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% if obj.type.name != "Directory" %}
|
|
||||||
<td>{{obj.file_details.size_mb}}</td><td>{{obj.in_dir.in_path.path_prefix.replace("static/","")}}/{{obj.in_dir.rel_path}}</td><td>{{obj.file_details.hash}}</td>
|
|
||||||
{% else %}
|
|
||||||
<td></td><td></td><td></td>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody></table>
|
|
||||||
</div class="row">
|
|
||||||
</div class="container">
|
</div class="container">
|
||||||
|
<div id="file_list_div" class="container-fluid">
|
||||||
|
</div class="container">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
|
||||||
|
<div class="row">
|
||||||
|
<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>
|
||||||
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
|
||||||
|
</button>
|
||||||
|
<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)">
|
||||||
|
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
|
||||||
|
</button>
|
||||||
|
</div class="col my-auto"> </div class="row">
|
||||||
|
</div class="container-fluid">
|
||||||
{% endblock main_content %}
|
{% endblock main_content %}
|
||||||
|
{% block script_content %}
|
||||||
|
<script>
|
||||||
|
// this is the list of entry ids for the images for ALL matches for this query
|
||||||
|
var entryList={{query_data.entry_list}}
|
||||||
|
var OPT = {{ OPT.to_dict()|tojson }};
|
||||||
|
|
||||||
|
// pageList is just those entries shown on this page from the full entryList
|
||||||
|
var pageList=[]
|
||||||
|
// force pageList to set pageList for & render the first page
|
||||||
|
getPage( 1, getPageFileList )
|
||||||
|
</script>
|
||||||
|
{% endblock script_content %}
|
||||||
|
|||||||
@@ -23,19 +23,8 @@
|
|||||||
document.viewing_eid=null;
|
document.viewing_eid=null;
|
||||||
document.viewing=null;
|
document.viewing=null;
|
||||||
|
|
||||||
var OPT={}
|
var OPT = {{ OPT.to_dict()|tojson }};
|
||||||
OPT.noo='{{OPT.noo}}'
|
OPT.root_eid = {{ query_data.root_eid }};
|
||||||
OPT.how_many={{OPT.how_many}}
|
|
||||||
OPT.folders="{{OPT.folders}}" === "True"
|
|
||||||
OPT.grouping='{{OPT.grouping}}'
|
|
||||||
OPT.cwd='{{OPT.cwd}}'
|
|
||||||
OPT.root_eid={{query_data.root_eid}}
|
|
||||||
OPT.search_term='{{OPT.orig_search_term}}'
|
|
||||||
OPT.size={{OPT.size}}
|
|
||||||
OPT.prefix='{{OPT.prefix}}'
|
|
||||||
OPT.default_flat_noo='{{OPT.default_flat_noo}}'
|
|
||||||
OPT.default_folder_noo='{{OPT.default_folder_noo}}'
|
|
||||||
OPT.default_search_noo='{{OPT.default_search_noo}}'
|
|
||||||
|
|
||||||
// this is the list of entry ids for the images for ALL matches for this query
|
// this is the list of entry ids for the images for ALL matches for this query
|
||||||
var entryList={{query_data.entry_list}}
|
var entryList={{query_data.entry_list}}
|
||||||
@@ -43,57 +32,17 @@
|
|||||||
// pageList is just those entries shown on this page from the full entryList
|
// pageList is just those entries shown on this page from the full entryList
|
||||||
var pageList=[]
|
var pageList=[]
|
||||||
// force pageList to set pageList for & render the first page
|
// force pageList to set pageList for & render the first page
|
||||||
getPage(1)
|
getPage(1,getPageFigures)
|
||||||
|
|
||||||
function cFO() {
|
function changeSize()
|
||||||
OPT.how_many=$('#how_many').val()
|
|
||||||
new_f=$('#folders').val()
|
|
||||||
new_f=( new_f == 'True' )
|
|
||||||
// if change to/from folders, also fix the noo menu
|
|
||||||
if( new_f != OPT.folders )
|
|
||||||
{
|
{
|
||||||
if( new_f )
|
sz=$('input[name="size"]:checked').val();
|
||||||
{
|
$('.thumb').prop('height',sz);
|
||||||
$('#noo option:lt(2)').prop('disabled', true);
|
|
||||||
$('#noo').val(OPT.default_folder_noo)
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
$('#noo option:lt(2)').prop('disabled', false);
|
|
||||||
$('#noo').val(OPT.default_flat_noo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OPT.noo=$('#noo').val()
|
|
||||||
OPT.folders=new_f
|
|
||||||
OPT.folders=$('#folders').val()
|
|
||||||
OPT.grouping=$('#grouping').val()
|
|
||||||
OPT.size=$('#size').val()
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: '/change_file_opts',
|
|
||||||
data: JSON.stringify(OPT),
|
|
||||||
contentType: 'application/json',
|
|
||||||
success: function(resp) {
|
|
||||||
entryList=resp.query_data.entry_list
|
|
||||||
// put data back into booleans, ints, etc
|
|
||||||
OPT.folders=( OPT.folders == 'True' )
|
|
||||||
OPT.how_many=parseInt(OPT.how_many)
|
|
||||||
$('.how_many_text').html( ` ${OPT.how_many} files ` )
|
|
||||||
OPT.root_eid=parseInt(OPT.root_eid)
|
|
||||||
OPT.size=parseInt(OPT.size)
|
|
||||||
getPage(1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="files_div">
|
<div id="files_div">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
|
|
||||||
{% if search_term is defined %}
|
|
||||||
<input type="hidden" name="search_term" id="view_term" value="{{search_term}}">
|
|
||||||
{% endif %}
|
|
||||||
<div class="d-flex row mb-2">
|
<div class="d-flex row mb-2">
|
||||||
{% if OPT.folders %}
|
{% if OPT.folders %}
|
||||||
<div class="my-auto col col-auto">
|
<div class="my-auto col col-auto">
|
||||||
@@ -113,13 +62,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="col col-auto">
|
<div class="col col-auto">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "cFO(); return false", "rounded-start py-2")|safe }}
|
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "changeOPT(getPageFigures); return false", "rounded-start py-2")|safe }}
|
||||||
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"], "cFO(); return false" )|safe }}
|
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"], "changeOPT(getPageFigures); return false" )|safe }}
|
||||||
{% if OPT.folders %}
|
{% if OPT.folders %}
|
||||||
<input type="hidden" name="grouping" id="grouping" value="{{OPT.grouping}}">
|
{{CreateFoldersSelect( OPT.folders, "changeOPT(getPageFigures); return false", "rounded-end" )|safe }}
|
||||||
{{CreateFoldersSelect( OPT.folders, "cFO(); return false", "rounded-end" )|safe }}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{{CreateFoldersSelect( OPT.folders, "cFO(); return false" )|safe }}
|
{{CreateFoldersSelect( OPT.folders, "changeOPT(getPageFigures); return false" )|safe }}
|
||||||
<span class="sm-txt my-auto btn btn-outline-info disabled border-top border-bottom">grouped by:</span>
|
<span class="sm-txt my-auto btn btn-outline-info disabled border-top border-bottom">grouped by:</span>
|
||||||
{{CreateSelect( "grouping", OPT.grouping, ["None", "Day", "Week", "Month"], "OPT.grouping=$('#grouping').val();drawPageOfFigures();return false", "rounded-end")|safe }}
|
{{CreateSelect( "grouping", OPT.grouping, ["None", "Day", "Week", "Month"], "OPT.grouping=$('#grouping').val();drawPageOfFigures();return false", "rounded-end")|safe }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -134,11 +82,11 @@
|
|||||||
</script>
|
</script>
|
||||||
{% 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()" 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')}}#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()">
|
<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')}}#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,'{{url_for('internal', filename='icons.svg')}}'); return false;">
|
<button aria-label="move" id="move" disabled name="move" class="sm-txt btn btn-outline-primary ms-4" onClick="MoveDBox(move_paths,'{{url_for('internal', filename='icons.svg')}}'); return false;">
|
||||||
@@ -156,60 +104,35 @@
|
|||||||
<button style="visibility:hidden" class="btn btn-outline-secondary" aria-label="ctrl-key" id="ctrl-key" onclick="document.fake_ctrl=1-document.fake_ctrl; event.stopPropagation(); return false">ctrl</button>
|
<button style="visibility:hidden" class="btn btn-outline-secondary" aria-label="ctrl-key" id="ctrl-key" onclick="document.fake_ctrl=1-document.fake_ctrl; event.stopPropagation(); return false">ctrl</button>
|
||||||
</div class="col flex-grow-1">
|
</div class="col flex-grow-1">
|
||||||
<div class="d-flex col col-auto justify-content-end">
|
<div class="d-flex col col-auto justify-content-end">
|
||||||
<div class="btn-group">
|
<div class="btn-group" role="group" aria-label="Size radio button group">
|
||||||
{% if OPT.size == 64 %}
|
<input type="radio" class="btn-check" name="size" id="size-xs" onCLick="changeSize()" autocomplete="off" value="64">
|
||||||
{% set bt="btn-info text-white" %}
|
<label class="btn btn-outline-info btn-radio" for="size-xs">XS</label>
|
||||||
{% else %}
|
|
||||||
{% set bt="btn-outline-info" %}
|
<input type="radio" class="btn-check" name="size" id="size-s" onCLick="changeSize()" autocomplete="off" value="96">
|
||||||
{% endif %}
|
<label class="btn btn-outline-info btn-radio" for="size-s">S</label>
|
||||||
<button aria-label="extra small" id="64" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(64)">XS</button>
|
|
||||||
{% if OPT.size == 96 %}
|
<input type="radio" class="btn-check" name="size" id="size-m" onCLick="changeSize()" autocomplete="off" value="128">
|
||||||
{% set bt="btn-info text-white" %}
|
<label class="btn btn-outline-info btn-radio" for="size-m">M</label>
|
||||||
{% else %}
|
|
||||||
{% set bt="btn-outline-info" %}
|
<input type="radio" class="btn-check" name="size" id="size-l" onCLick="changeSize()" autocomplete="off" value="192">
|
||||||
{% endif %}
|
<label class="btn btn-outline-info btn-radio" for="size-l">L</label>
|
||||||
<button aria-label="small" id="96" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(96)">S</button>
|
|
||||||
{% if OPT.size == 128 %}
|
<input type="radio" class="btn-check" name="size" id="size-xl" onCLick="changeSize()" autocomplete="off" value="256">
|
||||||
{% set bt="btn-info text-white" %}
|
<label class="btn btn-outline-info btn-radio" for="size-xl">XL</label>
|
||||||
{% else %}
|
</div>
|
||||||
{% set bt="btn-outline-info" %}
|
|
||||||
{% endif %}
|
|
||||||
<button aria-label="medium" id="128" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(128)">M</button>
|
|
||||||
{% if OPT.size == 192 %}
|
|
||||||
{% set bt="btn-info text-white" %}
|
|
||||||
{% else %}
|
|
||||||
{% set bt="btn-outline-info" %}
|
|
||||||
{% endif %}
|
|
||||||
<button aria-label="large" id="192" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(192)">L</button>
|
|
||||||
{% if OPT.size == 256 %}
|
|
||||||
{% set bt="btn-info text-white" %}
|
|
||||||
{% else %}
|
|
||||||
{% set bt="btn-outline-info" %}
|
|
||||||
{% endif %}
|
|
||||||
<button aria-label="extra large" id="256" class="px-2 sm-txt sz-but btn {{bt}}" onClick="$('#size').val(256)">XL</button>
|
|
||||||
</div class="btn-group">
|
|
||||||
</div class="d-flex col">
|
</div class="d-flex col">
|
||||||
<input id="offset" type="hidden" name="offset" value="{{OPT.offset}}">
|
|
||||||
<input id="size" type="hidden" name="size" value="{{OPT.size}}">
|
|
||||||
</div class="d-flex row mb-2">
|
</div class="d-flex row mb-2">
|
||||||
{% set eids=namespace( str="" ) %}
|
|
||||||
{# gather all the file eids and collect them in case we go gallery mode #}
|
|
||||||
{% for obj in query_data.entry_list %}
|
|
||||||
{% set eids.str = eids.str + obj|string +"," %}
|
|
||||||
{% endfor %}
|
|
||||||
<input name="eids" id="eids" type="hidden" value="{{eids.str}}">
|
|
||||||
</div container="fluid">
|
</div container="fluid">
|
||||||
<div id="figures" class="row ms-2">
|
<div id="figures" class="row ms-2">
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
|
|
||||||
<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()" 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')}}#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()">
|
<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')}}#next"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div class="col my-auto">
|
</div class="col my-auto">
|
||||||
@@ -219,6 +142,8 @@
|
|||||||
<div id="viewer_div" class="d-none">
|
<div id="viewer_div" class="d-none">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
|
||||||
.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;
|
||||||
@@ -280,7 +205,7 @@
|
|||||||
// pref page, load it
|
// pref page, load it
|
||||||
if( oldPageOffset != pageOffset )
|
if( oldPageOffset != pageOffset )
|
||||||
// pref page is pageOffset+1 now
|
// pref page is pageOffset+1 now
|
||||||
getPage(pageOffset+1,currentIndex)
|
getPage(pageOffset+1,getPageViewer,currentIndex)
|
||||||
else
|
else
|
||||||
document.viewing=document.entries[currentIndex]
|
document.viewing=document.entries[currentIndex]
|
||||||
}
|
}
|
||||||
@@ -297,7 +222,7 @@
|
|||||||
// next page, load it
|
// next page, load it
|
||||||
if( oldPageOffset != pageOffset )
|
if( oldPageOffset != pageOffset )
|
||||||
// next page is pageOffset+1 now
|
// next page is pageOffset+1 now
|
||||||
getPage(pageOffset+1,currentIndex)
|
getPage(pageOffset+1,getPageViewer,currentIndex)
|
||||||
else
|
else
|
||||||
document.viewing=document.entries[currentIndex]
|
document.viewing=document.entries[currentIndex]
|
||||||
}
|
}
|
||||||
@@ -434,7 +359,9 @@
|
|||||||
</div class="row">
|
</div class="row">
|
||||||
</div id="viewer">
|
</div id="viewer">
|
||||||
</div id="viewer_div">
|
</div id="viewer_div">
|
||||||
|
{% endblock main_content %}
|
||||||
|
|
||||||
|
{% block script_content %}
|
||||||
<script>
|
<script>
|
||||||
$( document ).keydown(function(event) {
|
$( document ).keydown(function(event) {
|
||||||
// if dbox is visible, dont process this hot-key, we are inputting text
|
// if dbox is visible, dont process this hot-key, we are inputting text
|
||||||
@@ -477,12 +404,6 @@ $( document ).keydown(function(event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var fullscreen=false;
|
var fullscreen=false;
|
||||||
</script>
|
|
||||||
|
|
||||||
{% endblock main_content %}
|
|
||||||
{% block script_content %}
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
$(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() });
|
$(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() });
|
||||||
|
|
||||||
@@ -593,5 +514,7 @@ if( isMobile() )
|
|||||||
$('#ctrl-key').css('visibility', 'visible');
|
$('#ctrl-key').css('visibility', 'visible');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check the size radiobutton
|
||||||
|
$(`input[name="size"][value="${OPT.size}"]`).prop('checked', true)
|
||||||
</script>
|
</script>
|
||||||
{% endblock script_content %}
|
{% endblock script_content %}
|
||||||
|
|||||||
Reference in New Issue
Block a user