Skip to content

Commit 34b8c75

Browse files
zaryatykling
andauthored
Initial photoswipe widget support (#309)
* Initial photoswipe widget support * Fixed src set, fixed thumb aspect ratio * Added loader, use static function * This should fix the loading issues * Fixed a few small bugs * More cleanup, also added the fix to splide * Move shared code to seperate file * Add loader from base template, added loader to splide * Small bug fix (dont load file if no metadata) * More widget styling * Added fast metadata load * Added fast load to splide widget * Fixed some pswp-caption-content styling * Widget view refactor * Added iframe widget, added icons to thumbs for attribution * Dont forget a file * Update src/static_src/js/photoswipe.js * Limited searching the whole dom * Improve widget view security * Added no files available message to widget, fixed missing value in widget json --------- Co-authored-by: Thomas Steen Rasmussen <tykling@bornhack.org>
1 parent 715bc34 commit 34b8c75

File tree

15 files changed

+771
-199
lines changed

15 files changed

+771
-199
lines changed

src/files/templates/includes/file_pswp_caption.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
<div class="pswp-caption-content" data-bma-file-uuid="{{ file.uuid }}">
2-
<p class="d-inline-block"><i class="{{ file.filetype_icon }}"></i> <a href="{{ file.get_absolute_url }}"><b>{{ file.title }}</b></a></p>
2+
<p class="d-inline-block me-3"><i class="{{ file.filetype_icon }}"></i> <a href="{{ file.get_absolute_url }}"><b>{{ file.title }}</b></a></p>
33

4+
<span class="d-inline-block me-3"><i class="fas fa-user fa-fw"></i> {{ file.attribution }}</span>
5+
46
{% if file.description %}
57
<span class="d-inline-block me-3"><i class="fas fa-newspaper fa-fw"></i> {{ file.description }}</span>
68
{% endif %}
79

10+
<span class="d-inline-block me-3">
11+
{% if file.license == "CC_ZERO_1_0" %}<i class="fa-brands fa-creative-commons-zero"></i>{% endif %}
12+
{% if file.license == "CC_BY_4_0" %}<i class="fa-brands fa-creative-commons-by"></i>{% endif %}
13+
{% if file.license == "CC_BY_SA_4_0" %}<i class="fa-brands fa-creative-commons-sa"></i>{% endif %}
14+
{{ file.license_name }}
15+
</span>
16+
817
{% if file.filetype == "image" %}
918

1019
{% if file.get_exif_camera %}

src/files/templates/includes/file_thumbnail_pswp.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<span class="d-inline-block mb-1">
1+
<span class="d-inline-block m-1">
22
{% if record.filetype == "image" %}
33
<a class="gallerya text-decoration-none" href="{{ record.fullsize_url }}"
44
data-bma-file-uuid="{{ record.uuid }}"

src/static_src/css/bma.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ div.image-hover i {
9393
position: absolute;
9494
transform: translate(-50%, -50%);
9595
}
96+
div.image-hover div {
97+
display: none;
98+
bottom: 5px;
99+
right: 10px;
100+
position: absolute;
101+
}
102+
div.image-hover:hover div {
103+
display: inline-block;
104+
}
96105
div.image-hover img:hover {
97106
opacity: 0.2;
98107
background-color: black;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.photoswipe-attribution-size {
2+
max-width: 130px;
3+
}

src/static_src/js/photoswipe.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const captionPlugin = new PhotoSwipeDynamicCaption(lightbox, {
3636
// Plugins options
3737
type: 'auto',
3838
captionContent: (slide) => {
39-
return slide.data.element.parentElement.querySelector("div.pswp-caption-content").innerHTML
39+
return slide.data.element.parentElement.querySelector(`.pswp-caption-content[data-bma-file-uuid="${slide.data.element.dataset.bmaFileUuid}"]`).innerHTML
4040
},
4141
});
4242

@@ -180,3 +180,13 @@ if (location.hash && location.hash.substring(0, 10) == "#lightbox=") {
180180
let slide = document.querySelector("a.gallerya[data-bma-file-uuid='" + uuid + "']");
181181
slide.click();
182182
}
183+
184+
//Disable license link click propagation
185+
$(".license-link").bind("click", function(e) {
186+
e.stopPropagation();
187+
});
188+
189+
//Disable attribution link click propagation
190+
$(".attribution-link").bind("click", function(e) {
191+
e.stopPropagation();
192+
});

src/utils/templates/thumbnail.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
<div class="image-hover {{ hoverclass }}">
22
<i class="fas fa-2x"></i>
33
<img srcset="{{ url }}{{ url2x }}" src="{{ url }}" height="{{ t.height }}" width="{{ width }}" title="{{ title }}" alt="{{ alt }}" class="img-fluid img-thumbnail">
4+
<div>
5+
<object><a class="attribution-link" href="{{ file.get_absolute_url }}"><span title="{{ file.title }} ({{ file.attribution }})" class="fa-regular fa-arrow-up-right-from-square"></span></a></object>
6+
<object><a class="text-decoration-none license-link" href="{{ file.license_url }}">
7+
{% if file.license == "CC_ZERO_1_0" %}<span title="{{ file.license_name}}" class="fa-brands fa-creative-commons-zero"></span>{% endif %}
8+
{% if file.license == "CC_BY_4_0" %}<span title="{{ file.license_name}}" class="fa-brands fa-creative-commons-by"></span>{% endif %}
9+
{% if file.license == "CC_BY_SA_4_0" %}<span title="{{ file.license_name}}" class="fa-brands fa-creative-commons-sa"></span>{% endif %}
10+
</a></object>
11+
</div>
412
</div>

src/utils/templatetags/bma_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def thumbnail(basefile: "BaseFile", width: int, ratio: str, mimetype: str = "ima
9292
"width": width,
9393
"height": t.height,
9494
"title": title,
95+
"file": basefile,
9596
"alt": alt,
9697
}
9798
)

src/widgets/templates/gallery.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{% extends "includes/iframe.html" %}
2+
{% load humanize static %}
3+
{% block extra_head %}
4+
<link rel="stylesheet" href="{% static 'css/vendor/photoswipe-v5.4.4.css' %}">
5+
<link rel="stylesheet" href="{% static 'css/vendor/photoswipe-dynamic-caption-plugin-v1.2.7.css' %}">
6+
{% endblock extra_head %}
7+
8+
{% block main_content %}
9+
<div class="row">
10+
{% csrf_token %}
11+
<div class="pswp-gallery" id="gallery">
12+
{% for file in files %}
13+
{% include "includes/file_thumbnail_pswp.html" with record=file width=150 ratio="1/1" %}
14+
{% endfor %}
15+
</div>
16+
</div>
17+
{% endblock main_content %}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// config (rendered serverside)
2+
const uuid = "{{ uuid }}";
3+
const host = "{{ host }}";
4+
const count = "{{ count }}";
5+
6+
const templateFiles = "{{ files|escapejs }}";
7+
8+
// custom error class
9+
class BmaNotFoundError extends Error {
10+
constructor(message) {
11+
super(message);
12+
this.name = "BmaNotFoundError";
13+
}
14+
}
15+
class BmaApiError extends Error {
16+
constructor(message) {
17+
super(message);
18+
this.name = "BmaApiError";
19+
}
20+
}
21+
class BmaPermissionError extends Error {
22+
constructor(message) {
23+
super(message);
24+
this.name = "BmaPermissionError";
25+
}
26+
}
27+
28+
const main_loader = document.createElement('div');
29+
main_loader.id = "photoswipe-" + count + "-loader"
30+
main_loader.innerHTML = `<div class="spinner-grow" role="status"></div><span class="h3">Loading Gallery....</span>`;
31+
// A reference to the currently running script
32+
const bma_script = document.scripts[document.scripts.length - 1];
33+
bma_script.parentElement.insertBefore(main_loader, bma_script);
34+
35+
36+
async function getFileMetadata(file_uuid) {
37+
const response = fetch("//" + host + "/api/v1/json/files/" + file_uuid + "/", {mode: 'cors'})
38+
.then((x) => {
39+
if (!x.ok) {
40+
// handle non-2xx x code
41+
if (x.status === 404) {
42+
throw new BmaNotFoundError("File UUID " + file_uuid + " not found!");
43+
} else if (x.status === 403) {
44+
throw new BmaPermissionError("No permission for file UUID " + file_uuid + "!");
45+
} else {
46+
throw new BmaApiError("BMA API returned unexpected x code " + x.status);
47+
}
48+
}
49+
return x.json()
50+
})
51+
.then((x) => ({[file_uuid]: x['bma_response']}))
52+
.catch((response) => {
53+
console.log(response);
54+
});
55+
return response
56+
}
57+
58+
async function getAlbumMetadata(album_uuid) {
59+
const response = fetch("//" + host + "/api/v1/json/albums/" + album_uuid + "/", {mode: 'cors'})
60+
.then((response) => {
61+
if (!response.ok) {
62+
// handle non-2xx response code
63+
if (response.status === 404) {
64+
throw new BmaNotFoundError("Album UUID " + album_uuid + " not found!");
65+
} else if (response.status === 403) {
66+
throw new BmaPermissionError("No permission for album UUID " + album_uuid + "!");
67+
} else {
68+
throw new BmaApiError("BMA API returned unexpected response code " + response.status);
69+
}
70+
}
71+
return response.json();
72+
})
73+
.then((data) => data["bma_response"])
74+
.catch((response) => {
75+
console.log(response);
76+
});
77+
return response;
78+
}
79+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{% load static %}
2+
{% load django_bootstrap5 %}
3+
{% load django_htmx %}
4+
{% load bma_utils %}
5+
<!DOCTYPE html>
6+
<html lang="en">
7+
<head>
8+
<meta charset="utf-8">
9+
<meta name="viewport" content="width=device-width, initial-scale=1">
10+
<title>{% block title %}Untitled page{% endblock %} - BornHack Media Archive</title>
11+
12+
<!-- Bootstrap CSS -->
13+
{% bootstrap_css %}
14+
15+
<!-- FontAwesome CSS -->
16+
<link href="{% static 'fontawesomefree/css/fontawesome.css' %}" rel="stylesheet" type="text/css">
17+
<link href="{% static 'fontawesomefree/css/brands.css' %}" rel="stylesheet" type="text/css">
18+
<link href="{% static 'fontawesomefree/css/solid.css' %}" rel="stylesheet" type="text/css">
19+
20+
<!-- Custom stylesheets -->
21+
<link href="{% static "css/bma.css" %}" rel="stylesheet">
22+
23+
<!-- jQuery -->
24+
<script src="{% static "js/vendor/jquery-3.6.0.min.js" %}"></script>
25+
26+
<!-- bootstrap JS -->
27+
{% bootstrap_javascript %}
28+
29+
<!-- Custom javascript -->
30+
<script src="{% static "js/bma.js" %}" defer></script>
31+
32+
<!-- BMA version -->
33+
{{ bma_version|json_script:"bma-version" }}
34+
35+
{% block extra_head %}{% endblock %}
36+
</head>
37+
38+
<body class="d-flex flex-column min-vh-100 bma-no-js {% block body-extra-classes %}{% endblock %}">
39+
{% block body %}
40+
<main class="flex-shrink-0">
41+
<div class="container-fluid">
42+
{% bootstrap_messages %}
43+
<!-- Begin page content -->
44+
{% block main_content %}
45+
<p class="lead">This is the default content of the block 'body' in the iframe.html template of the BMA widget. Please replace in templates inheriting from iframe.html</p>
46+
{% endblock main_content %}
47+
</div>
48+
</main>
49+
{% endblock body %}
50+
</body>
51+
</html>
52+

0 commit comments

Comments
 (0)