Added search function.
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
@@ -1,3 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
@@ -52,6 +52,15 @@
|
|||||||
margin-left: 2em;
|
margin-left: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
border: none;
|
||||||
|
background-color: #00000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Grid. *
|
* Grid. *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
BIN
viewer/static/imgs/find.png
Executable file
BIN
viewer/static/imgs/find.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@@ -8,98 +8,150 @@
|
|||||||
</title>
|
</title>
|
||||||
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
|
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="background">
|
<body class="background">
|
||||||
{% if images|length > 0 %}
|
<!-- Navigation bar. -->
|
||||||
<table class="fc mauto">
|
<table class="fc mauto">
|
||||||
<tr>
|
<tr>
|
||||||
|
<!-- Home button. -->
|
||||||
<td>
|
<td>
|
||||||
<a href="/gallery/" class="mr-2">
|
<a href="/gallery/" class="mr-2">
|
||||||
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
|
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<!-- Back button. -->
|
||||||
|
{% if not search %}
|
||||||
<td>
|
<td>
|
||||||
<a href=".." class="mr-2">
|
<a href=".." class="mr-2">
|
||||||
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
|
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Directory path. -->
|
||||||
<td>
|
<td>
|
||||||
<h1 class="mr-2">
|
<h1 class="mr-2">
|
||||||
{{request.path}} - Files ({{num_files}})
|
{% if not search %}
|
||||||
|
{{request.path}} - Files: {{num_files}}
|
||||||
|
{% else %}
|
||||||
|
Search: {{search_text}} - Files: {{num_files}}
|
||||||
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<!-- Page links. -->
|
||||||
{% if num_pages > 1 %}
|
{% if num_pages > 1 %}
|
||||||
<td>
|
<td>
|
||||||
<div class="mauto">
|
<div class="mauto">
|
||||||
{% for page in pages %}<a href="./?page={{page}}">{{page}}</a>{% if not forloop.last %}<span> </span>{% endif %}{% endfor %}
|
{% for page in pages %}<a href="./?page={{page}}{%if search %}&{{search}}{% endif %}">{{page}}</a>{% if not forloop.last %}<span> </span>{% endif %}{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="centered-container">
|
|
||||||
|
<!-- Search form. -->
|
||||||
|
{% if not search %}
|
||||||
|
<form action="{% url 'gallery_view_root' %}" method="GET">
|
||||||
<table class="fc mauto">
|
<table class="fc mauto">
|
||||||
<tr>
|
<tr>
|
||||||
{% if page != 1 %}
|
<!-- Search title. -->
|
||||||
<td class="fc">
|
<td>
|
||||||
<a href="./?page={{prev_page}}">
|
<h3>
|
||||||
<img src="{% static 'imgs/back.png' %}" class="navigation-icon">
|
Search:
|
||||||
</a>
|
</h3>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
|
||||||
<td class="fc">
|
<!-- Search bar. -->
|
||||||
<table class="mauto">
|
<td>
|
||||||
<tbody>
|
<input type="text" name="search" class="search-box">
|
||||||
{% for row in images %}
|
|
||||||
<tr>
|
|
||||||
{% for cell in row %}
|
|
||||||
<td class="column">
|
|
||||||
<a href="{{cell.path}}">
|
|
||||||
<img src="{{cell.thumbnail}}">
|
|
||||||
<br>
|
|
||||||
<span>
|
|
||||||
{{cell.path|truncatechars:15}}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</td>
|
</td>
|
||||||
{% if page != num_pages %}
|
|
||||||
<td class="fc">
|
<!-- Search submit. -->
|
||||||
<a href="./?page={{next_page}}">
|
<td>
|
||||||
<img src="{% static 'imgs/forward.png' %}" class="navigation-icon">
|
<button type="submit" class="search-btn">
|
||||||
</a>
|
<img src="{% static 'imgs/find.png' %}" class="small-nav-icon">
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Images in current directory. -->
|
||||||
|
{% if images|length > 0 %}
|
||||||
|
<table class="fc mauto">
|
||||||
|
<tr>
|
||||||
|
<!-- Previous page button. -->
|
||||||
|
{% if page != 1 %}
|
||||||
|
<td class="fc">
|
||||||
|
<a href="./?page={{prev_page}}{%if search %}&{{search}}{% endif %}">
|
||||||
|
<img src="{% static 'imgs/back.png' %}" class="navigation-icon">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Image rows. -->
|
||||||
|
<td class="fc">
|
||||||
|
<table class="mauto">
|
||||||
|
<tbody>
|
||||||
|
{% for row in images %}
|
||||||
|
<tr>
|
||||||
|
{% for image in row %}
|
||||||
|
<td class="column">
|
||||||
|
<a href="{{image.path}}">
|
||||||
|
<!-- Thumbnail. -->
|
||||||
|
<img src="{{image.thumbnail}}">
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- Image name. -->
|
||||||
|
<span>
|
||||||
|
{{image.name|truncatechars:15}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Next page button. -->
|
||||||
|
{% if page != num_pages %}
|
||||||
|
<td class="fc">
|
||||||
|
<a href="./?page={{next_page}}{%if search %}&{{search}}{% endif %}">
|
||||||
|
<img src="{% static 'imgs/forward.png' %}" class="navigation-icon">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if subdirs|length > 0 %}
|
{% if subdirs|length > 0 %}
|
||||||
|
<!-- Sub-directories title. -->
|
||||||
<div class="centered-container">
|
<div class="centered-container">
|
||||||
<h1>
|
<h1>
|
||||||
Sub-directories
|
Sub-directories
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Sub-directory rows. -->
|
||||||
<div class="centered-container">
|
<div class="centered-container">
|
||||||
<table class="mauto">
|
<table class="mauto">
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for row in subdirs %}
|
{% for row in subdirs %}
|
||||||
<tr>
|
<tr>
|
||||||
{% for cell in row %}
|
{% for subdir in row %}
|
||||||
<td class="column">
|
<td class="column">
|
||||||
{% if request.path == '/gallery/' %}
|
<a href="{{subdir.path}}">
|
||||||
<a href="{{cell.name}}">
|
|
||||||
{% else %}
|
|
||||||
<a href="{{request.path}}{{cell.name}}">
|
|
||||||
{% endif %}
|
|
||||||
<img src="{% static 'imgs/folder-pictures.png' %}">
|
<img src="{% static 'imgs/folder-pictures.png' %}">
|
||||||
<br>
|
<br>
|
||||||
<span>
|
<span>
|
||||||
{{cell.name}}
|
{{subdir.name}}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@@ -8,14 +8,19 @@
|
|||||||
</title>
|
</title>
|
||||||
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
|
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="background">
|
<body class="background">
|
||||||
|
<!-- Navigation. -->
|
||||||
<table class="fc mauto">
|
<table class="fc mauto">
|
||||||
<tr>
|
<tr>
|
||||||
|
<!-- Home button. -->
|
||||||
<td>
|
<td>
|
||||||
<a href="/gallery/">
|
<a href="/gallery/">
|
||||||
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
|
<img src="{% static 'imgs/gohome.png' %}" class="small-nav-icon">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<!-- Back button. -->
|
||||||
<td>
|
<td>
|
||||||
<a href="..">
|
<a href="..">
|
||||||
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
|
<img src="{% static 'imgs/back.png' %}" class="small-nav-icon">
|
||||||
@@ -23,8 +28,11 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Image view. -->
|
||||||
<table class="fc mauto">
|
<table class="fc mauto">
|
||||||
<tr>
|
<tr>
|
||||||
|
<!-- Previous image. -->
|
||||||
<td>
|
<td>
|
||||||
{% if prev %}
|
{% if prev %}
|
||||||
<a href="../{{prev}}">
|
<a href="../{{prev}}">
|
||||||
@@ -32,6 +40,8 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<!-- Current image. -->
|
||||||
<td>
|
<td>
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<a href="{{image_path}}" target="_blank">
|
<a href="{{image_path}}" target="_blank">
|
||||||
@@ -39,6 +49,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<!-- Next image. -->
|
||||||
<td>
|
<td>
|
||||||
{% if next %}
|
{% if next %}
|
||||||
<a href="../{{next}}">
|
<a href="../{{next}}">
|
||||||
|
121
viewer/views.py
121
viewer/views.py
@@ -6,10 +6,11 @@ from math import ceil
|
|||||||
import filetype
|
import filetype
|
||||||
|
|
||||||
# Django imports.
|
# Django imports.
|
||||||
from django.http import HttpResponseNotFound
|
from django.http import HttpResponseNotFound
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import (render,
|
from django.utils.http import urlencode
|
||||||
redirect)
|
from django.shortcuts import (render,
|
||||||
|
redirect)
|
||||||
|
|
||||||
# Project imports.
|
# Project imports.
|
||||||
from .utils import make_thumbnail
|
from .utils import make_thumbnail
|
||||||
@@ -26,6 +27,31 @@ IMAGES_PER_PAGE = CELLS_PER_ROW * ROWS_PER_PAGE
|
|||||||
# View functions. #
|
# View functions. #
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
|
|
||||||
|
def do_recursive_search(start_path, query):
|
||||||
|
"""
|
||||||
|
Gets all images and sub-directories inside the start_path whose name matches the given query,
|
||||||
|
and then joins the results recursively by iterating in each sub-directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get all sub-dirs and images that match the query.
|
||||||
|
subdirs = sorted([i.absolute() for i in start_path.iterdir() if i.is_dir() and query.lower() in i.name.lower()])
|
||||||
|
images = sorted([i for i in start_path.iterdir() if i.is_file() and filetype.is_image(str(i)) and query.lower() in i.name.lower()])
|
||||||
|
|
||||||
|
# For all sub-directories, regardless of the query.
|
||||||
|
for subdir in sorted([i for i in start_path.iterdir() if i.is_dir()]):
|
||||||
|
# Do a recursive search.
|
||||||
|
rec_subdirs, rec_images = do_recursive_search(subdir, query.lower())
|
||||||
|
|
||||||
|
# Join the results if any.
|
||||||
|
subdirs.extend(rec_subdirs)
|
||||||
|
images.extend(rec_images)
|
||||||
|
|
||||||
|
return subdirs, images
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
# View functions. #
|
||||||
|
###########################################################################################
|
||||||
|
|
||||||
def gallery_view(request, path = None):
|
def gallery_view(request, path = None):
|
||||||
"""
|
"""
|
||||||
Shows a list of subdirectories and image files inside the given path.
|
Shows a list of subdirectories and image files inside the given path.
|
||||||
@@ -33,6 +59,10 @@ def gallery_view(request, path = None):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def list2rows(lst, cells = CELLS_PER_ROW):
|
def list2rows(lst, cells = CELLS_PER_ROW):
|
||||||
|
"""
|
||||||
|
Converts a list into a matrix with the given amount of cells per row.
|
||||||
|
"""
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(lst):
|
while i < len(lst):
|
||||||
@@ -46,64 +76,101 @@ def gallery_view(request, path = None):
|
|||||||
i += cells
|
i += cells
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
# Get the absolute path to show if any, else show the base gallery path.
|
||||||
full_path = settings.GALLERY_ROOT.joinpath(path) if path is not None else settings.GALLERY_ROOT
|
full_path = settings.GALLERY_ROOT.joinpath(path) if path is not None else settings.GALLERY_ROOT
|
||||||
|
|
||||||
if full_path.exists():
|
# Get the search query from the request, if any.
|
||||||
if full_path.is_dir():
|
search = request.GET.get('search', default = '')
|
||||||
subdirs = sorted([i for i in full_path.iterdir() if i.is_dir()])
|
|
||||||
images = sorted([i for i in full_path.iterdir() if i.is_file() and filetype.is_image(str(i))])
|
|
||||||
img_data = []
|
|
||||||
num_pages = ceil((len(images) / CELLS_PER_ROW) / ROWS_PER_PAGE)
|
|
||||||
|
|
||||||
|
if full_path.exists():
|
||||||
|
# If the path exists then check if it points to a directory or an image.
|
||||||
|
if full_path.is_dir():
|
||||||
|
if search == '':
|
||||||
|
# If there is no search query then get all images and sub-directories of the current path.
|
||||||
|
subdirs = sorted([i for i in full_path.iterdir() if i.is_dir()])
|
||||||
|
images = sorted([i for i in full_path.iterdir() if i.is_file() and filetype.is_image(str(i))])
|
||||||
|
|
||||||
|
else:
|
||||||
|
# If there is a search query then search the current directory recursively.
|
||||||
|
subdirs, images = do_recursive_search(full_path, search)
|
||||||
|
|
||||||
|
# For every sub-directory found, prepare it's name and path for rendering.
|
||||||
|
subdir_data = []
|
||||||
|
for subdir in subdirs:
|
||||||
|
subdir_data.append({
|
||||||
|
'path': '/gallery/' + str(subdir.relative_to(settings.GALLERY_ROOT)),
|
||||||
|
'name': subdir.name
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get the page number to show, if any. Default to the first one if unavailable or error.
|
||||||
try:
|
try:
|
||||||
page = int(request.GET.get('page', 1))
|
page = int(request.GET.get('page', 1))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
page = 1
|
page = 1
|
||||||
|
|
||||||
|
# Compute the page offset to show.
|
||||||
|
num_pages = ceil((len(images) / CELLS_PER_ROW) / ROWS_PER_PAGE)
|
||||||
page_offset = IMAGES_PER_PAGE * (page - 1)
|
page_offset = IMAGES_PER_PAGE * (page - 1)
|
||||||
|
|
||||||
|
# Slice the images found with the page offset and prepare them for rendering.
|
||||||
|
img_data = []
|
||||||
for image in images[page_offset : page_offset + IMAGES_PER_PAGE]:
|
for image in images[page_offset : page_offset + IMAGES_PER_PAGE]:
|
||||||
|
# Create thumbnails as needed.
|
||||||
make_thumbnail(image)
|
make_thumbnail(image)
|
||||||
|
|
||||||
img_context = {
|
# Get the path of the image relative to the gallery root.
|
||||||
'path': image.name,
|
rel_path = image.relative_to(settings.GALLERY_ROOT)
|
||||||
|
|
||||||
|
# For each image, prepare it's path, thumbnail path and name for rendering.
|
||||||
|
img_data.append({
|
||||||
|
'path': '/gallery/' + str(rel_path),
|
||||||
'name': image.name,
|
'name': image.name,
|
||||||
'thumbnail': '/thumbs/' + path + '/' + image.name if path is not None else '/thumbs/' + image.name
|
'thumbnail': '/thumbs/' + str(rel_path)
|
||||||
}
|
})
|
||||||
|
|
||||||
img_data.append(img_context)
|
|
||||||
|
|
||||||
print(page)
|
|
||||||
|
|
||||||
|
# Rendering context.
|
||||||
context = {
|
context = {
|
||||||
'path': path,
|
'path': path,
|
||||||
'subdirs': list2rows(subdirs),
|
'subdirs': list2rows(subdir_data),
|
||||||
'images': list2rows(img_data),
|
'images': list2rows(img_data),
|
||||||
'pages': range(1, num_pages + 1),
|
'pages': range(1, num_pages + 1),
|
||||||
'num_files': len(images),
|
'num_files': len(images),
|
||||||
'page': page,
|
'page': page,
|
||||||
'prev_page': page - 1,
|
'prev_page': page - 1,
|
||||||
'next_page': page + 1,
|
'next_page': page + 1,
|
||||||
'num_pages': num_pages
|
'num_pages': num_pages,
|
||||||
|
'search': urlencode({'search': search}) if search != '' else None,
|
||||||
|
'search_text': search
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Glorious success!
|
||||||
return render(request, 'gallery_view.html', context)
|
return render(request, 'gallery_view.html', context)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# If the path points to an image, then get it's real path, and parent directory path.
|
||||||
image = Path('/imgs/').joinpath(path)
|
image = Path('/imgs/').joinpath(path)
|
||||||
img_dir = settings.GALLERY_ROOT.joinpath(path).parent
|
img_dir = settings.GALLERY_ROOT.joinpath(path).parent
|
||||||
|
|
||||||
|
# Then get all sibling images.
|
||||||
images = sorted([i.name for i in img_dir.iterdir() if i.is_file() and filetype.is_image(str(i))])
|
images = sorted([i.name for i in img_dir.iterdir() if i.is_file() and filetype.is_image(str(i))])
|
||||||
|
|
||||||
|
# Get the current image's index in it's directory.
|
||||||
index = images.index(image.name)
|
index = images.index(image.name)
|
||||||
|
|
||||||
|
# Get the previous and next image indices.
|
||||||
previous = index - 1 if index > 0 else None
|
previous = index - 1 if index > 0 else None
|
||||||
following = index + 1 if index < len(images) - 1 else None
|
following = index + 1 if index < len(images) - 1 else None
|
||||||
|
|
||||||
|
# Set the current, previous and next images as the rendering context.
|
||||||
context = {
|
context = {
|
||||||
'image_path': image,
|
'image_path': image,
|
||||||
'prev': images[previous] if previous is not None else None,
|
'prev': images[previous] if previous is not None else None,
|
||||||
'next': images[following] if following is not None else None
|
'next': images[following] if following is not None else None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Glorious success!
|
||||||
return render(request, 'image_view.html', context)
|
return render(request, 'image_view.html', context)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# 404 if the path wasn't found.
|
||||||
return HttpResponseNotFound('Not found')
|
return HttpResponseNotFound('Not found')
|
||||||
|
Reference in New Issue
Block a user