Compare commits

..

1 commit

Author SHA1 Message Date
Sanjay Bhangar
76d96e76fe generate title for non-content pages randomly from acronym table 2025-03-27 15:10:34 +05:30
15 changed files with 1967 additions and 368 deletions

View file

@ -78,6 +78,7 @@ TEMPLATES = [
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.template.context_processors.media', 'django.template.context_processors.media',
'content.context_processors.random_title',
], ],
'loaders': [ 'loaders': [
'django.template.loaders.filesystem.Loader', 'django.template.loaders.filesystem.Loader',

View file

@ -0,0 +1,170 @@
/** VARIABLES
===================================*/
/** RESET AND LAYOUT
===================================*/
.bx-wrapper {
position: relative;
margin-bottom: 60px;
padding: 0;
*zoom: 1;
-ms-touch-action: pan-y;
touch-action: pan-y;
}
.bx-wrapper img {
max-width: 100%;
display: block;
}
.bxslider {
margin: 0;
padding: 0;
}
ul.bxslider {
list-style: none;
}
.bx-viewport {
/*fix other elements on the page moving (on Chrome)*/
-webkit-transform: translatez(0);
}
/** THEME
===================================*/
.bx-wrapper .bx-pager,
.bx-wrapper .bx-controls-auto {
position: absolute;
bottom: -30px;
width: 100%;
}
/* LOADER */
.bx-wrapper .bx-loading {
min-height: 50px;
height: auto;
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 2000;
}
/* PAGER */
.bx-wrapper .bx-pager {
text-align: center;
font-size: .85em;
font-family: Arial;
font-weight: bold;
color: #666;
padding-top: 20px;
}
.bx-wrapper .bx-pager.bx-default-pager a {
background: #666;
text-indent: -9999px;
display: block;
width: 10px;
height: 10px;
margin: 0 5px;
outline: 0;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.bx-wrapper .bx-pager.bx-default-pager a:hover,
.bx-wrapper .bx-pager.bx-default-pager a.active,
.bx-wrapper .bx-pager.bx-default-pager a:focus {
background: #000;
}
.bx-wrapper .bx-pager-item,
.bx-wrapper .bx-controls-auto .bx-controls-auto-item {
display: inline-block;
vertical-align: bottom;
*zoom: 1;
*display: inline;
}
.bx-wrapper .bx-pager-item {
font-size: 0;
line-height: 0;
}
/* DIRECTION CONTROLS (NEXT / PREV) */
.bx-wrapper .bx-prev {
left: 10px;
background: url('controls.png') no-repeat 0 -32px;
}
.bx-wrapper .bx-prev:hover,
.bx-wrapper .bx-prev:focus {
background-position: 0 0;
}
.bx-wrapper .bx-next {
right: 30px;
background: url('controls.png') no-repeat -43px -32px;
}
.bx-wrapper .bx-next:hover,
.bx-wrapper .bx-next:focus {
background-position: -43px 0;
}
.bx-wrapper .bx-controls-direction a {
position: absolute;
top: 50%;
margin-top: -16px;
outline: 0;
width: 32px;
height: 32px;
text-indent: -9999px;
z-index: 9999;
}
.bx-wrapper .bx-controls-direction a.disabled {
display: none;
}
/* AUTO CONTROLS (START / STOP) */
.bx-wrapper .bx-controls-auto {
text-align: center;
}
.bx-wrapper .bx-controls-auto .bx-start {
display: block;
text-indent: -9999px;
width: 10px;
height: 11px;
outline: 0;
background: url('images/controls.png') -86px -11px no-repeat;
margin: 0 3px;
}
.bx-wrapper .bx-controls-auto .bx-start:hover,
.bx-wrapper .bx-controls-auto .bx-start.active,
.bx-wrapper .bx-controls-auto .bx-start:focus {
background-position: -86px 0;
}
.bx-wrapper .bx-controls-auto .bx-stop {
display: block;
text-indent: -9999px;
width: 9px;
height: 11px;
outline: 0;
background: url('images/controls.png') -86px -44px no-repeat;
margin: 0 3px;
}
.bx-wrapper .bx-controls-auto .bx-stop:hover,
.bx-wrapper .bx-controls-auto .bx-stop.active,
.bx-wrapper .bx-controls-auto .bx-stop:focus {
background-position: -86px -33px;
}
/* PAGER WITH AUTO-CONTROLS HYBRID LAYOUT */
.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager {
text-align: left;
width: 80%;
}
.bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto {
right: 0;
width: 35px;
}
/* IMAGE CAPTIONS */
.bx-wrapper .bx-caption {
position: absolute;
bottom: 0;
left: 0;
background: #666;
background: rgba(80, 80, 80, 0.75);
width: 100%;
}
.bx-wrapper .bx-caption span {
color: #fff;
font-family: Arial;
display: block;
font-size: .85em;
padding: 10px;
}

View file

@ -58,11 +58,6 @@ a:focus, a:hover {
padding-left: 0em !important; padding-left: 0em !important;
padding-top: 10px; /* moved below search bar */ padding-top: 10px; /* moved below search bar */
} }
@media screen and (max-width: 39.9375em) {
.special-column {
padding-right: 0;
}
}
.index-text { .index-text {
padding-left: 3%; padding-left: 3%;

View file

@ -1,9 +1,4 @@
.gallery-dialog { .gallery-dialog {
background: #282828;
overflow: hidden;
border: 1px solid black;
}
.gallery-dialog, .gallery-main-stage {
&:open { &:open {
background: #282828; background: #282828;
width: 100%; width: 100%;
@ -27,13 +22,11 @@
height: calc(100vh - 180px); height: calc(100vh - 180px);
} }
@media screen and (max-width: 39.9375em) { @media screen and (max-width: 39.9375em) {
&:open {
overflow: auto;
}
.photo-container .image { .photo-container .image {
height: auto; height: auto;
width: 100%; width: 100%;
} }
} }
.main-image { .main-image {
width: 100%; width: 100%;
@ -42,20 +35,15 @@
} }
.caption { .caption {
margin: 10px 0; margin: 10px 0;
font-size: 14px; font-size: 18px;
color: lightgray; color: lightgray;
text-align: center; text-align: center;
} }
.thumbnails { .thumbnails {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 10px;
overflow: auto;
}
@media screen and (max-width: 39.9375em) {
.thumbnails {
flex-wrap: wrap; flex-wrap: wrap;
} margin-top: 10px;
} }
.thumbnail { .thumbnail {
width: 80px; width: 80px;
@ -64,6 +52,9 @@
cursor: pointer; cursor: pointer;
border: 2px solid transparent; border: 2px solid transparent;
} }
.thumbnail.active {
border-color: blue;
}
.nav-btn { .nav-btn {
cursor: pointer; cursor: pointer;
font-size: 20px; font-size: 20px;
@ -93,8 +84,7 @@
.close:hover { .close:hover {
color: white !important; color: white !important;
} }
.download.disabled, .download.disabled {
.edit.disabled {
display: none; display: none;
} }
.download { .download {
@ -105,15 +95,7 @@
right: 24px right: 24px
} }
.edit { .download:hover {
color: lightgray !important;
cursor: pointer;
position: absolute;
top: 4px;
left: 4px
}
.download:hover,
.edit:hover {
color: white !important; color: white !important;
} }
@media screen and (max-width: 39.9375em) { @media screen and (max-width: 39.9375em) {
@ -140,60 +122,3 @@
} }
} }
.gallery-main-stage {
.photo-container .image {
height: auto;
}
.download {
right: 4px
}
@media screen and (max-width: 39.9375em) {
.download {
}
}
}
.gallery-dialog, .inline-gallery {
.thumbnail {
cursor: pointer;
border: 2px solid transparent;
}
.thumbnail.active {
cursor: initial;
border-color: #1779ba;
}
}
.inline-photo {
display: inline-block;
.caption {
display: none;
}
.photo {
scroll-margin-top: 12px;
}
}
.inline {
margin-left: -12px;
width: 100vw;
li {
padding: 0;
}
.inline-photo {
display: block;
.caption {
display: block;
color: #ffffff;
padding-left: 2px;
padding-right: 2px;
p {
margin-bottom: 0;
}
}
}
}
@media screen and (max-width: 39.9375em) {
.gallery {
}
}

View file

@ -1,34 +1,9 @@
function isNumber(x) {
return parseFloat(x) == x
};
function isMobile() {
return getComputedStyle(document.querySelector('.special-column')).paddingRight == '0px'
}
function isInView(el) {
var rect = el.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
// Only completely visible elements return true:
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
// Partially visible elements return true:
//isVisible = elemTop < window.innerHeight && elemBottom >= 0;
return isVisible;
}
function parseGalleryHash() { function parseGalleryHash() {
let parts = document.location.hash.slice(1).split('/') let parts = document.location.hash.slice(1).split('/')
if (parts.lengh == 1 && isNumber(parts[0])) { if (parts[0] == 'g') {
return { return {
'gallery': 'inline', "gallery": parseInt(parts[1], 10),
"image": parseInt(parts[0], 10) - 1, "image": parseInt(parts[2], 10),
}
} else if (parts.length == 2 && isNumber(parts[0]) && isNumber(parts[1])) {
return {
"gallery": parseInt(parts[0], 10) - 1,
"image": parseInt(parts[1], 10) - 1,
} }
} }
return {} return {}
@ -36,38 +11,9 @@ function parseGalleryHash() {
function loadGalleries() { function loadGalleries() {
let current = parseGalleryHash() let current = parseGalleryHash()
let galleryIdx = 0 let galleryIdx = 1
document.querySelectorAll('.gallery').forEach(gallery => { document.querySelectorAll('.gallery').forEach(gallery => {
var photos = [], dialog var photos = [], dialog
gallery.querySelectorAll(".photo").forEach(img => {
const src = img.src.replace('_thumbnail', '_display')
let photo = {
src: src,
caption: img.dataset.caption,
orig: img.dataset.orig,
edit: img.dataset.edit
}
photos.push(photo)
img.parentElement.href = `#${galleryIdx+1}/${photos.length}`
img.parentElement.addEventListener("click", event => {
event.preventDefault()
event.stopPropagation()
dialog.open(src, -1, event)
})
})
if (isMobile()) {
dialog = loadInlineGallery(photos, galleryIdx, null, gallery)
} else {
dialog = loadGallery(photos, galleryIdx, null, gallery)
}
dialog.element && gallery.appendChild(dialog.element)
if (current.gallery == galleryIdx) {
dialog.open(undefined, current.image)
}
galleryIdx += 1
})
document.querySelectorAll('.inline-gallery').forEach(gallery => {
var photos = [], stage
gallery.querySelectorAll(".photo").forEach(img => { gallery.querySelectorAll(".photo").forEach(img => {
const src = img.src.replace('_thumbnail', '_display') const src = img.src.replace('_thumbnail', '_display')
let photo = { let photo = {
@ -79,86 +25,20 @@ function loadGalleries() {
img.parentElement.addEventListener("click", event => { img.parentElement.addEventListener("click", event => {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
dialog.open(src, -1, event) dialog.open(src)
}) })
}) })
const main = document.querySelector('.gallery-main-stage') dialog = loadGallery(photos, galleryIdx)
stage = loadGallery(photos, 'inline', main, gallery) gallery.appendChild(dialog.element)
if (current.gallery == galleryIdx) {
dialog.open(undefined, current.image)
}
galleryIdx += 1
}) })
} }
function loadInlineGallery(images, idx, main, thumbnails) { function loadGallery(images, idx) {
thumbnails.querySelectorAll('.photo').forEach(img => { var gallery = document.createElement("dialog")
const container = document.createElement('div')
container.classList.add("inline-photo")
container.innerHTML = `
<img class="photo" src="${img.src}">
<div class="caption">${img.dataset.caption||''}</div>
`
img.replaceWith(container)
})
function scroll(event) {
let found = false
let index = 0
thumbnails.querySelectorAll('.photo').forEach(img => {
if (!found) {
if (isInView(img)) {
found = true
const hash = `#${idx + 1}/${index + 1}`
if (document.location.hash != hash) {
document.location.hash = hash
}
}
}
index += 1
})
/*
// fixme this jumps don't do it
if (!found && document.location.hash.slice(1).length) {
document.location.hash = ''
}
*/
}
return {
element: null,
open: function(src, newIdx=-1, event=null) {
let img
if (newIdx != -1) {
img = thumbnails.querySelectorAll('.photo')[newIdx - 1]
}
if (thumbnails.classList.contains("inline")) {
thumbnails.classList.remove("inline");
thumbnails.querySelectorAll('.photo').forEach(img => {
img.src = img.src.replace('_display', '_thumbnail')
})
thumbnails.previousElementSibling.scrollIntoView()
window.removeEventListener("scroll", scroll)
} else {
thumbnails.classList.add("inline");
thumbnails.querySelectorAll('.photo').forEach(img => {
img.src = img.src.replace('_thumbnail', '_display')
})
setTimeout(() => {
if (img) {
img.scrollIntoView()
} else if (event && event.target) {
event.target.scrollIntoView()
}
}, 20)
window.addEventListener("scroll", scroll)
}
}
}
}
function loadGallery(images, idx, main, thumbnails) {
let gallery;
if (idx == 'inline') {
gallery = main
} else {
gallery = document.createElement("dialog")
gallery.classList.add("gallery-dialog") gallery.classList.add("gallery-dialog")
gallery.innerHTML = ` gallery.innerHTML = `
<div class="photo-container"> <div class="photo-container">
@ -169,7 +49,6 @@ function loadGallery(images, idx, main, thumbnails) {
<button class="next nav-btn">Next </button> <button class="next nav-btn">Next </button>
</div> </div>
<button class="close">&#10006;</button> <button class="close">&#10006;</button>
<a class="edit disabled" target="_blank" title="edit">&#9998;</a>
<a class="download disabled" target="_blank" download title="download original"> <a class="download disabled" target="_blank" download title="download original">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg>
</a> </a>
@ -191,19 +70,14 @@ function loadGallery(images, idx, main, thumbnails) {
gallery.close(); gallery.close();
} }
}) })
}
let currentIndex = 0; let currentIndex = 0;
const mainImage = gallery.querySelector(".main-image"); const mainImage = gallery.querySelector(".main-image");
const caption = gallery.querySelector(".caption"); const caption = gallery.querySelector(".caption");
const prevBtn = gallery.querySelector(".prev.nav-btn"); const prevBtn = gallery.querySelector(".prev.nav-btn");
const nextBtn = gallery.querySelector(".next.nav-btn"); const nextBtn = gallery.querySelector(".next.nav-btn");
const thumbnailsContainer = gallery.querySelector(".thumbnails");
const download = gallery.querySelector(".download"); const download = gallery.querySelector(".download");
const edit = gallery.querySelector(".edit");
let thumbnailsContainer
if (idx != 'inline') {
thumbnailsContainer = gallery.querySelector(".thumbnails");
}
gallery.addEventListener("keydown", event => { gallery.addEventListener("keydown", event => {
if (event.keyCode == 39) { if (event.keyCode == 39) {
@ -223,18 +97,9 @@ function loadGallery(images, idx, main, thumbnails) {
mainImage.src = images[index].src; mainImage.src = images[index].src;
}, 0) }, 0)
caption.innerHTML = images[index].caption; caption.innerHTML = images[index].caption;
if (idx == 'inline') {
thumbnails.querySelectorAll(".thumbnail").forEach((thumb, i) => {
thumb.classList.toggle("active", i === index);
});
} else {
gallery.querySelectorAll(".thumbnail").forEach((thumb, i) => { gallery.querySelectorAll(".thumbnail").forEach((thumb, i) => {
thumb.classList.toggle("active", i === index); thumb.classList.toggle("active", i === index);
}); });
if (thumbnailsContainer && !isMobile()) {
gallery.querySelector('.active').scrollIntoView()
}
}
if (images[index].orig) { if (images[index].orig) {
download.href = images[index].orig download.href = images[index].orig
download.classList.remove('disabled') download.classList.remove('disabled')
@ -242,22 +107,9 @@ function loadGallery(images, idx, main, thumbnails) {
download.href = "" download.href = ""
download.classList.add('disabled') download.classList.add('disabled')
} }
if (edit) {
if (images[index].edit) {
edit.href = images[index].edit
edit.classList.remove('disabled')
} else {
edit.href = ""
edit.classList.add('disabled')
}
}
prevBtn.disabled = index === 0; prevBtn.disabled = index === 0;
nextBtn.disabled = index === images.length - 1; nextBtn.disabled = index === images.length - 1;
if (idx == 'inline') { document.location.hash = `#g/${idx}/${index}`
document.location.hash = `#${index + 1}`
} else {
document.location.hash = `#${idx + 1}/${index + 1}`
}
} }
function createThumbnails() { function createThumbnails() {
@ -265,9 +117,7 @@ function loadGallery(images, idx, main, thumbnails) {
const thumb = document.createElement("img"); const thumb = document.createElement("img");
thumb.src = img.src.replace('_display', '_thumbnail'); thumb.src = img.src.replace('_display', '_thumbnail');
thumb.classList.add("thumbnail"); thumb.classList.add("thumbnail");
thumb.onclick = (event) => { thumb.onclick = () => {
event.preventDefault()
event.stopPropagation()
currentIndex = index; currentIndex = index;
updateGallery(index); updateGallery(index);
}; };
@ -281,8 +131,6 @@ function loadGallery(images, idx, main, thumbnails) {
} }
prevBtn.onclick = () => { prevBtn.onclick = () => {
event.preventDefault()
event.stopPropagation()
if (currentIndex > 0) { if (currentIndex > 0) {
currentIndex--; currentIndex--;
updateGallery(currentIndex); updateGallery(currentIndex);
@ -290,31 +138,29 @@ function loadGallery(images, idx, main, thumbnails) {
}; };
nextBtn.onclick = () => { nextBtn.onclick = () => {
event.preventDefault()
event.stopPropagation()
if (currentIndex < images.length - 1) { if (currentIndex < images.length - 1) {
currentIndex++; currentIndex++;
updateGallery(currentIndex); updateGallery(currentIndex);
} }
}; };
idx != 'inline' && createThumbnails(); createThumbnails();
updateGallery(currentIndex); updateGallery(currentIndex);
const imagesIndex = images.map(img => img.src); const imagesIndex = images.map(img => img.src);
return { return {
element: gallery, element: gallery,
open: function(src, newIdx=-1) { open: function(src, idx=-1) {
if (newIdx != -1) { if (idx != -1) {
currentIndex = newIdx currentIndex = idx
} else { } else {
currentIndex = imagesIndex.indexOf(src) currentIndex = imagesIndex.indexOf(src)
} }
updateGallery(currentIndex) updateGallery(currentIndex)
if (idx != 'inline') {
showGallery() showGallery()
} }
} }
} }
}
window.addEventListener("load", loadGalleries) window.addEventListener("load", loadGalleries)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
var startSlide = 0;
if (document.querySelectorAll('.select-image').length && document.location.hash.length) {
startSlide = parseInt(document.location.hash.slice(1)) - 1
}
function loadSlideshow() {
$('a.original-link').bind('touchstart MSPointerDown pointerdown', function(event) {
event.stopPropagation()
});
$('a.original-link').on({
mousedown: function(event) {
event.stopPropagation()
},
})
slider = $('.slider1').show().bxSlider({
startSlide: startSlide,
preloadImages: 'all',
adaptiveHeight : true,
pager : false,
});
var images = $('.slider1 img'), count = images.length;
images.on({load: function(event) {
setTimeout(function() {
slider.resize()
slider.redrawSlider()
}, 100)
}})
document.querySelectorAll('.select-image').forEach(function(a) {
a.onclick = function(event) {
event.preventDefault();
slider.goToSlide(parseInt(this.dataset.id) - 1)
document.location.hash = '#' + this.dataset.id;
};
});
$(document).keydown(function(e){
if (e.keyCode == 39) // Right arrow
{
slider && slider.goToNextSlide && slider.goToNextSlide();
return false;
}
else if (e.keyCode == 37) // left arrow
{
slider && slider.goToPrevSlide && slider.goToPrevSlide();
return false;
}
});
}
$(document).ready(loadSlideshow);

View file

@ -8,24 +8,16 @@
</p> </p>
<ul class="sortedm2m-items"> <ul class="sortedm2m-items">
{% for row in selected %} {% for row in selected %}
<li class="sortedm2m-item"><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row | admin_thumbnail }} <div>{{ row.option_label }}</div></label></li> <li class="sortedm2m-item"><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row | admin_thumbnail }} {{ row.option_label }}</label></li>
{% endfor %} {% endfor %}
{% for row in unselected %} {% for row in unselected %}
<li class="sortedm2m-item"><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row | admin_thumbnail }}<div>{{ row.option_label }}</div></label></li> <li class="sortedm2m-item"><label{{ row.label_for|safe }}>{{ row.rendered_cb }} {{ row | admin_thumbnail }}{{ row.option_label }}</label></li>
{% endfor %} {% endfor %}
</ul> </ul>
<p class="help"> <p class="help">
{% trans "Choose items and order by drag & drop." %} {% trans "Choose items and order by drag & drop." %}
</p> </p>
<style>
.sortedm2m-container ul label {
display: flex;
gap: 8px;
}
.sortedm2m-item > label > div {
text-wrap-mode: wrap;
}
</style>
</div> </div>

View file

@ -0,0 +1,16 @@
from .models import Acronym
import random
def random_title(request):
count = Acronym.objects.count()
random_c = random.randint(1, count)
random_a = random.randint(1, count)
random_m = random.randint(1, count)
random_p = random.randint(1, count)
c = Acronym.objects.all()[random_c].c
a = Acronym.objects.all()[random_a].a
m = Acronym.objects.all()[random_m].m
p = Acronym.objects.all()[random_p].p
return {
'RANDOM_TITLE': f"{c} {a} {m} {p}"
}

View file

@ -200,8 +200,7 @@ class Content(models.Model):
if self.photo and self.photo.image.url.endswith('.gif'): if self.photo and self.photo.image.url.endswith('.gif'):
video_path = self.photo.image.path.replace('.gif', '.mp4') video_path = self.photo.image.path.replace('.gif', '.mp4')
image_path = self.photo.image.path.replace('.gif', '.jpg') image_path = self.photo.image.path.replace('.gif', '.jpg')
if os.path.exists(self.photo.image.path): if os.path.exists(self.photo.image.path) and not os.path.exists(video_path):
if not os.path.exists(video_path):
height = self.photo.image.height height = self.photo.image.height
if height % 2: if height % 2:
height += 1 height += 1

View file

@ -6,10 +6,11 @@
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% block head %} {% block head %}
<title>CAMP</title> <title>CAMP: {{ RANDOM_TITLE }}</title>
{% endblock %} {% endblock %}
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans"/> <link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans"/>
<link rel="stylesheet" type="text/css" href="{% static "css/foundation.css" %}?20250201"> <link rel="stylesheet" type="text/css" href="{% static "css/foundation.css" %}?20250201">
<link rel="stylesheet" type="text/css" href="{% static "css/jquery.bxslider.css" %}">
{% compress css file site %} {% compress css file site %}
<link rel="stylesheet" type="text/css" href="{% static "css/main.css" %}"> <link rel="stylesheet" type="text/css" href="{% static "css/main.css" %}">
<link rel="stylesheet" type="text/css" href="{% static "css/app.css" %}"> <link rel="stylesheet" type="text/css" href="{% static "css/app.css" %}">
@ -46,12 +47,16 @@
{% block content %} {% block content %}
{% endblock %} {% endblock %}
{}
<script src="{% static "js/jquery.js" %}"></script> <script src="{% static "js/jquery.js" %}"></script>
<script src="{% static "js/foundation.js" %}"></script> <script src="{% static "js/foundation.js" %}"></script>
{% compress js file base %} {% compress js file base %}
<script src="{% static "js/app.js" %}"></script> <script src="{% static "js/app.js" %}"></script>
<script src="{% static "js/what-input.js" %}"></script> <script src="{% static "js/what-input.js" %}"></script>
<script src="{% static "js/jquery.bxslider.js" %}?2"></script>
<script src="{% static "js/gallery.js" %}"></script> <script src="{% static "js/gallery.js" %}"></script>
<script src="{% static "js/slideshow.js" %}"></script>
{% endcompress %} {% endcompress %}
{% block end %} {% block end %}
{% endblock %} {% endblock %}

View file

@ -2,12 +2,7 @@
<h6><strong>{{gallery.title}}</strong></h6> <h6><strong>{{gallery.title}}</strong></h6>
<ul class="clearing-thumbs gallery" data-clearing> <ul class="clearing-thumbs gallery" data-clearing>
{% for photo in gallery.public %} {% for photo in gallery.public %}
<li><a href="{{ gallery.get_absolute_url }}#{{forloop.counter}}"><img src="{{ photo.get_thumbnail_url }}" <li><a href="{{ gallery.get_absolute_url }}#{{forloop.counter}}"><img src="{{ photo.get_thumbnail_url }}" class="photo" data-caption="{{ photo.caption_html }}"{% if request.user.is_staff %} data-orig="{{ photo.image.url }}"{% endif %}></a></li>
class="photo"
data-caption="{{ photo.caption_html }}"
{% if request.user.is_staff %}data-orig="{{ photo.image.url }}"{% endif %}
{% if request.user.is_staff %}data-edit="{{ photo.edit_url }}"{% endif %}
></a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View file

@ -10,34 +10,33 @@
<h6 class="page-header"><a href="{{ gallery.content.all.0.get_absolute_url }}">Back to {{ gallery.content.all.0.title }}</a></h6> <h6 class="page-header"><a href="{{ gallery.content.all.0.get_absolute_url }}">Back to {{ gallery.content.all.0.title }}</a></h6>
{% endif %} {% endif %}
<h5>{{ gallery.title }}</h5> <h5>{{ gallery.title }}</h5>
{% with gallery.public.0 as photo %} <ul class="slider1">
<div class="gallery-main-stage"> {% for photo in gallery.public %}
<div class="photo-container"> <li id="slide-{{photo.slug}}">
<div class="image"> <img src="{{ photo.get_display_url }}" alt="{{ photo.title }}" loading="lazy">
<img src="{{ photo.get_display_url }}" alt="{{ photo.title }}" class="main-image" alt="{{ photo.title }}"> <p>
</div> {{ photo.caption|safe }}
<button class="prev nav-btn"> Prev</button> {% if photo.caption %}<br>{%endif%}
<button class="next nav-btn">Next </button> {% if request.user.is_staff %}<a href="{{ photo.image.url }}" class="original-link" target="_blank" >Link to original file</a>{% endif %}
<a class="download disabled" target="_blank" download title="download original"> </p>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg>
</a> </li>
</div> {% endfor %}
<div class="caption">{{ photo.caption_html }}</div> </ul>
</div>
{% endwith %}
</div> </div>
<div class="medium-3 columns"> <div class="medium-3 columns">
<br> <br>
<p>{% trans "Other photos" %}:</p> <p>{% trans "Other photos" %}:</p>
<div class="inline-gallery"> <div>
{% for photo in gallery.public %} {% for photo in gallery.public %}
<div style="float: left; padding: 4px"> <div style="float: left; padding: 4px">
<a href="{{ gallery.get_absolute_url }}#{{forloop.counter}}"> <a href="{{ photo.get_absolute_url }}" class="select-image" data-id="{{forloop.counter}}">
<img src="{{ photo.get_thumbnail_url }}" class="thumbnail photo" alt="{{ photo.title }}" data-caption="{{ photo.caption_html }}"{% if request.user.is_staff %} data-orig="{{ photo.image.url }}"{% endif %}> <img src="{{ photo.get_thumbnail_url }}" class="thumbnail" alt="{{ photo.title }}">
</a> </a>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -8,7 +8,7 @@
<div class="medium-9 columns"> <div class="medium-9 columns">
<img src="{{ object.get_display_url }}" alt="{{ object.title }}"> <img src="{{ object.get_display_url }}" alt="{{ object.title }}">
<p> <p>
{{ object.caption_html|safe }} {{ object.caption|safe }}
{% if object.caption %}<br>{%endif%} {% if object.caption %}<br>{%endif%}
{% if request.user.is_staff %}<a href="{{ photo.image.url }}" class="original-link" target="_blank" >Link to original file</a>{% endif %} {% if request.user.is_staff %}<a href="{{ photo.image.url }}" class="original-link" target="_blank" >Link to original file</a>{% endif %}
</p> </p>

View file

@ -281,9 +281,7 @@ class ImageModel(models.Model):
if func is None: if func is None:
return _('An "admin_thumbnail" photo size has not been defined.') return _('An "admin_thumbnail" photo size has not been defined.')
else: else:
if not self.id: if hasattr(self, 'get_absolute_url'):
return ""
elif hasattr(self, 'get_absolute_url'):
return mark_safe(f'<a href="{self.get_absolute_url()}"><img src="{func()}"></a>') return mark_safe(f'<a href="{self.get_absolute_url()}"><img src="{func()}"></a>')
else: else:
return mark_safe(f'<a href="{self.image.url}"><img src="{func()}"></a>') return mark_safe(f'<a href="{self.image.url}"><img src="{func()}"></a>')
@ -541,7 +539,7 @@ class Photo(ImageModel):
verbose_name_plural = _("photos") verbose_name_plural = _("photos")
def __str__(self): def __str__(self):
return "%s\n%s" % (self.title, self.caption) return self.title
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# If crop_from or effect property has been changed on existing image, # If crop_from or effect property has been changed on existing image,
@ -596,12 +594,9 @@ class Photo(ImageModel):
def caption_html(self): def caption_html(self):
caption = self.caption caption = self.caption
if caption: if caption:
return markdownify(caption) return mark_safe(markdownify(caption))
return caption return caption
def edit_url(self):
return '/admin/photologue/photo/%s/change/' % self.id
class BaseEffect(models.Model): class BaseEffect(models.Model):
name = models.CharField(_('name'), name = models.CharField(_('name'),
max_length=30, max_length=30,