+
${file.title}`;
+
+ caption += `
${file.attribution}`;
+ caption += `
${createLicenseIcon(file.license)} ${file.license_name}`;
+ if (file.description)
+ caption += `
${file.description}`;
+ if (file.filetype === "image" && file.exif) {
+ if (file.exif.Image) {
+ if (file.exif.Image.Make && file.exif.Image.Model)
+ caption += `
${file.exif.Image.Make} ${file.exif.Image.Model}`;
+ }
+ if (file.exif.EXIF) {
+ if (file.exif.EXIF.LensModel)
+ caption += `
${file.exif.EXIF.LensModel}`
+ if (file.exif.EXIF.FocalLength)
+ caption += `
${file.exif.EXIF.FocalLength}mm`;
+
+ if (file.exif.EXIF.ExposureTime)
+ caption += `
${file.exif.EXIF.ExposureTime} s`;
+
+ if (file.exif.EXIF.ISOSpeedRatings)
+ caption += `
ISO ${file.exif.EXIF.ISOSpeedRatings}`;
+
+ if (file.exif.EXIF.FNumber)
+ caption += `
${file.exif.EXIF.FNumber}`;
+
+ if (file.exif.EXIF.Orientation)
+ caption += `
${file.exif.EXIF.Orientation}`;
+
+ if (file.exif.EXIF.DateTimeOriginal) {
+ caption += `
${file.exif.EXIF.DateTimeOriginal}`;
+ }
+
+ }
+ }
+ caption += "
";
+ return caption;
+ }
+
+ /**
+ * Creates license icon
+ * @param {string} license - License name
+ * @returns {string}
+ */
+ function createLicenseIcon(license) {
+ switch(license) {
+ case "CC_ZERO_1_0":
+ return '`;
+ // begin thumbnail photoswipe
+ // loop over files and add photoswipe slides
+ for (const [_fileid, metadata] of Object.entries(files)) {
+ if (metadata)
+ photoswipe_main_div.querySelector("div").innerHTML += createThumbnailPswp(metadata);
+ };
+ //Show message if there are no files to display
+ if (Object.entries(files).length === 0)
+ photoswipe_main_div.querySelector("div").innerHTML = "Sorry no files to display";
+ // closing divs and ul elements are added automatically,
+ // just add the photoswipe to DOM right where the embed was made
+ main_loader.remove();
+ bma_script.parentElement.insertBefore(photoswipe_main_div, bma_script);
+ }
+
+ async function init() {
+ // figure out which file(s) to show
+ const files = JSON.parse(templateFiles).reduce((acc, t) => {
+ acc[t.uuid] = t;
+ return acc;
+ }, {});
+ await createPhotoswipe(files);
+ }
+})()
diff --git a/src/widgets/templates/splide.js b/src/widgets/templates/splide.js
index f49b6288..f25ec07a 100644
--- a/src/widgets/templates/splide.js
+++ b/src/widgets/templates/splide.js
@@ -1,207 +1,126 @@
{% load static %}
(async function(){
- // config (rendered serverside)
- const uuid = "{{ uuid }}";
- const host = "{{ host }}";
- const count = "{{ count }}";
-
- // custom error class
- class BmaNotFoundError extends Error {
- constructor(message) {
- super(message);
- this.name = "BmaNotFoundError";
- }
- }
- class BmaApiError extends Error {
- constructor(message) {
- super(message);
- this.name = "BmaApiError";
- }
- }
- class BmaPermissionError extends Error {
- constructor(message) {
- super(message);
- this.name = "BmaPermissionError";
- }
+ {% include "includes/base.js" %}
+
+ // load splide css and js, which in turn calls init() when it is done loading
+ loadSplide();
+
+ async function loadSplide() {
+ // load splide JS
+ let splide_script = document.createElement('script');
+ splide_script.src = '//' + host + '{% static "js/vendor/splide-v4.1.3.min.js" %}';
+ splide_script.addEventListener("load", () => {
+ init();
+ });
+ document.head.appendChild(splide_script);
+
+ // load splide CSS
+ let splide_css = document.createElement( "link" );
+ splide_css.href = "//" + host + "{% static 'css/vendor/splide-sea-green-v4.1.3.min.css' %}";
+ splide_css.type = "text/css";
+ splide_css.rel = "stylesheet";
+ splide_css.media = "screen,print";
+ document.head.appendChild(splide_css);
+
+ // load custom css
+ let custom_css = document.createElement( "link" );
+ custom_css.href = "//" + host + "{% static 'css/splide-custom.css' %}";
+ custom_css.type = "text/css";
+ custom_css.rel = "stylesheet";
+ custom_css.media = "screen,print";
+ document.head.appendChild(custom_css);
+ }
+
+ async function createSplide(files) {
+ const splide_main_div = document.createElement('div');
+ const splide_thumb_ul = document.createElement("ul");
+ const splide_main_id = "splide-" + count + "-main";
+ const splide_thumb_id = "splide-" + count + "-thumb";
+
+ // begin main splide
+ splide_main_div.innerHTML = '
';
+ // begin thumbnail splide
+ splide_thumb_ul.setAttribute("id", splide_thumb_id);
+ splide_thumb_ul.className = "splide-thumbnails";
+ // loop over files and add splide slides
+ for (const [fileid, metadata] of Object.entries(files)) {
+ // get URLs from metadata
+ let urls = metadata["links"]["downloads"][metadata["aspect_ratio"]];
+ let srcset = "";
+ for (const [size, url] of Object.entries(urls)) {
+ const sizes = size.split("*");
+ srcset = srcset + "//" + host + url + " " + sizes[0] + "w, ";
+ }
+ let thumburl = metadata["links"]["thumbnails"]["1"]["200*200"];
+ // create metadata table
+ let tbl = '';
+
+ // add slide li to splide__list ul
+ splide_main_div.querySelector("div > div > ul").innerHTML += '' + tbl + '
';
+ // add thumbnail for this file
+ splide_thumb_ul.innerHTML += '';
+ };
+ //Show message if there are no files to display
+ if (Object.entries(files).length === 0)
+ splide_main_div.innerHTML = "Sorry no files to display";
+ // closing divs and ul elements are added automatically,
+ // just add the splide to DOM right where the embed was made
+ main_loader.remove();
+ bma_script.parentElement.insertBefore(splide_main_div, bma_script);
+ bma_script.parentElement.insertBefore(splide_thumb_ul, bma_script);
+
+ // create main splide
+ var splide = new Splide( '#' + splide_main_id, {
+ pagination: false,
+ })
+
+ async function initThumbnail( thumbnail, index ) {
+ thumbnail.addEventListener( 'click', function () {
+ splide.go( index );
+ } );
}
- // A reference to the currently running script
- const bma_script = document.scripts[document.scripts.length - 1];
-
- // load splide css and js, which in turn calls init() when it is done loading
- loadSplide();
-
- async function loadSplide() {
- // load splide JS
- let splide_script = document.createElement('script');
- splide_script.src = '//' + host + '{% static "js/vendor/splide-v4.1.3.min.js" %}';
- splide_script.addEventListener("load", () => {
- init();
- });
- document.head.appendChild(splide_script);
-
- // load splide CSS
- let splide_css = document.createElement( "link" );
- splide_css.href = "//" + host + "{% static 'css/vendor/splide-sea-green-v4.1.3.min.css' %}";
- splide_css.type = "text/css";
- splide_css.rel = "stylesheet";
- splide_css.media = "screen,print";
- document.head.appendChild(splide_css);
-
- // load custom css
- let custom_css = document.createElement( "link" );
- custom_css.href = "//" + host + "{% static 'css/splide-custom.css' %}";
- custom_css.type = "text/css";
- custom_css.rel = "stylesheet";
- custom_css.media = "screen,print";
- document.head.appendChild(custom_css);
+ // get thumbnails
+ thumbnails = splide_thumb_ul.querySelectorAll("li");
+ for ( var i = 0; i < thumbnails.length; i++ ) {
+ initThumbnail( thumbnails[ i ], i );
}
+ var current; // Keeps the current thumbnail
- async function getFileMetadata(file_uuid) {
- const response = await fetch("//" + host + "/api/v1/json/files/" + file_uuid + "/", {mode: 'cors'});
- if (!response.ok) {
- // handle non-2xx response code
- if (response.status === 404) {
- throw new BmaNotFoundError("File UUID " + file_uuid + " not found!");
- } else if (response.status === 403) {
- throw new BmaPermissionError("No permission for file UUID " + file_uuid + "!");
- } else {
- throw new BmaApiError("BMA API returned unexpected response code " + response.status);
- }
- }
- const data = await response.json();
- const file = data["bma_response"];
- return {[file_uuid]: file};
- }
+ splide.on( 'mounted move', function () {
+ if ( current ) {
+ current.classList.remove( 'is-active' );
+ }
- async function getAlbumMetadata(album_uuid) {
- let result = {};
- const response = await fetch("//" + host + "/api/v1/json/albums/" + album_uuid + "/", {mode: 'cors'});
- if (!response.ok) {
- // handle non-2xx response code
- if (response.status === 404) {
- throw new BmaNotFoundError("Album UUID " + album_uuid + " not found!");
- } else if (response.status === 403) {
- throw new BmaPermissionError("No permission for album UUID " + album_uuid + "!");
- } else {
- throw new BmaApiError("BMA API returned unexpected response code " + response.status);
- }
- }
- const data = await response.json();
- const album = data["bma_response"];
- for (file of album["files"]) {
- metadata = await getFileMetadata(file);
- result[file] = metadata[file];
- }
- return result;
- }
+ // Splide#index returns the latest slide index:
+ var thumbnail = thumbnails[ splide.index ];
- async function createSplide(files) {
- const splide_main_div = document.createElement('div');
- const splide_thumb_ul = document.createElement("ul");
- const splide_main_id = "splide-" + count + "-main";
- const splide_thumb_id = "splide-" + count + "-thumb";
-
- // begin main splide
- splide_main_div.innerHTML = '';
- // begin thumbnail splide
- splide_thumb_ul.setAttribute("id", splide_thumb_id);
- splide_thumb_ul.className = "splide-thumbnails";
- // loop over files and add splide slides
- for (const [fileid, metadata] of Object.entries(files)) {
- // get URLs from metadata
- let urls = metadata["links"]["downloads"][metadata["aspect_ratio"]];
- let srcset = "";
- for (const [size, url] of Object.entries(urls)) {
- const sizes = size.split("*");
- srcset = srcset + "//" + host + url + " " + sizes[0] + "w, ";
- }
- let thumburl = metadata["links"]["thumbnails"]["1"]["200*200"];
- // create metadata table
- let tbl = '';
-
- // add slide li to splide__list ul
- splide_main_div.querySelector("div > div > ul").innerHTML += '' + tbl + '
';
- // add thumbnail for this file
- splide_thumb_ul.innerHTML += '';
- };
- // closing divs and ul elements are added automatically,
- // just add the splide to DOM right where the embed was made
- bma_script.parentElement.insertBefore(splide_main_div, bma_script);
- bma_script.parentElement.insertBefore(splide_thumb_ul, bma_script);
-
- // create main splide
- var splide = new Splide( '#' + splide_main_id, {
- pagination: false,
- })
-
- async function initThumbnail( thumbnail, index ) {
- thumbnail.addEventListener( 'click', function () {
- splide.go( index );
- } );
- }
-
- // get thumbnails
- thumbnails = splide_thumb_ul.querySelectorAll("li");
- for ( var i = 0; i < thumbnails.length; i++ ) {
- initThumbnail( thumbnails[ i ], i );
- }
- var current; // Keeps the current thumbnail
-
- splide.on( 'mounted move', function () {
- if ( current ) {
- current.classList.remove( 'is-active' );
- }
-
- // Splide#index returns the latest slide index:
- var thumbnail = thumbnails[ splide.index ];
-
- if ( thumbnail ) {
- thumbnail.classList.add( 'is-active' );
- current = thumbnail;
- }
- });
-
- // ready to mount
- splide.mount();
+ if ( thumbnail ) {
+ thumbnail.classList.add( 'is-active' );
+ current = thumbnail;
+ }
+ });
- }
+ // ready to mount
+ splide.mount();
- async function init() {
- // figure out which file(s) to show
- let files = {};
-
- // is this uuid a file?
- try {
- files = await getFileMetadata(uuid);
- } catch (error) {
- if (!error instanceof BmaNotFoundError) {
- // API returned an error other than 404
- console.error("BMA API returned an error: ", error);
- return;
- }
- }
-
- // is this uuid an album?
- if (!(uuid in files)) {
- // check if the uuid is an album
- try {
- files = await getAlbumMetadata(uuid);
- } catch (error) {
- // API returned an error
- console.error("BMA API returned an error: ", error);
- return;
- }
- }
-
- // ready
- await createSplide(files);
- }
+ }
+
+ async function init() {
+ // figure out which file(s) to show
+ const files = JSON.parse(templateFiles).reduce((acc, t) => {
+ acc[t.uuid] = t;
+ return acc;
+ }, {});
+
+ // ready
+ await createSplide(files);
+ }
})()
diff --git a/src/widgets/urls.py b/src/widgets/urls.py
index 5e1613f1..a54aa0c3 100644
--- a/src/widgets/urls.py
+++ b/src/widgets/urls.py
@@ -2,6 +2,7 @@
from django.urls import path
+from .views import bma_widget_iframe_view
from .views import bma_widget_view
from .views import picture_embed_view
@@ -9,5 +10,6 @@
urlpatterns = [
path("picture//", picture_embed_view, name="picture_embed_view"),
+ path("iframe////", bma_widget_iframe_view),
path("///", bma_widget_view),
]
diff --git a/src/widgets/views.py b/src/widgets/views.py
index b95385b4..04acd42e 100644
--- a/src/widgets/views.py
+++ b/src/widgets/views.py
@@ -1,5 +1,6 @@
"""Widget related views."""
+import json
import uuid
from django.http import HttpRequest
@@ -7,19 +8,84 @@
from django.shortcuts import get_object_or_404
from django.shortcuts import render
+from albums.models import Album
+from files.models import BaseFile
from images.models import Image
+def serialise_basefile(file: BaseFile) -> dict[str, int | str | dict[str, str | dict[str, str]]]:
+ """Serialise a BaseFile object into a JSON-serialisable dictionary."""
+ json_data = {
+ "uuid": str(file.uuid),
+ "title": file.title,
+ "description": file.description,
+ "links": file.resolve_links(),
+ "filename": file.filename,
+ "filetype": file.filetype,
+ "filetype_icon": file.filetype_icon,
+ "license": file.license,
+ "license_name": file.license_name,
+ "license_url": file.license_url,
+ "attribution": file.attribution,
+ "source": file.source,
+ }
+ if file.filetype == "image":
+ json_data.update(
+ {
+ "aspect_ratio": file.aspect_ratio,
+ "exif": file.exif,
+ "width": file.width,
+ "height": file.height,
+ }
+ )
+ return json_data
+
+
def bma_widget_view(request: HttpRequest, style: str, count: int, uuid: str) -> HttpResponse:
"""Render a BMA widget rendered with the requested style, counter and UUID."""
+ js_files = []
+ try:
+ album = Album.bmanager.get(pk=uuid)
+ js_files = [serialise_basefile(file) for file in album.active_files_list if file.permitted(user=request.user)]
+ except Album.DoesNotExist:
+ try:
+ file = BaseFile.bmanager.get(uuid=uuid)
+ if file.permitted(user=request.user):
+ js_files.append(serialise_basefile(file))
+ except BaseFile.DoesNotExist:
+ pass
+
return render(
request,
f"{style}.js",
- context={"uuid": uuid, "count": count, "host": request.get_host()},
+ context={"uuid": uuid, "files": json.dumps(js_files), "count": count, "host": request.get_host()},
content_type="text/javascript",
)
+def bma_widget_iframe_view(request: HttpRequest, style: str, option: int, uuid: str) -> HttpResponse:
+ """Render a BMA iframe widget rendered with the requested style, counter and UUID."""
+ js_files = []
+ try:
+ album = Album.bmanager.get(pk=uuid)
+ js_files = BaseFile.bmanager.filter(
+ uuid__in=[f.uuid for f in album.active_files_list if f.permitted(user=request.user)]
+ )
+ except Album.DoesNotExist:
+ try:
+ file = BaseFile.bmanager.get(uuid=uuid)
+ if file.permitted(user=request.user):
+ js_files.append(serialise_basefile(file))
+ except BaseFile.DoesNotExist:
+ pass
+
+ return render(
+ request,
+ f"{style}.html",
+ context={"uuid": uuid, "files": js_files, "option": option, "host": request.get_host()},
+ )
+
+
def picture_embed_view(request: HttpRequest, image_uuid: uuid.UUID) -> HttpResponse:
"""Return a