Compare commits

...

5 Commits

6 changed files with 144 additions and 354 deletions

24
TODO
View File

@@ -1,20 +1,8 @@
###
# get search to work
###
### major fix - go to everywhere I call GetEntries(), and redo the logic totally...
* firstly, run the query as per normal, but get just the matched eids into an entry_lst
* make a unique query_id for this entry_lst, and store entry_ids into "query" table, with a unique query_id
* take most of pa_user_state that relates to query state and move it to the "query" table per query_id
* pa_user_state then becomes defaults for next query (so how_many, noo, etc)
* we can age out queries form the query_table after a few months?
* client side always has query_id. IF DB does not have query_id, then its really old? - just say so...
* client side takes query_id, entry_lst, current_eid, offset, first/last_eid, etc. as part of its first route / html creation.
* get this data as a json blob? or ask chatgpt to see how best to take the data and turn it into jscript data
* it then decides based on all this to GetEntryDetails( subset of entry_lst ) <- needs new route
* IN THEORY some of the subset of entry_lst don't exist -- BUT, we can handle that on response, e.g. say my query used to have 1,2,3, and since then another user/action deleted 2:
- I ask for details on 1,2,3 and get back details on 1,3 only.
- On client-side, I can say, since you ran this query, data in PA has changed - image#2 is no longer in PA.
Please run a new query (or bonus points, maybe have enough of the original query to note this and ask, do you want to ignore changes, or re-run query and get latest data?)
* client can go fwd or back in the entry_lst same as now (disabling buttons as needed), BUT as entry_lst is NOT recreated per page move, then no chance to get confused about first/last
* client side:
* for real chance to stop confusion, instead of removing deleted images from DOM, we should gray them out and put a big Del (red circle with line?) though it as overlay.
* Create another table is entry_ammendments - note the deletions, rotations, flips of specific eids - then reproduce that on the client side visually as needed
@@ -22,10 +10,6 @@
- When job that flips, rotates, deletes completes then lets update the query details (e.g. remove eids, or remove the ammendments)
- this actually is quite an improvement, if someone is deleting 2 as per above, I will see that as a pending change in my unrelated query, ditto flips, etc.
* NEED to work through how we deal with directories when we do the json data versions above?
- e.g. does entry_list only contain files? OR filter the details in the jscript?
- how do we do dirs in this context? (when folders=True)
### GENERAL
* jobs for AI should show path name
* rm dups job should show progress bar

View File

@@ -21,11 +21,12 @@ from datetime import datetime, timedelta
import pytz
import html
from flask_login import login_required, current_user
from states import States, PA_UserState
from query import Query
from types import SimpleNamespace
# Local Class imports
################################################################################
from states import States, PA_UserState
from query import Query
from job import Job, JobExtra, Joblog, NewJob, SetFELog
from path import PathType, Path, MovePathDetails
from person import Refimg, Person, PersonRefimgLink
@@ -472,8 +473,7 @@ def get_dir_entries():
# get content of dir_id
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
# FIXME: what do we do with ordering anyway???
#stmt=stmt.order_by(*order_map.get(OPT.noo) )
stmt=stmt.order_by(*order_map.get(OPT.noo) )
ids=db.session.execute(stmt).scalars().all()
entries_schema = EntrySchema(many=True)
entries = Entry.query.filter(Entry.id.in_(ids)).all()
@@ -485,39 +485,28 @@ def get_dir_entries():
################################################################################
def GetQueryData( OPT ):
query_data={}
query_data['query_id']=None
query_data['entry_list']=None
if OPT.path_type == 'Search':
print ("NOT YET")
return query_data
# 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).filter(Dir.rel_path == '').filter(Path.path_prefix==OPT.prefix) )
dir_stmt=( select(Entry.id).join(Dir).join(PathDirLink).join(Path).
filter(Dir.rel_path == '').filter(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
dir_arr=db.session.execute(dir_stmt).scalars().all()
dir_id=dir_arr[0]
# used to know the parent/root (in folder view), in flat view - just ignore/safe though
query_data['root_eid']=dir_id
if OPT.folders:
# start folder view with only the root folder
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
query_data['entry_list']=db.session.execute(stmt).scalars().all()
else:
# get every File that is in the OPT.prefix Path
stmt=( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix == OPT.prefix) )
stmt=( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).
filter(Path.path_prefix == OPT.prefix) )
stmt=stmt.order_by(*order_map.get(OPT.noo) )
query_data['entry_list']=db.session.execute(stmt).scalars().all()
# not sure I need this in hindsight - any value at all???
# # first time we get the data q_offset is 0, current=first one, search never gets here, so search_term=''
# # FIXME: Doubt we need cwd -- I only need originals to either invalidate this list, or recreate it... need to think about that a lot more
# query = Query( path_type=OPT.path_type, noo=OPT.noo, q_offset=0, folder=OPT.folders, grouping=OPT.grouping, root=OPT.root, cwd=OPT.cwd, search_term='',
# entry_list=query_data['entry_list'], current=query_data['entry_list'][0], created=datetime.now(pytz.utc) )
# db.session.add(query)
# db.session.commit()
#
# query_data['query_id']=query.id
return query_data
################################################################################
@@ -570,12 +559,24 @@ def GetEntries( OPT ):
return entries
################################################################################
# /change_file_opts -> allow sort order, how_many per page, etc. to change, and
# then send back the new query_data to update entryList
################################################################################
@app.route("/change_file_opts", methods=["POST"])
@login_required
def change_file_opts():
# reset options based on form post, then redirect back to orig page (with a GET to allow back button to work)
OPT=States( request )
return redirect( request.referrer )
def change_file_opts2():
data = request.get_json() # Parse JSON body
# allow dot-notation for OPT
OPT = SimpleNamespace(**data)
if OPT.folders == 'True':
OPT.folders=True
else:
OPT.folders=False
# so create a new entryList, and handle that on the client
query_data = GetQueryData( OPT )
return make_response( jsonify( query_data=query_data ) )
################################################################################
# /file_list -> show detailed file list of files from import_path(s)
@@ -862,12 +863,6 @@ def newview():
data = request.get_json() # Parse JSON body
eid = data.get('eid', 0) # Extract list of ids
# need appropriate schema? to get FaceData with entry, lists should just be
# what we have in entryList so it can help with next/prev
# include Entry for name/path, ffl (model_used), frl (distance), Face (for w/h, etc), Person (id,tag)
#stmt=select(Entry).filter(Entry.id==eid)
stmt = (
select(Entry)
.options(
@@ -877,8 +872,7 @@ def newview():
.where(Entry.id == eid)
)
print( stmt )
# this needs unique because:
# this needs unique() because:
# entry (one row for id=660)
# file (one row, since file_details is a one-to-one relationship)
# face (many rows, since a file can have many faces)
@@ -886,7 +880,6 @@ def newview():
# The SQL query returns a Cartesian product for the joins involving collections (like faces). For example, if your file has 3 faces,
# the result set will have 3 rows, each with the same entry and file data, but different face, refimg, and person data.
data=db.session.execute(stmt).unique().scalars().all()
print( data )
return jsonify(entries_schema.dump(data))
################################################################################

View File

@@ -473,7 +473,7 @@ function getDirEntries(dir_id, back)
document.entries=res
// rebuild entryList/pageList as each dir comes with new entries
entryList=res.map(obj => obj.id);
pageList=entryList.slice(0, OPT.howMany)
pageList=entryList.slice(0, OPT.how_many)
if( back )
document.back_id = res[0].in_dir.eid
drawPageOfFigures()
@@ -539,8 +539,8 @@ function getPage(pageNumber,viewing_idx=0)
// getting another event before we have the data for the page back
$('#la').prop('disabled', true)
$('#ra').prop('disabled', true)
const startIndex = (pageNumber - 1) * OPT.howMany;
const endIndex = startIndex + OPT.howMany;
const startIndex = (pageNumber - 1) * OPT.how_many;
const endIndex = startIndex + OPT.how_many;
pageList = entryList.slice(startIndex, endIndex);
// set up data to send to server to get the entry data for entries in pageList
@@ -581,7 +581,7 @@ function isFirstPage(pageNumber)
// Function to check if we are on the last page
function isLastPage(pageNumber)
{
const totalPages = Math.ceil(entryList.length / OPT.howMany);
const totalPages = Math.ceil(entryList.length / OPT.how_many);
return pageNumber >= totalPages;
}
@@ -592,7 +592,7 @@ function getPageNumberForId(id) {
if (idx === -1) {
return -1; // or null, if you prefer
}
return Math.floor(idx / OPT.howMany) + 1;
return Math.floor(idx / OPT.how_many) + 1;
}
// if we are on first page, disable prev, it not ensure next is enabled
@@ -618,7 +618,7 @@ function nextPage()
// should never happen / just return pageList unchanged
if ( currentPage === -1 || isLastPage( currentPage ) )
{
console.log( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.howMany + " 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
}
getPage( currentPage+1 )
@@ -634,7 +634,7 @@ function prevPage()
// should never happen / just return pageList unchanged
if (currentPage === 1 || currentPage === -1 )
{
console.log( "WARNING: seems first on pg=" + firstEntryOnPage + " of how many=" + OPT.howMany + " 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
}
getPage( currentPage-1 )

View File

@@ -93,8 +93,8 @@ def CreateSelect(name, selected, list, js="", add_class="", vals={} ):
# TODO: can this be collapsed into using above - probably if the 'selected' passed in was 'In Folder' or 'Flat View' -- but I think that isn't in a var???
# Helper function used in html files to create a bootstrap'd select with options. Same as CreateSelect() really, only contains
# hard-coded True/False around the if selected part, but with string based "True"/"False" in the vals={}, and list has "In Folders", "Flat View"
def CreateFoldersSelect(selected, add_class=""):
str = f'<select id="folders" name="folders" class="{add_class} sm-txt bg-white text-info border-info border-1 p-1" onChange="this.form.submit()">'
def CreateFoldersSelect(selected, js="", add_class=""):
str = f'<select id="folders" name="folders" class="{add_class} sm-txt bg-white text-info border-info border-1 p-1" onChange="{js};this.form.submit()">'
# if selected is true, then folders == true, so make this the selected option
if( selected ):
str += '<option selected value="True">In Folders</option>'

271
states.py
View File

@@ -52,157 +52,35 @@ class PA_UserState(db.Model):
################################################################################
class States(PA):
def __init__(self, request):
self.path_type=''
self.orig_search_term = ''
self.url = request.path
self.view_eid = None
self.current=0
self.first_eid=0
self.last_eid=0
self.num_entries=0
# set the prefix based on path
path=None
if 'files_ip' in self.url or 'file_list_ip' in self.url:
self.path_type = 'Import'
path = SettingsIPath()
elif 'files_sp' in self.url:
self.path_type = 'Storage'
path = SettingsSPath()
elif 'files_rbp' in self.url:
self.path_type = 'Bin'
path = SettingsRBPath()
elif 'search' in self.url:
self.path_type = 'Search'
self.search_term = ''
else:
self.path_type=''
if path:
self.prefix = SymlinkName(self.path_type,path,path+'/')
else:
self.prefix=None
# this is any next/prev or noo, grouping, etc. change (so use referrer to work out what to do with this)
# because this can happen on a view, or files_up, etc. change this FIRST
if 'change_file_opts' in request.path:
base=request.base_url
base=base.replace("change_file_opts", "")
self.url = "/"+request.referrer.replace(base, "" )
# if view_list, then we really are a view, and view_eid should be in the form
if 'view_list' in request.path:
self.path_type = 'View'
self.view_eid = request.form['view_eid']
self.url = request.form['orig_url']
# this occurs ONLY when a POST to /view/<id> occurs (at this stage orig_url will be from an import, storage, bin or search)
elif 'view' in request.path:
self.path_type = 'View'
self.view_eid = self.url[6:]
# use orig url to define defaults/look up states for 'last' import/storage/bin/search
if request.method == "POST":
self.url = request.form['orig_url']
else:
# GET's occur on redirect, and we don't have a form, so get it from pref
st=self.url[8:]
if request.referrer and 'search' in request.referrer:
st=re.sub( '.+/search/', '', request.referrer )
else:
st=''
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.view_eid==self.view_eid,PA_UserState.orig_search_term==st).first()
if not pref:
SetFELog( message=f"ERROR: pref not found - dn={current_user.dn}, st={st}, s={self}????" , level="danger", persistent=True, cant_close=False )
SetFELog( message=f"WARNING: I think this error occurred because you reloaded a page and the server had restarted between your original page load and this page reload, is that possible?" , level="warning", persistent=True, cant_close=False )
redirect("/")
else:
if not hasattr( pref, 'orig_url' ):
SetFELog( message=f"ERROR: orig_url not in pref - dn={current_user.dn}, st={st}, self={self}, pref={pref}????" , level="danger", persistent=True, cant_close=True )
redirect("/")
self.url = pref.orig_url
if 'files_ip' in self.url or 'file_list_ip' in self.url:
if self.path_type == "View":
self.orig_ptype = 'Import'
self.orig_url = self.url
else:
self.path_type = 'Import'
elif 'files_sp' in self.url:
if self.path_type == "View":
self.orig_ptype = 'Storage'
self.orig_url = self.url
else:
self.path_type = 'Storage'
elif 'files_rbp' in self.url:
if self.path_type == "View":
self.orig_ptype = 'Bin'
self.orig_url = self.url
else:
self.path_type = 'Bin'
elif 'search' in self.url:
# okay if we are a search, but came from a view then get last_search_state form prefs and use it
m=re.match( '.*search/(.+)$', self.url )
if m == None:
SetFELog( message=f"ERROR: DDP messed up, seems we are processing a search, but cant see the search term - is this even possible?" )
return
self.orig_search_term = m[1]
if self.path_type == "View":
self.orig_ptype = 'Search'
self.orig_url = self.url
else:
self.path_type = 'Search'
elif 'view' in self.url:
# use url to get eid of viewed entry
self.view_eid = self.url[6:]
# force this to be a search so rest of code won't totally die, but also not return anything
self.path_type="Search"
self.orig_url=self.url
elif 'change_file_opts' not in self.url:
SetFELog( message=f"ERROR: DDP messed up, failed to match URL {self.url} for settings this will fail, redirecting to home" , level="danger", persistent=True, cant_close=True )
SetFELog( message=f"referrer={request.referrer}" , level="danger", persistent=True, cant_close=True )
return
if self.path_type == 'View':
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.view_eid==self.view_eid,PA_UserState.orig_search_term==self.orig_search_term).first()
if not hasattr( self, 'orig_ptype' ):
self.orig_ptype='View'
self.orig_url=''
SetFELog( message=f"ERROR: No orig ptype? s={self} - pref={pref}, redirecting to home" , level="danger", persistent=True, cant_close=True )
SetFELog( message=f"referrer={request.referrer}" , level="danger", persistent=True, cant_close=True )
redirect("/")
# should find original path or search for this view (if not a search, search_term='')
orig_pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.orig_ptype,PA_UserState.orig_search_term==self.orig_search_term).first()
if not orig_pref:
SetFELog( message=f"ERROR: DDP messed up 2, failed to find orig_pref for a view pt={self.path_type} for search={self.orig_search_term}" , level="danger", persistent=True, cant_close=True )
SetFELog( message=f"referrer={request.referrer}" , level="danger", persistent=True, cant_close=True )
return
elif self.path_type == 'Search':
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.orig_search_term==self.orig_search_term).first()
else:
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first()
if pref:
self.grouping=pref.grouping
self.how_many=pref.how_many
self.offset=pref.st_offset
self.size=pref.size
self.cwd=pref.cwd
self.orig_ptype=pref.orig_ptype
self.orig_search_term=pref.orig_search_term
self.orig_url = pref.orig_url
self.view_eid = pref.view_eid
self.current = pref.current
if self.path_type == "View":
self.root='static/' + self.orig_ptype
self.first_eid=orig_pref.first_eid
self.last_eid=orig_pref.last_eid
self.num_entries=orig_pref.num_entries
self.noo=orig_pref.noo
self.folders=orig_pref.folders
self.orig_search_term=orig_pref.orig_search_term
else:
self.root=pref.root
self.first_eid = pref.first_eid
self.last_eid = pref.last_eid
self.num_entries = pref.num_entries
self.noo=pref.noo
self.folders=pref.folders
else:
# retreive defaults from 'PAUser' where defaults are stored
u=PAUser.query.filter(PAUser.dn==current_user.dn).one()
self.grouping=u.default_grouping
self.how_many=u.default_how_many
self.offset=0
self.size=u.default_size
if self.path_type == "View":
self.root='static/' + self.orig_ptype
self.first_eid=orig_pref.first_eid
self.last_eid=orig_pref.last_eid
self.num_entries=orig_pref.num_entries
self.noo=orig_pref.noo
self.folders=orig_pref.folders
self.orig_search_term=orig_pref.orig_search_term
else:
self.root='static/' + self.path_type
if self.path_type == 'Import':
self.noo = u.default_import_noo
@@ -215,111 +93,10 @@ class States(PA):
self.noo=u.default_search_noo
self.folders=False
self.default_flat_noo=u.default_import_noo
self.default_folder_noo=u.default_storage_noo
self.default_search_noo=u.default_search_noo
self.cwd=self.root
if not hasattr(self, 'orig_ptype'):
self.orig_ptype=None
if not hasattr(self, 'orig_search_term'):
self.orig_search_term=None
self.orig_url = self.url
# the above are defaults, if we are here, then we have current values, use them instead if they are set -- AI: searches dont set them so then we use those in the DB first
if request.method=="POST":
if self.path_type != "View" and 'noo' in request.form:
# we are changing values based on a POST to the form, if we changed the noo option, we need to reset things
if 'change_file_opts' in request.path and self.noo != request.form['noo']:
self.noo=request.form['noo']
self.first_eid=0
self.last_eid=0
self.offset=0
if 'how_many' in request.form:
self.how_many=request.form['how_many']
if 'offset' in request.form:
self.offset=int(request.form['offset'])
if 'grouping' in request.form:
self.grouping=request.form['grouping']
# this can be null if we come from view by details
if 'size' in request.form:
self.size = request.form['size']
# seems html cant do boolean, but uses strings so convert
if self.path_type != "View" and 'folders' in request.form:
# we are changing values based on a POST to the form, if we are in folder view and we changed the folders option, we need to reset things
if 'change_file_opts' in request.path:
if self.folders and self.folders != request.form['folders']:
self.num_entries=0
self.first_eid=0
self.last_eid=0
if request.form['folders'] == "False":
self.folders=False
else:
self.folders=True
# have to force grouping to None if we flick to folders from a flat view with grouping (otherwise we print out
# group headings for child content that is not in the CWD)
self.grouping=None
if 'orig_url' in request.form:
self.orig_url = request.form['orig_url']
# possible to not be set for an AI: search
if 'cwd' in request.form:
self.cwd = request.form['cwd']
if 'prev' in request.form:
self.offset -= int(self.how_many)
# just in case we hit prev too fast, stop this...
if self.offset < 0:
self.offset=0
if 'next' in request.form:
if (self.offset + int(self.how_many)) < self.num_entries:
self.offset += int(self.how_many)
else:
# tripping this still
SetFELog( message=f"WARNING: next image requested, but would go past end of list? - ignore this" , level="warning", persistent=True, cant_close=False )
if 'current' in request.form:
self.current = int(request.form['current'])
last_used=datetime.now(pytz.utc)
# set the prefix based on path
path=None
if self.path_type == 'Storage':
path = SettingsSPath()
elif self.path_type == 'Import':
path = SettingsIPath()
elif self.path_type == 'Bin':
path = SettingsRBPath()
if path:
self.prefix = SymlinkName(self.path_type,path,path+'/')
# now save pref
if not pref:
# insert new pref for this combo (might be a new search or view, or first time for a path)
pref=PA_UserState( pa_user_dn=current_user.dn, last_used=last_used, path_type=self.path_type, view_eid=self.view_eid,
noo=self.noo, grouping=self.grouping, how_many=self.how_many, st_offset=self.offset, size=self.size,
folders=self.folders, root=self.root, cwd=self.cwd, orig_ptype=self.orig_ptype, orig_search_term=self.orig_search_term,
orig_url=self.orig_url, current=self.current, first_eid=self.first_eid, last_eid=self.last_eid, num_entries=self.num_entries )
else:
# update this pref with the values calculated above (most likely from POST to form)
pref.pa_user_dn=current_user.dn
pref.path_type=self.path_type
pref.view_eid=self.view_eid
pref.noo=self.noo
pref.grouping=self.grouping
pref.how_many=self.how_many
pref.st_offset=self.offset
pref.size=self.size
pref.folders=self.folders
pref.root = self.root
pref.cwd = self.cwd
pref.orig_ptype = self.orig_ptype
pref.orig_search_term = self.orig_search_term
pref.orig_url = self.orig_url
pref.last_used = last_used
pref.first_eid = self.first_eid
pref.last_eid = self.last_eid
pref.num_entries = self.num_entries
# only passed in (at the moment) in view_list
pref.current = self.current
db.session.add(pref)
db.session.commit()
return

View File

@@ -5,6 +5,8 @@
<script src="{{ url_for( 'internal', filename='js/files_transform.js')}}"></script>
<script>
// FIXME: used by viewer code - should probably get rid of this?
var fullscreen=false;
document.fake_shift=0
document.fake_ctrl=0
var move_paths=[]
@@ -17,22 +19,23 @@
{% endfor %}
// GLOBALS
// OPTions set via GUI, will change if we alter drop-downs, etc. in GUI
// TODO: reference these from GUI, so we can finally ditch the form to submit/change them.
// BUT -- must handle noo changing with a form/post as it requires a new ordering
// this is which eid we are viewing an image/video (when we dbl-click & then next/prev)
document.viewing_eid=null;
document.viewing=null;
var OPT={}
OPT.noo='{{OPT.noo}}'
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.folders="{{OPT.folders}}" === "True"
OPT.howMany={{OPT.how_many}}
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
var entryList={{query_data.entry_list}}
@@ -41,6 +44,48 @@
var pageList=[]
// force pageList to set pageList for & render the first page
getPage(1)
function cFO() {
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( `&nbsp;${OPT.how_many} files&nbsp;` )
OPT.root_eid=parseInt(OPT.root_eid)
OPT.size=parseInt(OPT.size)
getPage(1)
}
})
}
</script>
<div id="files_div">
@@ -68,13 +113,13 @@
{% endif %}
<div class="col col-auto">
<div class="input-group">
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "$('#offset').val(0)", "rounded-start py-2")|safe }}
{{CreateSelect( "how_many", OPT.how_many|string, ["10", "25", "50", "75", "100", "150", "200", "500"])|safe }}
{{CreateSelect( "noo", OPT.noo, ["Oldest", "Newest","A to Z", "Z to A"], "cFO(); 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 }}
{% if OPT.folders %}
<input type="hidden" name="grouping" id="grouping" value="{{OPT.grouping}}">
{{CreateFoldersSelect( OPT.folders, "rounded-end" )|safe }}
{{CreateFoldersSelect( OPT.folders, "cFO(); return false", "rounded-end" )|safe }}
{% else %}
{{CreateFoldersSelect( OPT.folders )|safe }}
{{CreateFoldersSelect( OPT.folders, "cFO(); return false" )|safe }}
<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 }}
{% endif %}
@@ -92,7 +137,7 @@
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage()" disabled>
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
</button>
<span class="sm-txt my-auto">&nbsp;{{OPT.how_many}} files&nbsp;</span>
<span class="how_many_text sm-txt my-auto">&nbsp;{{OPT.how_many}} files&nbsp;</span>
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage()">
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
</button>
@@ -163,7 +208,7 @@
<button aria-label="prev" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary disabled" onClick="prevPage()" disabled>
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
</button>
<span class="sm-txt my-auto">&nbsp;{{OPT.how_many}} files&nbsp;</span>
<span class="how_many_text sm-txt my-auto">&nbsp;{{OPT.how_many}} files&nbsp;</span>
<button aria-label="next" id="next" name="next" class="next sm-txt btn btn-outline-secondary" onClick="nextPage()">
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
</button>
@@ -227,11 +272,11 @@
function getPreviousEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.howMany)
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex > 0) {
currentIndex--;
pageOffset=Math.floor(currentIndex / OPT.howMany)
currentIndex=currentIndex-(pageOffset*OPT.howMany)
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
@@ -244,11 +289,11 @@
function getNextEntry() {
var currentIndex = entryList.indexOf(document.viewing.id);
oldPageOffset=Math.floor(currentIndex / OPT.howMany)
oldPageOffset=Math.floor(currentIndex / OPT.how_many)
if (currentIndex < entryList.length - 1) {
currentIndex++
pageOffset=Math.floor(currentIndex / OPT.howMany)
currentIndex=currentIndex-(pageOffset*OPT.howMany)
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
@@ -268,9 +313,9 @@
function setEntryById(id) {
var currentIndex = entryList.indexOf(parseInt(id));
// if we are on a different page, adjust as document.entries only has <= howMany
pageOffset=Math.floor(currentIndex / OPT.howMany)
currentIndex = currentIndex-(pageOffset*OPT.howMany)
// 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]
}
@@ -533,7 +578,7 @@ $.contextMenu({
return {
callback: function( key, options) {
if( key == "details" ) { DetailsDBox() }
if( key == "view" ) { CallViewRoute( $(this).attr('id') ) }
if( key == "view" ) { dblClickToViewEntry( $(this).attr('id') ) }
if( key == "move" ) { MoveDBox(move_paths, "{{url_for('internal', filename='icons.svg')}}") }
if( key == "del" ) { DelDBox('Delete') }
if( key == "undel") { DelDBox('Restore') }
@@ -552,15 +597,6 @@ $.contextMenu({
});
$(document).ready(function() {
if( {{OPT.offset}} == 0 )
{
$('.prev').addClass('disabled')
$('.prev').prop('disabled', true)
}
$(".dir").click( function(e) { $('#offset').val(0) ; $('#cwd').val( $(this).attr('dir') ) ; $('#main_form').submit() } )
} )
$( document ).keydown(function(event) {
switch (event.key)
{