diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/jrnl/admin.py | 11 | ||||
-rw-r--r-- | app/jrnl/models.py | 31 | ||||
-rw-r--r-- | app/jrnl/templates/horizontal_select.html | 17 | ||||
-rw-r--r-- | app/photos/models.py | 4 | ||||
-rw-r--r-- | app/photos/static/image-preview.js | 1 | ||||
-rw-r--r-- | app/photos/static/my_styles.css | 38 | ||||
-rw-r--r-- | app/photos/urls.py | 5 | ||||
-rw-r--r-- | app/photos/views.py | 10 | ||||
-rw-r--r-- | app/utils/static/image-loader.js | 30 | ||||
-rw-r--r-- | app/utils/widgets.py | 8 |
10 files changed, 144 insertions, 11 deletions
diff --git a/app/jrnl/admin.py b/app/jrnl/admin.py index c3b0c81..2d843b9 100644 --- a/app/jrnl/admin.py +++ b/app/jrnl/admin.py @@ -6,6 +6,7 @@ from utils.widgets import AdminImageWidget, LGEntryForm from .models import Entry, HomepageCurrator from photos.forms import GalleryForm +from photos.models import LuxImage from utils.util import get_latlon @@ -13,6 +14,10 @@ from utils.util import get_latlon class EntryAdmin(OSMGeoAdmin): form = LGEntryForm + def render_change_form(self, request, context, *args, **kwargs): + context['adminform'].form.fields['featured_image'].queryset = LuxImage.objects.all()[:50] + return super(EntryAdmin, self).render_change_form(request, context, *args, **kwargs) + def formfield_for_dbfield(self, db_field, **kwargs): if db_field.name == 'thumbnail' or db_field.name == 'image': field = forms.FileField(widget=AdminImageWidget) @@ -46,7 +51,7 @@ class EntryAdmin(OSMGeoAdmin): 'fields': ( 'dek', 'meta_description', - ('image', 'thumbnail'), + 'image', 'template_name', 'enable_comments', ), @@ -55,6 +60,7 @@ class EntryAdmin(OSMGeoAdmin): 'fields': ( 'field_notes', 'books', + 'featured_image', ), 'classes': ( 'collapse', @@ -77,6 +83,9 @@ class EntryAdmin(OSMGeoAdmin): class Media: js = ('image-loader.js', 'next-prev-links.js') + css = { + "all": ("my_styles.css",) + } @admin.register(HomepageCurrator) diff --git a/app/jrnl/models.py b/app/jrnl/models.py index bcfd0b8..19f5417 100644 --- a/app/jrnl/models.py +++ b/app/jrnl/models.py @@ -1,6 +1,9 @@ import datetime import os import re +from PIL import Image +from django.db.models.signals import post_save +from django.dispatch import receiver from django.contrib.gis.db import models from django.utils.html import format_html @@ -18,7 +21,8 @@ from django.template.defaultfilters import slugify import markdown from bs4 import BeautifulSoup -from photos.models import PhotoGallery, LuxImage +from photos.models import PhotoGallery, LuxImage, LuxImageSize +from photos.utils import resize_image from locations.models import Location from sketches.models import Sketch from books.models import Book @@ -73,7 +77,7 @@ class Entry(models.Model): status = models.IntegerField(choices=PUB_STATUS, default=0) photo_gallery = models.ForeignKey(PhotoGallery, on_delete=models.CASCADE, blank=True, null=True, verbose_name='photo set') image = models.FileField(upload_to=get_upload_path, null=True, blank=True, help_text="should be 520 by 290") - thumbnail = models.FileField(upload_to=get_tn_path, null=True, blank=True, help_text="should be 160 wide") + #thumbnail = models.FileField(upload_to=get_tn_path, null=True, blank=True, help_text="should be 160 wide") meta_description = models.CharField(max_length=256, null=True, blank=True) TEMPLATES = ( (0, 'single'), @@ -108,7 +112,7 @@ class Entry(models.Model): return self.enable_comments and datetime.datetime.today() - datetime.timedelta(30) <= self.pub_date def get_thumbnail_url(self): - image_dir, img = self.thumbnail.url.split('post-thumbnail/')[1].split('/') + image_dir, img = self.image.url.split('post-thumbnail/')[1].split('/') return '%spost-thumbnail/%s/%s' % (settings.IMAGES_URL, image_dir, img) def get_image_url(self): @@ -175,8 +179,15 @@ class Entry(models.Model): except model.DoesNotExist: return '' - def save(self): - if self.pk: + def get_image_name(self): + return self.image.url.split("post-images/")[1][5:-4] + + def get_image_ext(self): + return self.image.url[-3:] + + def save(self, *args, **kwargs): + created = self.pk is None + if not created: md = render_images(self.body_markdown) self.body_html = markdown_to_html(md) self.has_video = parse_video(self.body_html) @@ -184,9 +195,13 @@ class Entry(models.Model): self.location = Location.objects.filter(geometry__contains=self.point).get() except Location.DoesNotExist: raise forms.ValidationError("There is no location associated with that point, add it: %sadmin/locations/location/add/" % (settings.BASE_URL)) - - super(Entry, self).save() - + old = type(self).objects.get(pk=self.pk) if self.pk else None + print("self.image.path: ", self.image.path) + if old and old.featured_image != self.featured_image or created: # Field has changed + s = LuxImageSize.objects.get(name="featured_jrnl") + self.featured_image.sizes.add(s) + self.featured_image.save() + super(Entry, self).save(*args, **kwargs) class HomepageCurrator(models.Model): diff --git a/app/jrnl/templates/horizontal_select.html b/app/jrnl/templates/horizontal_select.html new file mode 100644 index 0000000..4b0a2a1 --- /dev/null +++ b/app/jrnl/templates/horizontal_select.html @@ -0,0 +1,17 @@ +{% with id=widget.attrs.id %} + <ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}> + {% for group, options, index in widget.optgroups %} + {% if group %} + <li>{{ group }} + <ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}> + {% endif %} + {% for option in options %} + <li data-imageid="{{option.value}}">{% include option.template_name with widget=option %}</li> + {% endfor %} + {% if group %} + </ul> + </li> + {% endif %} + {% endfor %} + </ul> +{% endwith %} diff --git a/app/photos/models.py b/app/photos/models.py index 557b9a0..0e5b0e4 100644 --- a/app/photos/models.py +++ b/app/photos/models.py @@ -120,7 +120,7 @@ class LuxImage(models.Model): s = LuxImageSize.objects.get(name=size) if s not in self.sizes.all(): print("new size is "+s.name) - self.sizes.add(s) + self.sizes.add(s) return "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), base, size, self.get_image_ext()) def get_image_path_by_size(self, size="original"): @@ -141,7 +141,7 @@ class LuxImage(models.Model): @property def longitude(self): return self.point.x - + @property def get_previous_published(self): return self.get_previous_by_pub_date() diff --git a/app/photos/static/image-preview.js b/app/photos/static/image-preview.js index b46dbd8..b8fead5 100644 --- a/app/photos/static/image-preview.js +++ b/app/photos/static/image-preview.js @@ -36,6 +36,7 @@ function build_image_preview () { return; } } + document.addEventListener("DOMContentLoaded", function(event) { build_image_preview(); }); diff --git a/app/photos/static/my_styles.css b/app/photos/static/my_styles.css new file mode 100644 index 0000000..986c8e6 --- /dev/null +++ b/app/photos/static/my_styles.css @@ -0,0 +1,38 @@ + +/*o.v.*/ + +#id_featured_image { + /*style the "box" in its minimzed state*/ + border:1px solid black; width:230px; overflow:hidden; + height:300px; overflow-y:scroll; + /*animate collapsing the dropdown from open to closed state (v. fast)*/ +} +#id_featured_image input { + /*hide the nasty default radio buttons. like, completely!*/ + position:absolute;top:0;left:0;opacity:0; +} + + +#id_featured_image label { + /*style the labels to look like dropdown options, kinda*/ + color: #000; + display:none; + margin: 2px 2px 2px 10px; + height:102px; + opacity:.6; + background-repeat: no-repeat; +} +#id_featured_image:hover label{ + /*this is how labels render in the "expanded" state. we want to see only the selected radio button in the collapsed menu, and all of them when expanded*/ + display:block; +} +#id_featured_image label:hover { + opacity:.8; +} +#id_featured_image input:checked + label { + /*tricky! labels immediately following a checked radio button (with our markup they are semantically related) should be fully opaque regardless of hover, and they should always be visible (i.e. even in the collapsed menu*/ + opacity:1 !important; display:block; +} + +/*pfft, nothing as cool here, just the value trace*/ +#trace {margin:0 0 20px;} diff --git a/app/photos/urls.py b/app/photos/urls.py index 7be732d..1da29a6 100644 --- a/app/photos/urls.py +++ b/app/photos/urls.py @@ -16,6 +16,11 @@ urlpatterns = [ name="admin_image_preview" ), url( + r'data/admin/tn/(?P<pk>\d+)/$', + views.thumb_preview_json, + name="admin_thumb_preview" + ), + url( r'galleries/private/(?P<slug>[-\w]+)$', views.PrivateGallery.as_view(), name="private" diff --git a/app/photos/views.py b/app/photos/views.py index d2ecd39..0d51c8e 100644 --- a/app/photos/views.py +++ b/app/photos/views.py @@ -79,6 +79,16 @@ def photo_preview_json(request, pk): return HttpResponse(data) +def thumb_preview_json(request, pk): + p = LuxImage.objects.get(pk=pk) + thumb = p.get_image_by_size("tn") + data = {} + data['url'] = thumb[22:] + + data = json.dumps(data) + return HttpResponse(data) + + def gallery_list_by_area(request, slug, page): """Grabs entries by region or country""" request.page_url = '/photos/' + slug + '/%d/' diff --git a/app/utils/static/image-loader.js b/app/utils/static/image-loader.js index 90054de..2b0a281 100644 --- a/app/utils/static/image-loader.js +++ b/app/utils/static/image-loader.js @@ -2,6 +2,36 @@ function add_images(){ var el = document.getElementById("id_body_markdown"); var iframe = '<iframe frameborder="0" style="border: #dddddd 1px solid;margin-left: 20px;width:330px; height:720px;" src="/luximages/insert/?textarea='+el.id+'"></iframe>'; el.insertAdjacentHTML('afterend', iframe); + + var featured_image = document.getElementById("id_featured_image") + + if (featured_image) { + featured_image.querySelectorAll('li').forEach(function(element) { + var cur = element.dataset.imageid + if (cur != "") { + var request = new XMLHttpRequest(); + request.open('GET', '/photos/luximage/data/admin/tn/'+cur+'/', true); + request.onload = function() { + if (request.status >= 200 && request.status < 400) { + var data = JSON.parse(request.responseText); + var el = element.getElementsByTagName('label')[0]; + url = "url('"+data['url']+"');"; + //console.log(url); + el.style.backgroundImage = 'url('+data["url"]+')'; + + //console.log(el.style); + } else { + console.log("server error", request.statusText); + } + }; + request.onerror = function() { + console.log("error on request"); + }; + request.send(); + } + }); + } + } document.addEventListener("DOMContentLoaded", function(event) { add_images(); diff --git a/app/utils/widgets.py b/app/utils/widgets.py index eac4631..2b76f6b 100644 --- a/app/utils/widgets.py +++ b/app/utils/widgets.py @@ -99,6 +99,11 @@ def thumbnail(image_path): return '<img style="max-width: 400px" src="%s" alt="%s" />' % (absolute_url, image_path) +class ImageRadioSelect(forms.RadioSelect): + template_name = 'horizontal_select.html' + + + class AdminImageWidget(AdminFileWidget): """ A FileField Widget that displays an image instead of a file path @@ -124,6 +129,7 @@ class LGEntryForm(forms.ModelForm): class Meta: widgets = { 'body_markdown': forms.Textarea(attrs={'rows': 40, 'cols': 100}), + 'featured_image': ImageRadioSelect, } @@ -132,6 +138,8 @@ class LGEntryFormSmall(forms.ModelForm): widgets = { 'body_markdown': forms.Textarea(attrs={'rows': 12, 'cols': 100}), } + + class OLAdminBase(OSMGeoAdmin): default_lon = -9285175 default_lat = 4025046 |