diff options
-rw-r--r-- | app/books/admin.py | 2 | ||||
-rw-r--r-- | app/books/models.py | 13 | ||||
-rw-r--r-- | app/jrnl/models.py | 10 | ||||
-rw-r--r-- | app/jrnl/views.py | 1 | ||||
-rw-r--r-- | app/links/admin.py | 3 | ||||
-rw-r--r-- | app/links/models.py | 18 | ||||
-rw-r--r-- | app/locations/admin.py | 7 | ||||
-rw-r--r-- | app/locations/models.py | 20 | ||||
-rw-r--r-- | app/photos/admin.py | 2 | ||||
-rw-r--r-- | app/photos/models.py | 17 | ||||
-rw-r--r-- | app/photos/static/image-preview.js | 13 | ||||
-rw-r--r-- | app/photos/views.py | 10 | ||||
-rw-r--r-- | app/sightings/admin.py | 4 | ||||
-rw-r--r-- | app/sightings/models.py | 20 | ||||
-rw-r--r-- | app/sketches/admin.py | 2 | ||||
-rw-r--r-- | app/sketches/models.py | 12 | ||||
-rw-r--r-- | app/utils/static/next-prev-links.js | 80 | ||||
-rw-r--r-- | app/utils/urls.py | 12 | ||||
-rw-r--r-- | app/utils/views.py | 13 | ||||
-rw-r--r-- | config/base_urls.py | 1 | ||||
-rw-r--r-- | design/templates/archives/sightings.html | 2 |
21 files changed, 208 insertions, 54 deletions
diff --git a/app/books/admin.py b/app/books/admin.py index 1896067..29a885f 100644 --- a/app/books/admin.py +++ b/app/books/admin.py @@ -7,6 +7,8 @@ class BookAdmin(admin.ModelAdmin): search_fields = ['title', 'body_markdown'] list_filter = ('rating', 'read_date') + class Media: + js = ('next-prev-links.js',) class BookHighlightAdmin(admin.ModelAdmin): list_display = ('book', 'page', 'date_added') diff --git a/app/books/models.py b/app/books/models.py index f888480..ebd3a2a 100644 --- a/app/books/models.py +++ b/app/books/models.py @@ -56,6 +56,19 @@ class Book(models.Model): def ratings_range(cls): return range(1, 6) + @property + def get_previous_admin_url(self): + n = self.get_previous_by_pub_date() + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) + + @property + def get_next_admin_url(self): + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' + def admin_thumbnail(self): return force_text('<a href=""><img src="%s" width="100" style="width:100px"></a>' % (self.get_image_url())) admin_thumbnail.allow_tags = True diff --git a/app/jrnl/models.py b/app/jrnl/models.py index d0b9120..b9018bf 100644 --- a/app/jrnl/models.py +++ b/app/jrnl/models.py @@ -5,6 +5,7 @@ import re from django.contrib.gis.db import models from django.utils.html import format_html from django.urls import reverse +from django.apps import apps from django.template.loader import render_to_string from django.conf import settings from django.template import Context @@ -156,7 +157,7 @@ class Entry(models.Model): @property def get_previous_admin_url(self): n = self.get_previous_by_pub_date() - return "/admin/jrnl/entry/%s/change/" % n.pk + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) @property @@ -165,8 +166,11 @@ class Entry(models.Model): @property def get_next_admin_url(self): - n = self.get_next_by_pub_date() - return "/admin/jrnl/entry/%s/change/" % n.pk + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' def save(self): if self.pk: diff --git a/app/jrnl/views.py b/app/jrnl/views.py index 59fff7a..7cf0bb9 100644 --- a/app/jrnl/views.py +++ b/app/jrnl/views.py @@ -1,3 +1,4 @@ +import simplejson from django.views.generic import ListView from django.views.generic.detail import DetailView from django.views.generic.dates import YearArchiveView, MonthArchiveView diff --git a/app/links/admin.py b/app/links/admin.py index c1c0bdb..1811b3f 100644 --- a/app/links/admin.py +++ b/app/links/admin.py @@ -33,4 +33,7 @@ class LinkAdmin(admin.ModelAdmin): }), ) + class Media: + js = ('next-prev-links.js',) + admin.site.register(Link, LinkAdmin) diff --git a/app/links/models.py b/app/links/models.py index 4954a29..cdbe680 100644 --- a/app/links/models.py +++ b/app/links/models.py @@ -4,6 +4,7 @@ from django.template.defaultfilters import striptags from django.urls import reverse from django.utils.encoding import force_text from django.utils.html import format_html +from django.apps import apps from django.db import models from django.utils import timezone from django.core.mail import EmailMessage @@ -69,6 +70,23 @@ class Link(models.Model): return format_html('<a href="%s">Visit Site</a>' % (self.url)) admin_link.short_description = 'Link' + @property + def get_next_published(self): + return self.get_next_by_pub_date(status__exact=1) + + @property + def get_previous_admin_url(self): + n = self.get_previous_by_pub_date() + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) + + @property + def get_next_admin_url(self): + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' + @receiver(post_save, sender=Link) def post_save_events(sender, update_fields, created, instance, **kwargs): diff --git a/app/locations/admin.py b/app/locations/admin.py index c3419b1..4a52778 100644 --- a/app/locations/admin.py +++ b/app/locations/admin.py @@ -3,6 +3,7 @@ from django.contrib.gis.admin import OSMGeoAdmin from locations.models import Region, Country, Location, State, Route, CheckIn from utils.widgets import OLAdminBase +from utils.util import get_latlon class RegionAdmin(OSMGeoAdmin): list_display = ('name', 'slug') @@ -183,8 +184,7 @@ class LocationAdmin(OSMGeoAdmin): }), ) # options for OSM map Using custom ESRI topo map - default_lon = -9285175 - default_lat = 4025046 + default_lat, default_lon = get_latlon() default_zoom = 6 units = True scrollable = False @@ -193,6 +193,9 @@ class LocationAdmin(OSMGeoAdmin): map_template = 'gis/admin/osm.html' openlayers_url = '/static/admin/js/OpenLayers.js' + class Media: + js = ('next-prev-links.js',) + admin.site.register(Location, LocationAdmin) diff --git a/app/locations/models.py b/app/locations/models.py index e9c79e5..f9a3e5b 100644 --- a/app/locations/models.py +++ b/app/locations/models.py @@ -1,5 +1,7 @@ import json import requests +from django.urls import reverse +from django.apps import apps from django.contrib.gis.geos import GEOSGeometry, fromstr, MultiPolygon from django.contrib.gis.db import models from django.contrib.sitemaps import Sitemap @@ -117,9 +119,13 @@ class Location(models.Model): state = models.ForeignKey(State, on_delete=models.CASCADE) name = models.CharField(max_length=50, ) slug = models.SlugField() - pub_date = models.DateTimeField('Date published', null=True) + pub_date = models.DateTimeField('Date published') geometry = models.MultiPolygonField(srid=4326) + class Meta: + ordering = ('-pub_date',) + get_latest_by = 'pub_date' + def __str__(self): return self.name @@ -129,6 +135,18 @@ class Location(models.Model): else: return self.state.country + @property + def get_previous_admin_url(self): + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_previous_by_pub_date().id] ) + + @property + def get_next_admin_url(self): + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' + def get_absolute_url(self): return "/locations/%s/%s/%s/" % (self.state.country.slug, self.state.slug, self.slug) diff --git a/app/photos/admin.py b/app/photos/admin.py index d0f28d7..a052169 100644 --- a/app/photos/admin.py +++ b/app/photos/admin.py @@ -52,7 +52,7 @@ class LuxImageAdmin(OSMGeoAdmin): ) class Media: - js = ('image-preview.js','next-prev-links.js') + js = ('image-preview.js',) admin.site.register(LuxImage, LuxImageAdmin) diff --git a/app/photos/models.py b/app/photos/models.py index d68cd09..91ac15d 100644 --- a/app/photos/models.py +++ b/app/photos/models.py @@ -145,18 +145,21 @@ class LuxImage(models.Model): return self.get_previous_by_pub_date() @property - def get_previous_admin_url(self): - n = self.get_previous_by_pub_date() - return "/admin/photos/luximage/%s/change/" % n.pk - - @property def get_next_published(self): return self.get_next_by_pub_date() @property + def get_previous_admin_url(self): + n = self.get_previous_by_pub_date() + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) + + @property def get_next_admin_url(self): - n = self.get_next_by_pub_date() - return "/admin/photos/luximage/%s/change/" % n.pk + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' @property def is_portait(self): diff --git a/app/photos/static/image-preview.js b/app/photos/static/image-preview.js index 13445f2..aac9c0b 100644 --- a/app/photos/static/image-preview.js +++ b/app/photos/static/image-preview.js @@ -1,7 +1,7 @@ function build_image_preview () { - var style = document.createElement('style'); var url = window.location.href var cur = url.split('/')[6]; + if (cur) { var container = document.createElement("div"); container.className = "form-row field-image"; var wrapper = document.createElement("div"); @@ -9,13 +9,14 @@ function build_image_preview () { label.textContent = "Image:"; var pwrap = document.createElement("p"); var img = document.createElement("img"); + var request = new XMLHttpRequest(); - request.open('GET', '/photos/data/admin/preview/'+cur+'/', true); + request.open('GET', '/photos/luximage/data/admin/preview/'+cur+'/', true); request.onload = function() { if (request.status >= 200 && request.status < 400) { - resp = request.responseText; + var data = JSON.parse(request.responseText); //console.log(resp); - img.src = resp; + img.src = data['url']; } else { console.log("server error"); } @@ -24,6 +25,7 @@ function build_image_preview () { console.log("error on request"); }; request.send(); + pwrap.appendChild(img); wrapper.appendChild(label); wrapper.appendChild(pwrap); @@ -31,6 +33,9 @@ function build_image_preview () { parent = document.getElementById("luximage_form"); node = parent.children[1].children[0]; node.parentNode.insertBefore(container, node.previousSibling); + } else { + return; + } } document.addEventListener("DOMContentLoaded", function(event) { build_image_preview(); diff --git a/app/photos/views.py b/app/photos/views.py index fd32828..c0daf4d 100644 --- a/app/photos/views.py +++ b/app/photos/views.py @@ -69,14 +69,16 @@ def photo_json(request, slug): p = PhotoGallery.objects.filter(set_slug=slug) return HttpResponse(serializers.serialize('json', p), mimetype='application/json') +import simplejson def photo_preview_json(request, pk): p = LuxImage.objects.get(pk=pk) - data = () + data = {} data['url'] = p.get_admin_image() - data['prev'] = p.get_previous_admin_url() - data['next'] = p.get_next_admin_url() - return HttpResponse(serializers.serialize('json', data), mimetype='application/json') + data['prev'] = p.get_previous_admin_url + data['next'] = p.get_next_admin_url + data = simplejson.dumps(data) + return HttpResponse(data) def gallery_list_by_area(request, slug, page): diff --git a/app/sightings/admin.py b/app/sightings/admin.py index 9cd0fef..433d465 100644 --- a/app/sightings/admin.py +++ b/app/sightings/admin.py @@ -46,3 +46,7 @@ class SightingAdmin(OSMGeoAdmin): map_height = 425 map_template = 'gis/admin/osm.html' openlayers_url = '/static/admin/js/OpenLayers.js' + + class Media: + js = ('next-prev-links.js',) + diff --git a/app/sightings/models.py b/app/sightings/models.py index 96e0b5e..792c52b 100644 --- a/app/sightings/models.py +++ b/app/sightings/models.py @@ -1,5 +1,6 @@ import datetime from django.urls import reverse +from django.apps import apps from django.template.defaultfilters import slugify from django.contrib.gis.db import models from django.contrib.auth.models import User @@ -82,14 +83,14 @@ class Sighting(models.Model): ap = models.ForeignKey(AP, on_delete=models.CASCADE) point = models.PointField(blank=True) location = models.ForeignKey(Location, on_delete=models.CASCADE, blank=True) - date = models.DateTimeField('Date', default=timezone.now) + pub_date = models.DateTimeField('Date', default=timezone.now) seen_by = models.ManyToManyField(User) images = models.ManyToManyField(LuxImage, blank=True) #audio = models.ManyToManyField(BirdAudio, blank=True) class Meta: - ordering = ["-date", ] - get_latest_by = "date" + ordering = ["-pub_date", ] + get_latest_by = "pub_date" @property def state(self): @@ -113,6 +114,19 @@ class Sighting(models.Model): '''Get the site's latitude.''' return self.point.y + @property + def get_previous_admin_url(self): + n = self.get_previous_by_pub_date() + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) + + @property + def get_next_admin_url(self): + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' + def get_small_image(self): for img in self.images.all(): for size in img.sizes.all(): diff --git a/app/sketches/admin.py b/app/sketches/admin.py index 41715aa..07a2e6a 100644 --- a/app/sketches/admin.py +++ b/app/sketches/admin.py @@ -34,7 +34,7 @@ class SketchAdmin(OLAdminBase): default_zoom = 10 class Media: - js = ('image-loader.js',) + js = ('image-loader.js', 'next-prev-links.js') diff --git a/app/sketches/models.py b/app/sketches/models.py index c7d28a5..2d7f9ac 100644 --- a/app/sketches/models.py +++ b/app/sketches/models.py @@ -58,6 +58,18 @@ class Sketch(models.Model): def get_next_published(self): return self.get_next_by_pub_date() + @property + def get_previous_admin_url(self): + n = self.get_previous_by_pub_date() + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[n.id] ) + + @property + def get_next_admin_url(self): + model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) + try: + return reverse('admin:%s_%s_change' %(self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk] ) + except model.DoesNotExist: + return '' def save(self, *args, **kwargs): md = render_images(self.body_markdown) diff --git a/app/utils/static/next-prev-links.js b/app/utils/static/next-prev-links.js index 7af1b66..82a1dd8 100644 --- a/app/utils/static/next-prev-links.js +++ b/app/utils/static/next-prev-links.js @@ -1,33 +1,59 @@ function build_next_prev() { + var url = window.location.href - var style = document.createElement('style'); - style.type = 'text/css'; - style.innerHTML = '.np-container {padding-left: 0;} .prev, .next {display: inline-block; margin-right: .5em;} .prev:after { content: "|"; margin-left:.5em;} .prev a:before {content: "\u00AB"; margin-right: 3px;} .next a:after{content: "\u00BB"; margin-left: 3px;}'; - document.getElementsByTagName('head')[0].appendChild(style); var cur = Number(url.split('/')[6]); - var base_url = url.split(cur)[0]; - var next = cur+1; - var prev = cur-1; - var container = document.createElement("ul"); - var next_li = document.createElement("li"); - var next_link = document.createElement("a"); - var prev_li = document.createElement("li"); - var prev_link = document.createElement("a"); - prev_li.className = "prev"; - next_li.className = "next"; - container.className = "np-container"; - next_link.href = base_url + next + "/change/"; - next_link.textContent = "Next"; - prev_link.href = base_url + prev + "/change/"; - prev_link.textContent = "Prev"; - next_li.appendChild(next_link); - prev_li.appendChild(prev_link); - container.appendChild(prev_li); - container.appendChild(next_li); - console.log(container); - Array.from(document.getElementsByClassName('object-tools')).forEach(function(item) { - item.parentNode.insertBefore(container, item.nextSibling); - }) + var app = url.split('/')[4]; + var model = url.split('/')[5]; + if (cur) { + var style = document.createElement('style'); + style.type = 'text/css'; + style.innerHTML = '.np-container {padding-left: 0;} .prev, .next {display: inline-block; margin-right: .5em;} .prev:after { content: "|"; margin-left:.5em;} .prev a:before {content: "\u00AB"; margin-right: 3px;} .next a:after{content: "\u00BB"; margin-left: 3px;}'; + document.getElementsByTagName('head')[0].appendChild(style); + + json_url = '/admin/data/'+app+'/'+model+'/'+cur+'/'; + console.log(json_url); + + var container = document.createElement("ul"); + var next_li = document.createElement("li"); + var next_link = document.createElement("a"); + var prev_li = document.createElement("li"); + var prev_link = document.createElement("a"); + prev_li.className = "prev"; + next_li.className = "next"; + container.className = "np-container"; + next_link.textContent = "Next"; + prev_link.textContent = "Prev"; + + var request = new XMLHttpRequest(); + request.open('GET', json_url, true); + request.onload = function() { + if (request.status >= 200 && request.status < 400) { + var data = JSON.parse(request.responseText); + next_link.href = data['next']; + prev_link.href = data['prev']; + if (data['next'] != '') { + next_li.appendChild(next_link); + } + if (data['prev']) { + prev_li.appendChild(prev_link); + } + } else { + console.log("server error"); + } + }; + request.onerror = function() { + console.log("error on request"); + }; + request.send(); + container.appendChild(prev_li); + container.appendChild(next_li); + //console.log(container); + Array.from(document.getElementsByClassName('object-tools')).forEach(function(item) { + item.parentNode.insertBefore(container, item.nextSibling); + }) + } else { + return; + } }; document.addEventListener("DOMContentLoaded", function(event) { build_next_prev(); diff --git a/app/utils/urls.py b/app/utils/urls.py new file mode 100644 index 0000000..7c37c5d --- /dev/null +++ b/app/utils/urls.py @@ -0,0 +1,12 @@ +from django.urls import path + +from . import views + + +urlpatterns = [ + path( + r'<str:app>/<str:model>/<int:pk>/', + views.nav_json, + name="admin_links" + ), +] diff --git a/app/utils/views.py b/app/utils/views.py index 0b96111..6ebf44d 100644 --- a/app/utils/views.py +++ b/app/utils/views.py @@ -1,4 +1,6 @@ from itertools import chain +import json +from django.http import Http404, HttpResponse from django.views.generic import ListView from photos.models import LuxImage, LuxVideo from django.shortcuts import render_to_response @@ -53,3 +55,14 @@ class TagAutocomplete(autocomplete.Select2QuerySetView): qs = qs.filter(name__istartswith=self.q) return qs + +from django.apps import apps + +def nav_json(request, app, model, pk): + model = apps.get_model(app_label=app, model_name=model) + p = model.objects.get(pk=pk) + data = {} + data['prev'] = p.get_previous_admin_url + data['next'] = p.get_next_admin_url + data = json.dumps(data) + return HttpResponse(data) diff --git a/config/base_urls.py b/config/base_urls.py index 9493d2f..fd7d6a7 100644 --- a/config/base_urls.py +++ b/config/base_urls.py @@ -34,6 +34,7 @@ sitemaps = { urlpatterns = [ path(r'tag-autocomplete/', TagAutocomplete.as_view(), name='tag-autocomplete'), re_path(r'^admin/build/.*', builder.views.do_build), + path(r'admin/data/', include('utils.urls')), path(r'admin/', admin.site.urls), path(r'luximages/insert/', utils.views.insert_image), path(r'sitemap.xml', sitemap, {'sitemaps': sitemaps}), diff --git a/design/templates/archives/sightings.html b/design/templates/archives/sightings.html index 89e31ce..e9d4610 100644 --- a/design/templates/archives/sightings.html +++ b/design/templates/archives/sightings.html @@ -28,7 +28,7 @@ </figure> </div> <h3 class="post--title"><a href="{{object.ap.get_absolute_url}}" title="{%if object.title_keywords%}{{object.title_keywords}}{%else%}{{object.ap}}{%endif%}">{{object.ap|safe|smartypants|widont}}</a> (<span class="sci">{{object.ap.scientific_name}}</span>)</h3> - <time class="post--date" datetime="{{object.date|date:'c'}}">Seen: {{object.date|date:"F"}} <span>{{object.date|date:"j, Y"}}</span></time> + <time class="post--date" datetime="{{object.pub_date|date:'c'}}">Seen: {{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time> <p> <span class="sighting location place post--location" itemscope itemtype="http://schema.org/Place">Loc: {% if object.country.name == "United States" %}<span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, {{object.state.name}}, <span class="p-country-name">U.S.</span>{%else%}<span class="p-region">{{object.location.name|smartypants|safe}}</span>, {{object.country.name}}</a>{%endif%} |