summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf@c63593aa-01b0-44d9-8516-4b9c7e931d7f <luxagraf@c63593aa-01b0-44d9-8516-4b9c7e931d7f>2009-01-05 04:07:10 +0000
committerluxagraf@c63593aa-01b0-44d9-8516-4b9c7e931d7f <luxagraf@c63593aa-01b0-44d9-8516-4b9c7e931d7f>2009-01-05 04:07:10 +0000
commit637d71d2c3a7c1c65a931e1eb094052a095cdf05 (patch)
treeca34a2fead939b133143ec7647a9437d52c89075
have at it
-rw-r--r--apps/blog/__init__.py0
-rw-r--r--apps/blog/admin.py73
-rw-r--r--apps/blog/fields.py7
-rw-r--r--apps/blog/models.py101
-rw-r--r--apps/blog/urls.py15
-rw-r--r--apps/blog/views.py65
-rw-r--r--apps/blog/widgets.py32
-rw-r--r--apps/locations/__init__.py0
-rw-r--r--apps/locations/admin.py241
-rw-r--r--apps/locations/models.py170
-rw-r--r--apps/locations/urls.py6
-rw-r--r--apps/locations/views.py11
-rw-r--r--apps/photos/__init__.py0
-rw-r--r--apps/photos/admin.py66
-rw-r--r--apps/photos/detail_urls.py10
-rw-r--r--apps/photos/models.py154
-rw-r--r--apps/photos/urls.py12
-rw-r--r--apps/photos/utils.py411
-rw-r--r--apps/photos/views.py49
-rw-r--r--base_urls.py55
-rw-r--r--media/css/base.css471
-rw-r--r--media/css/ie6.css10
-rw-r--r--media/img/body-bg.gifbin0 -> 75 bytes
-rw-r--r--media/img/entry_marker.pngbin0 -> 826 bytes
-rw-r--r--media/img/luxheadnewer.gifbin0 -> 20267 bytes
-rw-r--r--media/img/map.gifbin0 -> 547 bytes
-rw-r--r--media/img/marker-entry.pngbin0 -> 849 bytes
-rw-r--r--media/img/photos.gifbin0 -> 680 bytes
-rw-r--r--media/img/shadow.pngbin0 -> 665 bytes
-rw-r--r--media/img/stories.gifbin0 -> 578 bytes
-rw-r--r--media/img/underline.gifbin0 -> 51 bytes
-rw-r--r--templates/404.html30
-rw-r--r--templates/500.html37
-rw-r--r--templates/archives/homepage.html60
-rw-r--r--templates/archives/map.html150
-rw-r--r--templates/archives/photos.html77
-rw-r--r--templates/archives/region.html110
-rw-r--r--templates/archives/robots.html1
-rw-r--r--templates/archives/writing.html79
-rw-r--r--templates/base.html110
-rw-r--r--templates/contact_form/contact_form.html73
-rw-r--r--templates/contact_form/contact_form.txt5
-rw-r--r--templates/contact_form/contact_form_sent.html25
-rw-r--r--templates/contact_form/contact_form_subject.txt1
-rw-r--r--templates/details/about.html42
-rw-r--r--templates/details/entry.html66
-rw-r--r--templates/details/photo.html85
-rw-r--r--templates/gis/admin/google.html5
-rw-r--r--templates/gis/admin/google.js2
49 files changed, 2917 insertions, 0 deletions
diff --git a/apps/blog/__init__.py b/apps/blog/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/blog/__init__.py
diff --git a/apps/blog/admin.py b/apps/blog/admin.py
new file mode 100644
index 0000000..37aab8d
--- /dev/null
+++ b/apps/blog/admin.py
@@ -0,0 +1,73 @@
+from django.contrib import admin
+from django import forms
+from blog.models import Entry, PostImage
+from blog.widgets import AdminImageWidget
+from django.contrib.gis.admin import OSMGeoAdmin
+from django.contrib.gis.maps.google import GoogleMap
+from django.conf import settings
+
+
+
+GMAP = GoogleMap(key=settings.GOOGLE_MAPS_API_KEY)
+
+class EntryAdmin(OSMGeoAdmin):
+ def formfield_for_dbfield(self, db_field, **kwargs):
+ if db_field.name == 'thumbnail':
+ field = forms.FileField(widget=AdminImageWidget)
+ else:
+ field = super(EntryAdmin,self).formfield_for_dbfield(db_field,**kwargs)
+ return field
+ list_display = ('title', 'pub_date','enable_comments', 'status','region','location')
+ search_fields = ['title', 'body_markdown']
+ prepopulated_fields = {"slug" : ('title',)}
+ list_filter = ('pub_date', 'enable_comments', 'status','region','location')
+ fieldsets = (
+ ('Entry', {'fields': ('title','body_markdown', ('location','region'), 'pub_date', ('status','enable_comments'), 'tags', 'slug'), 'classes': ('show','extrapretty','wide')}),
+ ('Pub Location', {'fields': ('point',('thumbnail',),'dek'), 'classes': ('collapse', 'wide')}),
+ )
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ default_lon = -9314310
+ default_lat = 3991847
+ default_zoom = 6
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+
+
+
+
+class PostImageAdmin(admin.ModelAdmin):
+ list_display = ('title', 'output_tags')
+
+
+admin.site.register(PostImage, PostImageAdmin)
+admin.site.register(Entry, EntryAdmin)
diff --git a/apps/blog/fields.py b/apps/blog/fields.py
new file mode 100644
index 0000000..bab8ad3
--- /dev/null
+++ b/apps/blog/fields.py
@@ -0,0 +1,7 @@
+from django import forms
+from blog.widgets import AdminImageWidget
+
+
+class FileUploadForm(forms.ModelForm):
+ upload = forms.FileField(widget=AdminImageWidget)
+
diff --git a/apps/blog/models.py b/apps/blog/models.py
new file mode 100644
index 0000000..d9cea69
--- /dev/null
+++ b/apps/blog/models.py
@@ -0,0 +1,101 @@
+import datetime
+from django.contrib.gis.db import models
+from django.conf import settings
+from django.contrib.syndication.feeds import Feed
+from django.contrib.sitemaps import Sitemap
+from django.template.defaultfilters import truncatewords_html
+
+
+import markdown2 as markdown
+from tagging.fields import TagField
+from tagging.models import Tag
+
+from photos.models import PhotoGallery
+from locations.models import Location,Region
+#from locations.signals import create_location_item
+
+def get_upload_path(self, filename):
+ return "%s/post-thumbs/%s/%s" %(settings.IMAGES_ROOT, datetime.datetime.today().strftime("%Y"), filename)
+
+def markdown_processor(md):
+ processed = markdown.markdown(md, safe_mode = False).split('<break>')
+ html = processed[0]+processed[1]
+ lede = processed[0]
+ return html, lede
+
+class PostImage(models.Model):
+ title = models.CharField(max_length=100)
+ image = models.ImageField(upload_to="%s%s" %(settings.IMAGES_ROOT, datetime.datetime.today().strftime("%Y")))
+
+ def __unicode__(self):
+ return self.title
+
+ def output_tags(self):
+ return force_unicode('<img src="%s%s" alt="%s" class="postpic"/>' % \
+ (settings.IMAGES_URL, self.image.url.split('images')[1].split('/',1)[1], self.title))
+
+class Entry(models.Model):
+ title = models.CharField(max_length=200)
+ slug = models.SlugField(unique_for_date='pub_date')
+ lede = models.TextField(blank=True)
+ body_html = models.TextField(blank=True)
+ body_markdown = models.TextField()
+ dek = models.TextField(null=True,blank=True)
+ pub_date = models.DateTimeField('Date published')
+ tags = TagField()
+ enable_comments = models.BooleanField(default=True)
+ point = models.PointField(null=True)
+ location = models.ForeignKey(Location, null=True)
+ region = models.ForeignKey(Region, null=True)
+ PUB_STATUS = (
+ (0, 'Draft'),
+ (1, 'Published'),
+ )
+ status = models.IntegerField(choices=PUB_STATUS, default=0)
+ photo_gallery = models.ForeignKey(PhotoGallery, blank=True, null=True, verbose_name='photo set')
+ thumbnail = models.FileField(upload_to=get_upload_path, null=True,blank=True)
+
+ class Meta:
+ ordering = ('-pub_date',)
+ get_latest_by = 'pub_date'
+ verbose_name_plural = 'entries'
+
+ def __unicode__(self):
+ return self.title
+
+ def get_absolute_url(self):
+ return "/%s/%s/" % (self.pub_date.strftime("%Y/%b/%d").lower(), self.slug)
+
+ def get_previous_published(self):
+ return self.get_previous_by_pub_date(status__exact=1)
+
+ def get_next_published(self):
+ return self.get_next_by_pub_date(status__exact=1)
+
+ def get_tags(self):
+ return Tag.objects.get_for_object(self)
+
+ def comment_period_open(self):
+ return self.enable_comments and datetime.datetime.today() - datetime.timedelta(30) <= self.pub_date
+
+ def get_thumbnail_url(self):
+ return '%s%s' %(settings.IMAGES_URL, self.thumbnail.url[33:])
+
+ def save(self):
+ html,lede = markdown_processor(self.body_markdown)
+ self.body_html = html
+ self.lede = lede
+ self.dek == markdown.markdown(self.dek, safe_mode = False)
+ super(Entry, self).save()
+
+class BlogSitemap(Sitemap):
+ changefreq = "never"
+ priority = 1.0
+
+ def items(self):
+ return Entry.objects.filter(status=1)
+
+ def lastmod(self, obj):
+ return obj.pub_date
+
+#signals.post_save.connect(create_location_item, sender=Entry) \ No newline at end of file
diff --git a/apps/blog/urls.py b/apps/blog/urls.py
new file mode 100644
index 0000000..57a3e7a
--- /dev/null
+++ b/apps/blog/urls.py
@@ -0,0 +1,15 @@
+from django.conf.urls.defaults import *
+from django.views.generic.list_detail import object_list
+from django.views.generic.simple import redirect_to
+
+from blog.models import Entry
+
+
+
+urlpatterns = patterns('',
+
+ (r'(?P<slug>[-\w]+)/(?P<page>\d+)/$', 'blog.views.entry_list_by_area'),
+ (r'(?P<page>\d+)/$', 'blog.views.entry_list'),
+ (r'(?P<slug>[-\w]+)/$', redirect_to, {'url': '/writing/%(slug)s/1/'}),
+ (r'', redirect_to, {'url': '/writing/1/'}),
+)
diff --git a/apps/blog/views.py b/apps/blog/views.py
new file mode 100644
index 0000000..9641813
--- /dev/null
+++ b/apps/blog/views.py
@@ -0,0 +1,65 @@
+from django.shortcuts import render_to_response,get_object_or_404
+from django.template import RequestContext
+from django.views.generic.date_based import object_detail
+from django.views.generic.list_detail import object_list
+from django.http import Http404
+
+
+from blog.models import Entry
+from locations.models import Region, Country
+
+def home(request):
+ featured = Entry.objects.filter(status__exact=1).order_by('-pub_date')[:1].get()
+ context = {
+ 'featured': featured,
+ 'object_list': Entry.objects.all().exclude(id=featured.id).order_by('-pub_date')[:5],
+ }
+ return render_to_response('archives/homepage.html', context, context_instance = RequestContext(request))
+
+
+def entry_detail(request, year, month, day, slug):
+ obj = get_object_or_404(Entry, slug__exact=slug)
+ photos = {}
+ if obj.photo_gallery:
+ photos = Photo.objects.filter(set__exact=obj.get().photo_gallery.id)[:9]
+ extra = {'photos':photos,}
+ return render_to_response('details/entry.html', {'object': obj,'photos':photos}, context_instance=RequestContext(request))
+
+
+"""
+List of all writing
+"""
+def entry_list(request,page):
+ request.page_url = '/writing/%d/'
+ request.page = int(page)
+ qs = Entry.objects.filter(status__exact=1).order_by('-pub_date')
+ context = {
+ 'country_list': Country.objects.filter(visited=True),
+ 'region_list': Region.objects.all()
+ }
+ return object_list(request, queryset=qs, template_name='archives/writing.html',
+ extra_context=context)
+
+
+"""
+Grabs entries by region or country
+"""
+def entry_list_by_area(request,slug,page):
+ request.page_url = '/writing/'+slug+'/%d/'
+ request.page = int(page)
+ try:
+ region = Region.objects.get(slug__exact=slug)
+ qs = Entry.objects.filter(status__exact=1,region = region).order_by('-pub_date')
+ except:
+ region = Country.objects.get(slug__exact=slug)
+ qs = Entry.objects.filter(status__exact=1,location__state__country = region).order_by('-pub_date')
+ if not region:
+ raise Http404
+ context = {
+ 'region': region,
+ 'country_list': Country.objects.filter(visited=True),
+ 'region_list': Region.objects.all()
+ }
+ return object_list(request, queryset=qs, template_name='archives/writing.html',
+ extra_context=context)
+
diff --git a/apps/blog/widgets.py b/apps/blog/widgets.py
new file mode 100644
index 0000000..a9451e7
--- /dev/null
+++ b/apps/blog/widgets.py
@@ -0,0 +1,32 @@
+from django.contrib.admin.widgets import AdminFileWidget
+from django.utils.translation import ugettext as _
+from django.utils.safestring import mark_safe
+from django.conf import settings
+from PIL import Image
+import os
+
+try:
+ from sorl.thumbnail.main import DjangoThumbnail
+ def thumbnail(image_path):
+ t = DjangoThumbnail(relative_source=image_path, requested_size=(200,200))
+ return u'<img src="%s" alt="%s" />' % (t.absolute_url, image_path)
+except ImportError:
+ def thumbnail(image_path):
+ absolute_url = os.path.join(settings.IMAGES_URL, image_path)
+ return u'<img src="%s" alt="%s" />' % (absolute_url, image_path)
+
+class AdminImageWidget(AdminFileWidget):
+ """
+ A FileField Widget that displays an image instead of a file path
+ if the current file is an image.
+ """
+ def render(self, name, value, attrs=None):
+ output = []
+ file_name = str(value)
+ if file_name:
+ file_path = '%s' % (file_name)
+ output.append('<a target="_blank" href="%s">%s</a><br />%s <a target="_blank" href="%s">%s</a><br />%s ' % \
+ (file_path, thumbnail(file_name), _('Currently:'), file_path, file_name, _('Change:')))
+
+ output.append(super(AdminFileWidget, self).render(name, value, attrs))
+ return mark_safe(u''.join(output))
diff --git a/apps/locations/__init__.py b/apps/locations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/locations/__init__.py
diff --git a/apps/locations/admin.py b/apps/locations/admin.py
new file mode 100644
index 0000000..7fcfee5
--- /dev/null
+++ b/apps/locations/admin.py
@@ -0,0 +1,241 @@
+from django.contrib import admin
+from django.contrib.gis.admin import OSMGeoAdmin
+from locations.models import Region,Country,Location,State
+from django.contrib import databrowse
+from django.contrib.gis.maps.google import GoogleMap
+from django.conf import settings
+
+GMAP = GoogleMap(key=settings.GOOGLE_MAPS_API_KEY)
+databrowse.site.register(Region)
+
+class RegionAdmin(OSMGeoAdmin):
+ # Standard Django Admin Options
+ list_display = ('name','slug')
+ prepopulated_fields = {'slug': ('name',)}
+ search_fields = ('name',)
+ ordering = ('name',)
+ save_as = True
+ search_fields = ['name',]
+ list_select_related = True
+ fieldsets = (
+ ('Region', {'fields': ('name','slug','pub_date'), 'classes': ('show','extrapretty')}),
+ ('Editable Map View', {'fields': ('geometry',), 'classes': ('show', 'wide')}),
+ )
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ #default_lon = 0
+ #default_lat = 0
+ #default_zoom = 4
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+# Finally, with these options set now register the model
+# associating the Options with the actual model
+admin.site.register(Region,RegionAdmin)
+
+class CountryAdmin(OSMGeoAdmin):
+ """
+ # Standard Django Admin Options
+ list_display = ('name','slug','region')
+ prepopulated_fields = {'slug': ('name',)}
+ search_fields = ('name',)
+ ordering = ('name',)
+ save_as = True
+ search_fields = ['name',]
+ list_select_related = True
+ fieldsets = (
+ ('Country', {'fields': ('name','slug','abbr','region','pub_date'), 'classes': ('show','extrapretty')}),
+ ('Editable Map View', {'fields': ('geometry',), 'classes': ('show', 'wide')}),
+ )
+ """
+
+ # Standard Django Admin Options
+ list_display = ('name','pop2005','region','subregion',)
+ search_fields = ('name',)
+ ordering = ('name',)
+ list_filter = ('visited','region','subregion',)
+ save_as = True
+ search_fields = ['name','iso2','iso3','subregion','region']
+ list_select_related = True
+ fieldsets = (
+ ('Country Attributes', {'fields': (('name','pop2005','slug','zoom_level','visited')), 'classes': ('show','extrapretty')}),
+ ('Country Codes', {'fields': ('region','subregion','iso2','iso3','un',), 'classes': ('collapse',)}),
+ ('Area and Coordinates', {'fields': ('area','lat','lon',), 'classes': ('collapse', 'wide')}),
+ ('Editable Map View', {'fields': ('geometry',), 'classes': ('show', 'wide')}),
+ )
+
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ #default_lon = 0
+ #default_lat = 0
+ #default_zoom = 4
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+# Finally, with these options set now register the model
+# associating the Options with the actual model
+admin.site.register(Country,CountryAdmin)
+
+
+
+class StateAdmin(OSMGeoAdmin):
+ # Standard Django Admin Options
+ list_display = ('name','slug','country')
+ prepopulated_fields = {'slug': ('name',)}
+ search_fields = ('name','country')
+ ordering = ('name',)
+ save_as = True
+ search_fields = ['name',]
+ list_select_related = True
+ fieldsets = (
+ ('Location', {'fields': ('name','slug','pub_date','country'), 'classes': ('show','extrapretty')}),
+ ('Editable Map View', {'fields': ('geometry',), 'classes': ('show', 'wide')}),
+ )
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ #default_lon = 0
+ #default_lat = 0
+ #default_zoom = 4
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+# Finally, with these options set now register the model
+# associating the Options with the actual model
+admin.site.register(State,StateAdmin)
+
+class LocationAdmin(OSMGeoAdmin):
+ # Standard Django Admin Options
+ list_display = ('name','slug','state')
+ prepopulated_fields = {'slug': ('name',)}
+ search_fields = ('name','state')
+ ordering = ('name',)
+ save_as = True
+ search_fields = ['name',]
+ list_select_related = True
+ fieldsets = (
+ ('Location', {'fields': ('name','slug','pub_date','state'), 'classes': ('show','extrapretty')}),
+ ('Editable Map View', {'fields': ('geometry',), 'classes': ('show', 'wide')}),
+ )
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ #default_lon = 0
+ #default_lat = 0
+ #default_zoom = 4
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+# Finally, with these options set now register the model
+# associating the Options with the actual model
+admin.site.register(Location,LocationAdmin) \ No newline at end of file
diff --git a/apps/locations/models.py b/apps/locations/models.py
new file mode 100644
index 0000000..57806a2
--- /dev/null
+++ b/apps/locations/models.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+# models.py
+
+# All standard Django fields as well as GeoDjango geometry fields and the GeoManager() can be
+# imported from django.contrib.gis.db after adding django.contrib.gis to INSTALLED_APPS
+from django.contrib.gis.db import models
+from django.contrib.sitemaps import Sitemap
+# Used to display html 'help text' links within Admin App
+from django.utils.safestring import mark_safe
+
+class Region(models.Model):
+ name = models.CharField(max_length=50, )
+ slug = models.SlugField()
+ pub_date = models.DateTimeField('Date published',null=True)
+ # GeoDjango specific Polygon Field and GeoManager
+ geometry = models.MultiPolygonField(srid=4326, null=True)
+ lon = models.FloatField('Longitude',help_text="Longitude of centerpoint",null=True)
+ lat = models.FloatField('Latitude',help_text="Latitude of centerpoint",null=True)
+ zoom_level = models.CharField(max_length=2,null=True)
+ # GeoManager, a subclass that adds a rich set of geospatial queryset methods
+ objects = models.GeoManager()
+
+ def get_absolute_url(self):
+ return "/locations/region/%s/" % (self.slug)
+
+ def __unicode__(self): return self.name
+
+
+# imported from django.contrib.gis.db
+from django.contrib.gis.db import models
+
+# Used to display html 'help text' links within Admin App
+from django.utils.safestring import mark_safe
+
+class Country(models.Model):
+ """
+
+ A geographic model based on the v3 of the simplified world borders multipolygon shapefile
+ from http://thematicmapping.org/downloads/world_borders.php.
+
+ Field names, Django types, and max_lengths were autogenerated using the ogrinspect utility with hand
+ edits to add alternative field names and help_text.
+
+ Imported using LayerMapping (requires GDAL) called within the load_data.py script provided
+ within this sample project.
+
+ All fields match the source dataset, an ESRI format shapefile made up of several related files:
+ .shp - holds the vector data that is to be stored in the MultiPolygonField field named'geometry'.
+ .shx - spatial index file for geometries stored in the .shp.
+ .dbf - database file for holding attribute data (can be opened in excel and open office).
+ .prj - contains the spatial reference information for the geometries stored in the .shp
+
+
+ """
+
+ # Regular Django fields corresponding to the attributes in the
+ # world borders shapefile
+ name = models.CharField(max_length=50)
+ area = models.IntegerField(help_text="Area of Country in SQ meters")
+ pop2005 = models.IntegerField('Population 2005')
+ fips = models.CharField('FIPS Code', max_length=2, help_text=mark_safe('<a href="http://www.census.gov/geo/www/fips/fips.html">Federal Information Processing Standard Code</a>'))
+ iso2 = models.CharField('2 Digit ISO', max_length=2, help_text=mark_safe('<a href="http://www.iso.org/">International Organization for Standardization</a>' ))
+ iso3 = models.CharField('3 Digit ISO', max_length=3,help_text=mark_safe('<a href="http://www.iso.org/">International Organization for Standardization</a>' ))
+ un = models.IntegerField('United Nations Code')
+ REGION_CODES = (
+ (0, 'MISC'),
+ (2, 'Africa'),
+ (9, 'Oceania'),
+ (19, 'Americas'),
+ (142, 'Asia'),
+ (150, 'Europe'),
+ )
+ SUBREGION_CODES = (
+ (0, 'MISC'),
+ (5, 'South America'),
+ (11, 'Western Africa'),
+ (13, 'Central America'),
+ (14, 'Eastern Africa'),
+ (15, 'Northern Africa'),
+ (17, 'Middle Africa'),
+ (18, 'Southern Africa'),
+ (21, 'North America'),
+ (29, 'Caribbean'),
+ (30, 'Eastern Asia'),
+ (34, 'Southern Asia'),
+ (35, 'Southeast Asia'),
+ (39, 'Southern Europe'),
+ (53, 'Australia and New Zealand'),
+ (54, 'Melanesia'),
+ (57, 'Micronesia'),
+ (61, 'Polynesia'),
+ (143, 'Central Asia'),
+ (145, 'Western Asia'),
+ (151, 'Eastern Europe'),
+ (154, 'Northern Europe'),
+ (155, 'Western Europe'),
+ )
+ region = models.IntegerField('Region Code',choices=REGION_CODES)
+ subregion = models.IntegerField('Sub-Region Code',choices=SUBREGION_CODES)
+ lon = models.FloatField('Longitude',help_text="Longitude of centerpoint")
+ lat = models.FloatField('Latitude',help_text="Latitude of centerpoint")
+ zoom_level = models.CharField(max_length=2,null=True)
+ slug = models.SlugField(null=True)
+ visited = models.BooleanField(default=False)
+ lux_region = models.ForeignKey(Region, null=True)
+ pub_date = models.DateTimeField('Date published',null=True)
+ # GeoDjango-specific: a geometry field (MultiPolygonField), and
+ # overriding the default manager with a GeoManager instance.
+ geometry = models.MultiPolygonField('Country Border',srid=4326)
+ objects = models.GeoManager()
+
+
+ # Returns the string representation of the model.
+ def __unicode__(self):
+ return self.name
+
+ class Meta:
+ ordering = ['name']
+ verbose_name_plural = 'Countries'
+
+ def get_absolute_url(self):
+ return "/locations/%s/" % (self.slug)
+
+
+class State(models.Model):
+ name = models.CharField(max_length=250, blank=True, null=True,)
+ country = models.ForeignKey(Country)
+ slug = models.SlugField()
+ pub_date = models.DateTimeField('Date published',null=True)
+ geometry = models.MultiPolygonField(srid=4326,null=True)
+ objects = models.GeoManager()
+
+ class Meta:
+ ordering = ['name']
+
+ class Admin:
+ pass
+
+ def __unicode__(self):
+ return "%s" %(self.name)
+
+ def get_absolute_url(self):
+ return "/locations/%s/%s/" % (self.country.slug, self.slug)
+
+class Location(models.Model):
+ state = models.ForeignKey(State)
+ name = models.CharField(max_length=50, )
+ slug = models.SlugField()
+ pub_date = models.DateTimeField('Date published',null=True)
+ # GeoDjango specific Polygon Field and GeoManager
+ geometry = models.MultiPolygonField(srid=4326)
+ # GeoManager, a subclass that adds a rich set of geospatial queryset methods
+ objects = models.GeoManager()
+
+ def get_absolute_url(self):
+ return "/locations/%s/%s/%s/" % (self.state.country.slug, self.state.slug, self.slug)
+
+
+ def __unicode__(self): return self.name
+
+class WritingbyLocationSitemap(Sitemap):
+ changefreq = "weekly"
+ priority = 0.6
+
+ def location():
+ return '/writing/%s/1/' %(self.slug)
+
+ def items(self):
+ return Location.objects.all()
+
diff --git a/apps/locations/urls.py b/apps/locations/urls.py
new file mode 100644
index 0000000..669b828
--- /dev/null
+++ b/apps/locations/urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+ #(r'(?P<slug>[0-9a-zA-Z_.-]+)/$', 'locations.views.list_view_region'),
+ (r'^$', 'locations.views.list_view'),
+)
diff --git a/apps/locations/views.py b/apps/locations/views.py
new file mode 100644
index 0000000..a59a2e5
--- /dev/null
+++ b/apps/locations/views.py
@@ -0,0 +1,11 @@
+from django.shortcuts import render_to_response,get_object_or_404
+from django.template import RequestContext
+
+from blog.models import Entry
+from locations.models import Location, Country, Region
+
+def list_view(request):
+ qs = Entry.objects.filter(status__exact=1)
+ cl = Country.objects.filter(visited=True).exclude(name='default')
+ rl = Region.objects.all()
+ return render_to_response('archives/map.html', {'object_list': qs,'country_list':cl,'region_list':rl}, context_instance=RequestContext(request)) \ No newline at end of file
diff --git a/apps/photos/__init__.py b/apps/photos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/photos/__init__.py
diff --git a/apps/photos/admin.py b/apps/photos/admin.py
new file mode 100644
index 0000000..3cc1ae8
--- /dev/null
+++ b/apps/photos/admin.py
@@ -0,0 +1,66 @@
+from django.contrib import admin
+from django.contrib.gis.admin import OSMGeoAdmin
+from django.contrib.gis.maps.google import GoogleMap
+from django.conf import settings
+
+from photos.models import Photo,PhotoGallery
+
+GMAP = GoogleMap(key=settings.GOOGLE_MAPS_API_KEY)
+
+class PhotoAdmin(OSMGeoAdmin):
+ list_display = ('title','admin_thumbnail', 'flickr_id', 'pub_date',)
+ list_filter = ('pub_date',)
+ fieldsets = (
+ (None, {'fields': (('title', 'description'),'pub_date', 'tags',('lat','lon'))}),
+ ('Exif Data', {'fields': ('exif_aperture','exif_shutter','exif_iso','exif_lens','exif_date','exif_make','exif_model'), 'classes': ('collapse')}),
+ ('Flickr Data', {'fields': ('flickr_id','flickr_owner','flickr_farm','flickr_server','flickr_secret','flickr_originalsecret'), 'classes': ('collapse')}),
+ )
+ extra_js = [GMAP.api_url + GMAP.key]
+ map_template = 'gis/admin/google.html'
+ # Default GeoDjango OpenLayers map options
+ # Uncomment and modify as desired
+ # To learn more about this jargon visit:
+ # www.openlayers.org
+
+ #default_lon = 0
+ #default_lat = 0
+ #default_zoom = 4
+ #display_wkt = False
+ #display_srid = False
+ #extra_js = []
+ #num_zoom = 18
+ #max_zoom = False
+ #min_zoom = False
+ #units = False
+ #max_resolution = False
+ #max_extent = False
+ #modifiable = True
+ #mouse_position = True
+ #scale_text = True
+ #layerswitcher = True
+ scrollable = False
+ #admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
+ map_width = 700
+ map_height = 325
+ #map_srid = 4326
+ #map_template = 'gis/admin/openlayers.html'
+ #openlayers_url = 'http://openlayers.org/api/2.6/OpenLayers.js'
+ #wms_url = 'http://labs.metacarta.com/wms/vmap0'
+ #wms_layer = 'basic'
+ #wms_name = 'OpenLayers WMS'
+ #debug = False
+ #widget = OpenLayersWidget
+
+admin.site.register(Photo, PhotoAdmin)
+
+
+class PhotoGalleryAdmin(OSMGeoAdmin):
+ list_display = ('set_title','region','location')
+ list_filter = ('region','location')
+ fieldsets = (
+ (None, {'fields': (('set_id','set_title', 'set_desc'),'set_slug','primary','location','region')}),
+ )
+
+
+
+admin.site.register(PhotoGallery, PhotoGalleryAdmin) \ No newline at end of file
diff --git a/apps/photos/detail_urls.py b/apps/photos/detail_urls.py
new file mode 100644
index 0000000..9ff9b84
--- /dev/null
+++ b/apps/photos/detail_urls.py
@@ -0,0 +1,10 @@
+from django.conf.urls.defaults import *
+from photos.models import Photo
+
+detail_dict = {
+ 'queryset': Photo.objects.all(),
+}
+
+urlpatterns = patterns('django.views.generic.list_detail',
+ (r'^(?P<object_id>\d+)/$', 'object_detail', dict(detail_dict, template_name='details/photo.html')),
+)
diff --git a/apps/photos/models.py b/apps/photos/models.py
new file mode 100644
index 0000000..9b6d331
--- /dev/null
+++ b/apps/photos/models.py
@@ -0,0 +1,154 @@
+import datetime
+from django.contrib.gis.db import models
+from django.contrib.syndication.feeds import Feed
+from django.contrib.sitemaps import Sitemap
+from django.utils.encoding import force_unicode
+from django.conf import settings
+
+from tagging.fields import TagField
+from tagging.models import Tag
+
+from locations.models import Location,Region
+
+class Photo(models.Model):
+ description = models.TextField(blank=True, null=True)
+ title = models.CharField(blank=True, max_length=300)
+ pub_date = models.DateTimeField()
+ tags = TagField()
+ exif_aperture = models.CharField(max_length=50, blank=True, null=True)
+ exif_make = models.CharField(max_length=50, blank=True, null=True)
+ exif_model = models.CharField(max_length=50, blank=True, null=True)
+ exif_shutter = models.CharField(max_length=50, blank=True, null=True)
+ exif_iso = models.CharField(max_length=50, blank=True, null=True)
+ exif_lens = models.CharField(max_length=50, blank=True, null=True)
+ exif_date = models.DateTimeField()
+ """Flickr Specific Stuff"""
+ flickr_id = models.CharField(max_length=300) #varchar since Flickr ids are larger than than integerfield can handle and BigIntegerField gets weird in Postgres.
+ flickr_owner = models.CharField(max_length=20)
+ flickr_server = models.IntegerField()
+ flickr_farm = models.IntegerField()
+ flickr_secret = models.CharField(max_length=50)
+ flickr_originalsecret = models.CharField(max_length=50)
+ lon = models.FloatField('Longitude',help_text="Longitude of centerpoint",null=True)
+ lat = models.FloatField('Latitude',help_text="Latitude of centerpoint",null=True)
+ location = models.ForeignKey(Location, null=True)
+ region = models.ForeignKey(Region, null=True)
+
+
+
+
+ class Meta:
+ ordering = ('-pub_date',)
+
+
+ def admin_thumbnail(self):
+ return force_unicode('<a href="%s"><img src="%s"></a>' % \
+ (self.get_absolute_url(), self.get_small_square_url()))
+ admin_thumbnail.allow_tags = True
+ admin_thumbnail.short_description = 'Thumbnail'
+
+
+ def __unicode__(self):
+ return self.title
+
+ def get_absolute_url(self):
+ return "/photo/%s/" % (self.id)
+
+ def get_model_name(self):
+ return 'photo'
+
+ def get_small_square_url(self):
+ return self.get_pic_url(size="small_square")
+
+ def get_large_url(self):
+ return self.get_pic_url(size="large")
+
+ def get_small_url(self):
+ return self.get_pic_url(size="small")
+
+ def get_medium_url(self):
+ return self.get_pic_url(size="medium")
+
+ def get_original_url(self):
+ #return self.get_pic_url(size="original")
+ return "http://farm%s.static.flickr.com/%s/%s_%s_o.jpg" % (self.flickr_farm, self.flickr_server, self.flickr_id, self.flickr_originalsecret)
+
+ def get_pic_url(self, size='small'):
+ # small_square=75x75
+ # thumb=100 on longest side
+ # small=240 on longest side
+ # medium=500 on longest side
+ # large=1024 on longest side
+ # original=duh
+
+ base_url = "http://static.flickr.com"
+ size_char='s' # default to small_square
+
+ if size == 'small_square':
+ size_char='_s'
+ elif size == 'thumb':
+ size_char='_t'
+ elif size == 'small':
+ size_char='_m'
+ elif size == 'medium':
+ size_char=''
+ elif size == 'large':
+ size_char='_b'
+ elif size == 'original':
+ size_char='_o'
+
+ return "http://farm%s.static.flickr.com/%s/%s_%s%s.jpg" % (self.flickr_farm, self.flickr_server, self.flickr_id, self.flickr_secret, size_char)
+
+ def get_tumble_image(self):
+ return "%s/crops/%s/%s.jpg" %(settings.IMAGES_URL, self.pub_date.strftime("%Y/%b").lower(), self.id)
+
+ def get_tags(self):
+ return Tag.objects.get_for_object(self)
+
+ def get_previous_published(self):
+ return self.get_previous_by_pub_date()
+
+ def get_next_published(self):
+ return self.get_next_by_pub_date()
+
+ def comment_period_open(self):
+ return self.enable_comments and datetime.datetime.today() - datetime.timedelta(30) <= self.pub_date
+ """
+ def save(self):
+ self.lat = self.gps.split(',')[0]
+ self.lon = self.gps.split(',')[1]
+ super(Photo, self).save()
+ """
+class PhotoGallery(models.Model):
+ set_id = models.CharField(blank=True, max_length=300)
+ set_title = models.CharField(blank=True, max_length=300)
+ set_desc = models.TextField(blank=True, null=True)
+ set_slug = models.CharField(blank=True, max_length=300)
+ primary = models.CharField(blank=True, max_length=300)
+ photos = models.ManyToManyField(Photo)
+ location = models.ForeignKey(Location, null=True)
+ region = models.ForeignKey(Region, null=True)
+
+ class Meta:
+ ordering = ('id',)
+
+ def __unicode__(self):
+ return self.set_title
+
+ def get_main_image(self):
+ return "%sgallery_thumbs/%s.jpg" % (settings.IMAGES_URL, self.id)
+
+ def get_absolute_url(self):
+ return "/photos/album/%s/" % (self.id)
+
+
+class PhotoSitemap(Sitemap):
+ changefreq = "never"
+ priority = 0.7
+
+ def items(self):
+ return Photo.objects.all()
+
+ def lastmod(self, obj):
+ return obj.pub_date
+
diff --git a/apps/photos/urls.py b/apps/photos/urls.py
new file mode 100644
index 0000000..44b4869
--- /dev/null
+++ b/apps/photos/urls.py
@@ -0,0 +1,12 @@
+from django.conf.urls.defaults import *
+from django.views.generic import list_detail
+from django.views.generic.simple import redirect_to
+
+
+
+urlpatterns = patterns('',
+ (r'(?P<slug>[-\w]+)/(?P<page>\d+)/$', 'photos.views.gallery_list_by_area'),
+ (r'(?P<page>\d+)/$', 'photos.views.gallery_list'),
+ (r'(?P<slug>[-\w]+)/$', redirect_to, {'url': '/photos/%(slug)s/1/'}),
+ (r'', redirect_to, {'url': '/photos/1/'}),
+) \ No newline at end of file
diff --git a/apps/photos/utils.py b/apps/photos/utils.py
new file mode 100644
index 0000000..de0884d
--- /dev/null
+++ b/apps/photos/utils.py
@@ -0,0 +1,411 @@
+from __future__ import division
+import datetime
+import os
+import cStringIO # *much* faster than StringIO
+import urllib
+
+
+from django.contrib.contenttypes.models import ContentType
+from django.template.defaultfilters import slugify
+from django.core.exceptions import ObjectDoesNotExist
+from django.utils.encoding import force_unicode,smart_unicode
+from django.conf import settings
+
+# Required PIL classes may or may not be available from the root namespace
+# depending on the installation
+try:
+ import Image
+ import ImageFile
+ import ImageFilter
+ import ImageEnhance
+except ImportError:
+ try:
+ from PIL import Image
+ from PIL import ImageFile
+ from PIL import ImageFilter
+ from PIL import ImageEnhance
+ except ImportError:
+ raise ImportError("Could not import the Python Imaging Library.")
+
+
+from strutils import safestr
+from photos.models import Photo,PhotoGallery
+
+
+# Flickr Sync stuffs
+API_KEY = settings.FLICKR_API_KEY
+from APIClients import FlickrClient
+
+EXIF_PARAMS = {"Aperture":'f/2.8',"Make":'Apple',"Model":'iPhone',"Exposure":'',"ISO Speed":'',"Focal Length":'',"Shutter Speed":'','Date and Time (Original)':'2008:07:03 22:44:25'}
+
+def sync_flickr_photos(*args, **kwargs):
+ cur_page = 1 # Start on the first page of the stream
+ paginate_by = 100 # Get 100 photos at a time
+ dupe = False # Set our dupe flag for the following loop
+ BASE_PATH = 'http://flickr.com/services/rest/'
+ client = FlickrClient(BASE_PATH, API_KEY)
+ data = client.flickr_people_getPublicPhotos(user_id=settings.FLICKR_USER_ID, page=cur_page, per_page=paginate_by,extras="date_upload,date_taken,geo")
+ #photos.photos.photo.reverse()
+ for post in data.findall('photos/photo'):
+ info = dict((k, smart_unicode(post.get(k))) for k in post.keys())
+ try:
+ row = Photo.objects.get(flickr_id=info['id'], flickr_secret=info['secret'])
+ # If the row exists already, set the dupe flag
+ dupe = True
+ print 'already have '+info['id']+' moving on'
+ except ObjectDoesNotExist:
+ taglist = []
+ place = place_handler(force_unicode(info['latitude'])+","+force_unicode(info['longitude']))
+ details = client.flickr_photos_getInfo(user_id=settings.FLICKR_USER_ID, photo_id=force_unicode(info['id']))
+ for t in details.findall('photo/tags/tag'):
+ tag = dict((k, smart_unicode(t.get(k))) for k in t.keys())
+ taglist.append(tag['raw'])
+ exif = exif_handler(client.flickr_photos_getExif(user_id=API_KEY, photo_id=safestr(info['id'])))
+ photo = Photo.objects.create(
+ title = info['title'],
+ flickr_id = info['id'],
+ flickr_owner = info['owner'],
+ flickr_server = info['server'],
+ flickr_secret = info['secret'],
+ flickr_originalsecret = force_unicode(details[0].attrib['originalsecret']),
+ flickr_farm = info['farm'],
+ pub_date = flickr_datetime_to_datetime(info['datetaken']),
+ description = force_unicode(details[0].findtext('description')),
+ exif_aperture = exif['Aperture'],
+ exif_make = exif['Make'],
+ exif_model = exif['Model'],
+ exif_shutter = exif['Exposure'],
+ exif_iso = exif['ISO Speed'],
+ exif_lens = exif['Focal Length'],
+ exif_date = flickr_datetime_to_datetime(exif["Date and Time (Original)"].replace(':', '-', 2)),
+ gps = force_unicode(info['latitude'])+","+force_unicode(info['longitude']),
+ place = place,
+ tags = ", ".join(t for t in taglist)
+ )
+ photo.save()
+ make_local_size(photo)
+
+def exif_handler(data):
+ converted = {}
+ try:
+ for t in data.findall('photo/exif'):
+ e = dict((k, smart_unicode(t.get(k))) for k in t.keys())
+ if safestr(e['label']) == "Aperture":
+ if not converted.has_key("Aperture"):
+ converted["Aperture"] = safestr(t.findtext('clean'))
+ else:
+ converted[safestr(e['label'])] = safestr(t.findtext('raw'))
+ except:
+ pass
+ for k,v in EXIF_PARAMS.items():
+ if not converted.has_key(k):
+ converted[k] = v
+ return converted
+
+
+def flickr_datetime_to_datetime(fdt):
+ from datetime import datetime
+ from time import strptime
+ date_parts = strptime(fdt, '%Y-%m-%d %H:%M:%S')
+ return datetime(*date_parts[0:6])
+
+def place_handler(gps):
+ place = Place.objects.all()
+ count = Place.objects.count()
+ num = 1
+ for p in place:
+ if p.within_bounds(gps) is True:
+ return p
+ elif p.within_bounds(gps) is False and count == num:
+ return Place.objects.filter(name='Default').get()
+ num += 1
+
+ImageFile.MAXBLOCK = 1000000
+
+def make_local_size(photo,set):
+ crop_dir = settings.IMAGES_ROOT + '/gallery_thumbs/'
+ if not os.path.isdir(crop_dir):
+ os.makedirs(crop_dir)
+ remote = photo.get_original_url()
+ print remote
+ fname = urllib.urlopen(remote)
+ im = cStringIO.StringIO(fname.read()) # constructs a StringIO holding the image
+ img = Image.open(im)
+
+ #calculate crop:
+ cur_width, cur_height = img.size
+ new_width, new_height = 210, 210
+ ratio = max(float(new_width)/cur_width,float(new_height)/cur_height)
+ x = (cur_width * ratio)
+ y = (cur_height * ratio)
+ xd = abs(new_width - x)
+ yd = abs(new_height - y)
+ x_diff = int(xd / 2)
+ y_diff = int(yd / 2)
+ box = (int(x_diff), int(y_diff), int(x_diff+new_width), int(y_diff+new_height))
+
+ #create resized file
+ resized = img.resize((int(x), int(y)), Image.ANTIALIAS).crop(box)
+ # save resized file
+ resized_filename = '%s/%s.jpg' %(crop_dir, set.id)
+ try:
+ if img.format == 'JPEG':
+ resized.save(resized_filename, 'JPEG', quality=95, optimize=True)
+ else:
+ resized.save(resized_filename)
+ except IOError, e:
+ if os.path.isfile(resized_filename):
+ os.unlink(resized_filename)
+ raise e
+ #os.unlink(img)
+
+
+
+def sync_sets(*args, **kwargs):
+ dupe = False # Set our dupe flag for the following loop
+ BASE_PATH = 'http://flickr.com/services/rest/'
+ client = FlickrClient(BASE_PATH, API_KEY)
+ data = client.flickr_photosets_getList(user_id=settings.FLICKR_USER_ID)
+ nodes = data.findall('photosets/photoset')
+ for post in nodes:
+ info = dict((k, smart_unicode(post.get(k))) for k in post.keys())
+ try:
+ row = PhotoGallery.objects.get(set_id__exact=info['id'])
+ # okay it already exists, but is it up-to-date?
+ #get_photos_in_set(row,set.id)
+
+ except ObjectDoesNotExist:
+ s = PhotoGallery.objects.create (
+ set_id = force_unicode(info['id']),
+ set_title = force_unicode(post.findtext('title')),
+ set_desc = force_unicode(post.findtext('description')),
+ set_slug = slugify(force_unicode(post.findtext('title'))),
+ primary = force_unicode(info['primary']),
+ )
+
+ get_photos_in_set(s)
+
+def get_photos_in_set(set):
+ BASE_PATH = 'http://flickr.com/services/rest/'
+ client = FlickrClient(BASE_PATH, API_KEY)
+ data = client.flickr_photosets_getPhotos(user_id=settings.FLICKR_USER_ID, photoset_id=str(set.set_id))
+ for post in data.findall('photoset/photo'):
+ info = dict((k, smart_unicode(post.get(k))) for k in post.keys())
+ photo = Photo.objects.get(flickr_id__exact=str(info['id']))
+ set.photos.add(photo)
+
+
+"""
+def sync_flickr_comments(*args, **kwargs):
+ cur_page = 1 # Start on the first page of the stream
+ paginate_by = 100 # Get 100 photos at a time
+ inc = 1 # Set our dupe flag for the following loop
+ # Get our flickr client running
+ client = FlickrClient(settings.FLICKR_API_KEY)
+ # get total number of photos in stream
+ total = client.flickr_people_getInfo(user_id=settings.FLICKR_USER_ID)
+ total_num = safestr(total.person.photos.count)
+ while (inc < int(total_num)):
+ photos = client.flickr_people_getPublicPhotos(user_id=settings.FLICKR_USER_ID, page=cur_page, per_page=paginate_by,extras="date_upload,date_taken,geo")
+ incr = 1
+ for photo in photos.photos:
+ do_photo_comments(photo("id"),photo("secret"))
+ inc = inc+1
+ incr = incr+1
+ print cur_page
+ if incr == 100:
+ cur_page = cur_page+1
+
+
+
+def do_photo_comments(id, secret):
+ # Get our flickr client running
+ client = FlickrClient(settings.FLICKR_API_KEY)
+ photo = Photo.objects.get(flickr_id=id, flickr_secret=secret)
+ comments = client.flickr_photos_comments_getList(user_id=settings.FLICKR_USER_ID, photo_id=id)
+ for item in comments.comments:
+ try:
+ item
+ print item('authorname')
+ dt = datetime.datetime.fromtimestamp(float(item('datecreate')))
+ ctype = ContentType.objects.get_for_model(Photo)
+ try:
+ f = FreeComment.objects.get(content_type=ctype, object_id=photo.id, submit_date=dt)
+ #print f.id
+ except ObjectDoesNotExist:
+ if safestr(item('authorname')) == 'luxagraf':
+ mail = 'hyper@luxagraf.net'
+ else:
+ mail = slugify(item('authorname'))+'@flickr.com'
+ c = FreeComment.objects.create (
+ content_type = ctype,
+ object_id = photo.id,
+ comment = safestr(item),
+ person_name = safestr(item('authorname')),
+ person_email = mail,
+ person_url = item('permalink'),
+ is_public = True,
+ site_id = 1,
+ approved = 0,
+ submit_date = dt
+ )
+
+ except AttributeError:
+ pass
+
+ def get_country_name(lat,long):
+ name = GeoClient.findCountrySubdivision(lat,long, http_proxy=None)
+ if name.countrySubdivision.countryCode.PCDATA == "US":
+ r_name = "US-%s" %(force_unicode(STATE_LIST[name.countrySubdivision.adminCode1.PCDATA]))
+ else:
+ r_name = force_unicode(name.countrySubdivision.countryName.PCDATA)
+ return r_name
+
+
+def create_size(self, photosize):
+ if self.size_exists(photosize):
+ return
+ if not os.path.isdir(self.cache_path()):
+ os.makedirs(self.cache_path())
+ try:
+ im = Image.open(self.get_image_filename())
+ except IOError:
+ return
+ if im.size == photosize.size():
+ shutil.copy(self.get_image_filename(),
+ self._get_SIZE_path(photosize))
+ return
+ cur_width, cur_height = im.size
+ new_width, new_height = photosize.size()
+ if photosize.crop:
+ ratio = max(float(new_width)/cur_width,float(new_height)/cur_height)
+ x = (cur_width * ratio)
+ y = (cur_height * ratio)
+ xd = abs(new_width - x)
+ yd = abs(new_height - y)
+ x_diff = int(xd / 2)
+ y_diff = int(yd / 2)
+ if self.crop_from == 'top':
+ box = (int(x_diff), 0, int(x_diff+new_width), new_height)
+ elif self.crop_from == 'left':
+ box = (0, int(y_diff), new_width, int(y_diff+new_height))
+ elif self.crop_from == 'bottom':
+ box = (int(x_diff), int(yd), int(x_diff+new_width), int(y)) # y - yd = new_height
+ elif self.crop_from == 'right':
+ box = (int(xd), int(y_diff), int(x), int(y_diff+new_height)) # x - xd = new_width
+ else:
+ box = (int(x_diff), int(y_diff), int(x_diff+new_width), int(y_diff+new_height))
+ resized = im.resize((int(x), int(y)), Image.ANTIALIAS).crop(box)
+ else:
+ if not new_width == 0 and not new_height == 0:
+ if cur_width > cur_height:
+ ratio = float(new_width)/cur_width
+ else:
+ ratio = float(new_height)/cur_height
+ else:
+ if new_width == 0:
+ ratio = float(new_height)/cur_height
+ else:
+ ratio = float(new_width)/cur_width
+ resized = im.resize((int(cur_width*ratio), int(cur_height*ratio)), Image.ANTIALIAS)
+
+ # Apply effect if found
+ if self.effect is not None:
+ resized = self.effect.process(resized)
+ elif photosize.effect is not None:
+ resized = photosize.effect.process(resized)
+
+ # save resized file
+ resized_filename = getattr(self, "get_%s_path" % photosize.name)()
+ try:
+ if im.format == 'JPEG':
+ resized.save(resized_filename, 'JPEG', quality=int(photosize.quality),
+ optimize=True)
+ else:
+ resized.save(resized_filename)
+ except IOError, e:
+ if os.path.isfile(resized_filename):
+ os.unlink(resized_filename)
+ raise e
+
+"""
+
+
+
+"""
+for p in photos.photos.photo:
+ try:
+ row = Photo.objects.get(flickr_id=p.id, flickr_secret=p.secret)
+ # If the row exists already, set the dupe flag
+ dupe = True
+ #print 'already have '+p.id+' moving on'
+ except ObjectDoesNotExist:
+ #assign the photo to a place, uses "default" if the photo isn't near anything
+ place = place_handler(force_unicode(p.latitude)+","+force_unicode(p.longitude))
+ #Grab tags
+ tags = client.flickr_photos_getInfo(user_id=settings.FLICKR_USER_ID, photo_id=force_unicode(p.id))
+ # grab exif data
+ exif = exif_handler(client.flickr_photos_getExif(user_id=API_KEY, photo_id=safestr(p.id)))
+ # sort the exif data if it's available
+ if exif.has_key("Aperture"):
+ aperture = exif["Aperture"]
+ else: aperture = ''
+ if exif.has_key("Make"):
+ make = exif["Make"]
+ else: make = ''
+ if exif.has_key("Model"):
+ model = exif["Model"]
+ else: model = ''
+ if exif.has_key("Exposure"):
+ exposure = exif["Exposure"]
+ else: exposure = ''
+ if exif.has_key("ISO Speed"):
+ iso = exif["ISO Speed"]
+ else: iso = ''
+ if exif.has_key("Focal Length"):
+ length = exif["Focal Length"]
+ else: length = ''
+ if exif.has_key("Date and Time (Original)"):
+ dto = flickr_datetime_to_datetime(exif["Date and Time (Original)"].replace(':', '-', 2))
+ else: dto = flickr_datetime_to_datetime(p.datetaken)
+ photo = Photo.objects.create(
+ title = p.title,
+ flickr_id = p.id,
+ flickr_owner = p.owner,
+ flickr_server = p.server,
+ flickr_secret = p.secret,
+ flickr_originalsecret = tags.photo.originalsecret,
+ flickr_farm = p.farm,
+ pub_date = flickr_datetime_to_datetime(p.datetaken),
+ description = force_unicode(tags.photo.description.PCDATA),
+ exif_aperture = aperture,
+ exif_make = make,
+ exif_model = model,
+ exif_shutter = exposure,
+ exif_iso = iso,
+ exif_lens = length,
+ exif_date = dto,
+ gps = force_unicode(p.latitude)+","+force_unicode(p.longitude),
+ place = place,
+ tags = str(", ".join(t.raw for t in tags.photo.tags.tag)).lower()
+ )
+ make_local_size(photo)
+ #if (dupe):
+ #break
+
+"""
+
+from locations.models import Location
+from photos.models import Photo
+from django.contrib.gis.geos import Point
+
+def find_loc(photos):
+ for photo in photos:
+ p = Point(photo.lon, photo.lat, srid=4326)
+ try:
+ loc = Location.objects.filter(geometry__contains=p).get()
+ photo.location = loc
+ print photo.id
+ photo.save()
+ except Location.DoesNotExist:
+ print "photo %s does not fall within any exisiting location" %(photo.id) \ No newline at end of file
diff --git a/apps/photos/views.py b/apps/photos/views.py
new file mode 100644
index 0000000..23efbde
--- /dev/null
+++ b/apps/photos/views.py
@@ -0,0 +1,49 @@
+from django.shortcuts import render_to_response,get_object_or_404
+from django.template import RequestContext
+from django.views.generic.list_detail import object_list
+from django.http import Http404
+
+from tagging.models import Tag,TaggedItem
+from photos.models import Photo,PhotoGallery
+from locations.models import Country, Region
+
+def potd_list(request):
+ potd_obj = Tag.objects.filter(name__exact='potd')
+ qs = TaggedItem.objects.get_by_model(Photo, potd_obj)
+ return render_to_response('photos/photo-of-the-day.html', {'object_list': qs,})
+
+
+
+def gallery_list(request,page):
+ request.page_url = '/photos/%d/'
+ request.page = int(page)
+ qs = PhotoGallery.objects.all().order_by('-id')
+ context = {
+ 'country_list': Country.objects.filter(visited=True),
+ 'region_list': Region.objects.all()
+ }
+ return object_list(request, queryset=qs, template_name='archives/photos.html',
+ extra_context=context)
+
+
+"""
+Grabs entries by region or country
+"""
+def gallery_list_by_area(request,slug,page):
+ request.page_url = '/photos/'+slug+'/%d/'
+ request.page = int(page)
+ try:
+ region = Region.objects.get(slug__exact=slug)
+ qs = PhotoGallery.objects.filter(region = region).order_by('-id')
+ except:
+ region = Country.objects.get(slug__exact=slug)
+ qs = PhotoGallery.objects.filter(location__state__country = region).order_by('-id')
+ if not region:
+ raise Http404
+ context = {
+ 'region': region,
+ 'country_list': Country.objects.filter(visited=True),
+ 'region_list': Region.objects.all()
+ }
+ return object_list(request, queryset=qs, template_name='archives/photos.html',
+ extra_context=context)
diff --git a/base_urls.py b/base_urls.py
new file mode 100644
index 0000000..95e4b8f
--- /dev/null
+++ b/base_urls.py
@@ -0,0 +1,55 @@
+from django.conf.urls.defaults import *
+from django.contrib import admin
+from django.views.generic import list_detail
+from django.views.generic.simple import redirect_to,direct_to_template
+from django.contrib.sitemaps import FlatPageSitemap
+from django.conf import settings
+
+from blog.models import BlogSitemap
+from locations.models import WritingbyLocationSitemap
+
+admin.autodiscover()
+
+
+sitemaps = {
+ 'blog': BlogSitemap,
+ 'flatpages': FlatPageSitemap,
+ #'locations': WritingbyLocationSitemap
+}
+
+
+# old page redirects
+urlpatterns = patterns('',
+ (r'^2003/nov/02/take-me-your-leader-ii/$', direct_to_template, {'template': 'static/oldcontent.html'}),
+ (r'^2003/aug/07/take-me-your-leader/$', direct_to_template, {'template': 'static/oldcontent.html'}),
+ (r'^2004/jan/07/david-foster-wallace-infinity/$', direct_to_template, {'template': 'static/oldcontent.html'}),
+)
+
+if settings.DEVELOPMENT:
+ urlpatterns = patterns('',
+ (r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/Users/lux/Sites/luxagraf/media'}),
+ (r'^images/(?P<path>.*)$', 'django.views.static.serve', {'document_root': '/Users/lux/Sites/luxagraf/images'}),
+ )
+
+urlpatterns += patterns('',
+ (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+ (r'^admin/(.*)', admin.site.root),
+ (r'^robots.txt$', direct_to_template, {'template': 'archives/robots.html'}),
+ (r'^googleb11655cd59dacf3c.html$', direct_to_template, {'template': 'static/gverify.html'}),
+ (r'^contact/', include('contact_form.urls')),
+ #(r'^photo-of-the-day/$', 'luxagraf.photos.views.potd_list'),
+ (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
+ (r'^writing/', include('blog.urls')),
+ #Entry detail i.e. /year/month/day/my-title/
+ (r'(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'blog.views.entry_detail'),
+ # locations
+ (r'^locations/', include('locations.urls')),
+ (r'^photos/', include('photos.urls')),
+ (r'^photo/', include('photos.detail_urls')),
+ # map
+ (r'^map/', include('locations.urls')),
+ #homepage
+ (r'^$', 'blog.views.home'), #'blog.views.home'),
+ #static pages
+ #(r'(?P<page>[-\w]+)/$', 'static.views.page_view'),
+)
diff --git a/media/css/base.css b/media/css/base.css
new file mode 100644
index 0000000..585eeb0
--- /dev/null
+++ b/media/css/base.css
@@ -0,0 +1,471 @@
+/* -------------- reset from blueprint ---------------------- */
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ font-size: 100%;
+ vertical-align: baseline;
+ border: 0;
+ outline: 0;
+ background: transparent;
+}
+
+ol, ul { list-style: none; }
+blockquote, q { quotes: none; }
+:focus { outline: 0; }
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/* --------------------- Basic Typography Stuff ------------------------ */
+
+* {margin:0;}
+html {height:100%;}
+body {
+ /*url("../img/underline.gif")*/
+ background: #faf9f4 url(../img/body-bg.gif) repeat-x;
+ font-family: Georgia, "Times New Roman", Times, Serif;
+ /* font-size 14px */
+ font-size: 87.5%;
+ /* line height of 24 px */
+ line-height: 1.5em;
+ color: #473d39;
+}
+body {height:100%;text-align: center;}
+
+html>body { font-size: 14px;}
+
+a:link {
+ text-decoration: none;
+ font-weight: bold;
+ color: #333;
+}
+
+a:visited {
+ color: #736357;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+a:hover {
+ color: #b53a04 !important;
+ text-decoration: none;
+ font-weight: bold;
+}
+
+h2, h3 {
+ color: #473d39;
+ font-size: 2.3em;
+ line-height: 1.5em;
+ letter-spacing: -1px;
+ font-weight: normal;
+}
+
+h3 a, h2 a { font-weight: normal !important; }
+blockquote { margin: 17px 20px; }
+
+p {
+ margin-bottom: 1.5em;
+ margin-top: 1.5em;
+}
+
+/* head ---------------------------------------------------------------------------------------- */
+#header {
+ width: 100%;
+ width: 940px;
+ height: 107px;
+ background: #201a11;
+ margin: 0 auto;
+}
+
+#header h1 a {
+ display: block;
+ text-indent: -9999px;
+ width: 500px;
+ height: 100px;
+ float:left;
+ margin-top: 7px;
+ background: url(../img/luxheadnewer.gif) -4px 0 no-repeat;
+}
+
+#header h1 a:hover { background: url(../img/luxheadnewer.gif) -4px -100px no-repeat; }
+
+ul#menu {
+ float: right;
+ width: 150px;
+ margin-right: 43px;
+ margin-top: 73px;
+}
+
+ul#menu li {
+ float: left;
+ margin: 3px;
+}
+
+ul#menu li a {
+ display: block;
+ text-indent: -9999px;
+ width: 43px;
+ height: 16px;
+}
+
+ul#menu li#stories a { background: url(../img/stories.gif) 0 0 no-repeat; }
+ul#menu li#stories a:hover { background: url(../img/stories.gif) 0 -15px no-repeat; }
+ul#menu li#photos a { background: url(../img/photos.gif) 0 0 no-repeat; }
+ul#menu li#photos a:hover { background: url(../img/photos.gif) 0 -15px no-repeat; }
+
+ul#menu li#map a {
+ background: url(../img/map.gif) 0 0 no-repeat;
+ width: 25px;
+}
+
+ul#menu li#map a:hover { background: url(../img/map.gif) 0 -15px no-repeat; }
+ul#menu li a:hover { color: #b53a04; }
+
+/* Main Layout ---------------------------------------------------------- */
+.container {
+ width: 940px;
+ margin: 2em auto -32px auto;
+ min-height: 100%;
+ height: auto !important;
+ height: 100%;
+ text-align: left;
+}
+
+div#primary {
+ width: 655px;
+ float: left;
+}
+
+div.content, div.archives dd {
+ width: 465px;
+ float: right;
+ padding: 0 0 30px 0;
+}
+
+/* Date section */
+div.meta, div.photo-archives span.date, div.archives span.date {
+ line-height: 1.916em;
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ font-weight: bold;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: .5px;
+ color: #786E69;
+ width: 180px;
+}
+
+div.meta { margin-top: 13px; }
+
+div.archives span.date {
+ font-size: 10px;
+ margin-top: 6px;
+}
+
+div.meta a:hover { color: #b53a04; }
+
+/* --------- Archive Sections (bottom homepage and primary archives --------- */
+body#home div.archives { clear: both; }
+
+body#home div.archives h4#archive-header, #comment-header,#dsq-add-new-comment {
+ margin-left: 190px;
+ margin-bottom: 1.5em;
+ border-bottom: 1px solid #e2d7c6;
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ color: #666;
+ font-weight: bold;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+#comment-header,#dsq-add-new-comment {
+ margin-left:0;
+}
+
+div.archives li {
+ clear: both;
+ margin-bottom: 1.5em;
+}
+
+div.archives li dl dd { clear: right; }
+
+div.archives span.post-image {
+ float: left;
+ width: 190px;
+}
+
+div.archives span.post-image img { border: #000 5px solid; }
+
+div.archives span.date {
+ display: block;
+ line-height: 24px;
+ width: auto;
+}
+
+div.archives span.more {
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ color: #666;
+ font-weight: bold;
+ font-size: 10px;
+ display: block;
+ text-transform: uppercase;
+}
+
+div.archives h3 {
+ padding-bottom: 0px !important;
+ font-size: 22px !important;
+ letter-spacing: -1px !important;
+ padding-top: 8px !important;
+ line-height: 16px !important;
+}
+
+/* Primary Column special cases */
+body#writing-archive div#primary h2 {
+ margin: 0 0 0 190px;
+ line-height: 36px;
+ padding: 0 0 26px 0;
+ width: 465px;
+ float: right;
+}
+
+/* Metadata section at the end of each entry */
+div#extra {
+ font-style: italic;
+ margin-left: 40px;
+ width: 385px;
+ font-size: 90%;
+}
+div.photo-archives {
+ margin-left: 190px;
+ width: 600px;
+}
+div.photo-archives li {float: left; padding-right: 30px; width: 240px;}
+div.photo-archives li dd {width: 240px; margin-left: 5px; background: #f3f;}
+div.photo-archives span.date { display: block;}
+div.photo-archives img {
+ border: #000 10px solid;
+}
+div#extra span { font-style: normal; }
+
+div.pagination, div#nav {
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ color: #666;
+ font-weight: bold;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ display: block;
+}
+
+div.pagination-wrapper {
+ clear: both;
+ width: 655px;
+}
+
+div.pagination-wrapper .pagination { float: right; }
+
+div.pagination .page {
+ font-size: 12px;
+ padding 5px: ;
+}
+
+div.pagination .disabled { display: none; }
+div#nav li { display: inline; }
+div#nav li.next { margin-left: 17px; }
+div#nav div.first { padding-top: 49px; }
+
+/* ------------------- Sidebar --------------------------------------*/
+#sidebar {
+ width: 190px;
+ float: right;
+ margin-top: 2em;
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ color: #444;
+ font-size: 80%;
+ line-height: 1.5em;
+}
+
+#sidebar h4, #sidebar #nav {
+ font-weight: bold;
+ margin-bottom: .3em;
+ margin-top: 1.5em;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+#sidebar h4.first { margin-top: 0 !important; }
+
+#sidebar #nav {
+ margin-top: 0;
+ margin-bottom: 3em;
+ font-size: 95%;
+}
+
+#sidebar .blok { width: 170px; }
+
+#sidebar .blok ul li {
+ color: #736357;
+ margin-left: 5px;
+ font-family: Georgia, "Times New Roman", Times, Serif;
+}
+
+#sidebar .blok ul li a:hover { color: #b53a04; }
+#sidebar .blok ul li a { font-weight: normal; }
+
+#sidebar ul.follow li img {
+ margin-right: 5px;
+ position: relative;
+ top: 2px;
+}
+
+#sidebar .blok div#nav div.pagination .page {
+ font-size: 12px !important;
+ padding 5px: ;
+}
+
+#sidebar .blok div#nav .pagination { float: none; }
+
+#sidebar p {
+ font-family: Georgia, "Times New Roman", Times, Serif;
+ margin: .3em 5px;
+}
+
+/*----------------------------- Map ------------------------------------------ */
+#map-canvas {
+ margin-left: -200px;
+ height: 450px;
+ width: 710px;
+ border: #000 10px solid;
+ margin-top: 1.5em;
+}
+
+#map-canvas p {
+ font-size: 90% !important;
+ margin-top: 0;
+ margin-bottom: 0 !important;
+}
+
+.mcanvas { height: 220px; }
+.mcanvas { height: auto; }
+
+#map-canvas span {
+ font-size: 10px;
+ font-weight: bold;
+ letter-spacing: 1.3px;
+ color: #786E69;
+}
+
+#map-canvas img {
+ float: left;
+ margin: 5px 5px 0px 0;
+ border: #000 4px solid;
+}
+
+/*This might be against the terms of service, but what the hell */
+img[src="http://maps.google.com/intl/en_us/mapfiles/poweredby.png"],
+#map-canvas>div:first-child+div>*,img[src="http://maps.google.com/intl/en_us/mapfiles/poweredby.png"] { display: none; }
+
+/* -------------------- Disqus comments ------------------------- */
+
+/* a site promo at the top and bottom of the thread? Let's not get greedy. */
+
+.dsq-brlink {display: none;}
+
+h4#comment-header { padding-top: 5em;}
+
+/* -------------------------- footer --------------------------------------*/
+.push { height: 32px; }
+
+#foot {
+ height:32px;
+ clear: both;
+ position: relative !important;
+ background: #201a11;
+ width: 100%;
+ bottom: 0 !important;
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande", "Lucida Sans", Verdana, Arial, sans-serif;
+ font-weight: bold;
+ font-size: 12px;
+ color: #cac0ad;
+}
+
+#footer { padding-top: 6px; margin: 0 auto; width: 940px;
+ }
+span#foot-float { float: left; }
+
+#footer ul {
+ display: inline;
+ float: left;
+ margin-left: 4px;
+ width: 200px;
+}
+
+#footer ul li {
+ display: inline;
+ margin: 0 4px;
+ text-transform: uppercase;
+}
+
+#footer p {
+ float: right;
+ display: inline;
+ margin: 0;
+ font-size: 85%;
+}
+
+/* ------------ Misc span and image classes -------------------*/
+span.break {
+ display: block;
+ margin: 1.44px 0 1.44px 80px;
+ text-align: center;
+ width: 300px;
+ height: 8px;
+ background: url(img/break.gif) no-repeat;
+}
+
+span.drop {
+ display: block;
+ font-size: 5.5em;
+ float: left;
+ padding: 21px 5px 5px 0;
+ overflow: visible;
+}
+
+p.pull-quote {
+ font-style: italic;
+ margin-left: 40px;
+ width: 385px;
+ font-size: 95%;
+ text-align: center;
+}
+
+p.pull-quote cite {
+ display: block;
+ font-style: normal;
+}
+ul.tsites li a { font-weight: bold !important;}
+.small { font-size: 75%;}
+img.postpic, img.postpicright {
+ display: block;
+ margin: .3em .6em;
+ border: #000 10px solid;
+ clear: both;
+}
+
+img.postpic {
+ float: left;
+ margin-left: 0;
+ margin-top: .3em;
+}
+
+img.postpicright {
+ float: right;
+ margin-right: 0;
+}
+
+img.postpicleft {
+ float: left;
+ margin: 5px;
+}
diff --git a/media/css/ie6.css b/media/css/ie6.css
new file mode 100644
index 0000000..b2194bf
--- /dev/null
+++ b/media/css/ie6.css
@@ -0,0 +1,10 @@
+ul#menu {
+ margin-right: 24px;
+}
+
+ul#menu li a { line-height: 15px;}
+div.meta { margin-top: 0px; }
+span.drop {
+ padding: 21px 5px 15px 0;
+ overflow: visible;
+} \ No newline at end of file
diff --git a/media/img/body-bg.gif b/media/img/body-bg.gif
new file mode 100644
index 0000000..c8d100d
--- /dev/null
+++ b/media/img/body-bg.gif
Binary files differ
diff --git a/media/img/entry_marker.png b/media/img/entry_marker.png
new file mode 100644
index 0000000..b398a88
--- /dev/null
+++ b/media/img/entry_marker.png
Binary files differ
diff --git a/media/img/luxheadnewer.gif b/media/img/luxheadnewer.gif
new file mode 100644
index 0000000..2eb8e9c
--- /dev/null
+++ b/media/img/luxheadnewer.gif
Binary files differ
diff --git a/media/img/map.gif b/media/img/map.gif
new file mode 100644
index 0000000..a89c9de
--- /dev/null
+++ b/media/img/map.gif
Binary files differ
diff --git a/media/img/marker-entry.png b/media/img/marker-entry.png
new file mode 100644
index 0000000..cad0d3e
--- /dev/null
+++ b/media/img/marker-entry.png
Binary files differ
diff --git a/media/img/photos.gif b/media/img/photos.gif
new file mode 100644
index 0000000..119e1c8
--- /dev/null
+++ b/media/img/photos.gif
Binary files differ
diff --git a/media/img/shadow.png b/media/img/shadow.png
new file mode 100644
index 0000000..62af3ea
--- /dev/null
+++ b/media/img/shadow.png
Binary files differ
diff --git a/media/img/stories.gif b/media/img/stories.gif
new file mode 100644
index 0000000..cadf236
--- /dev/null
+++ b/media/img/stories.gif
Binary files differ
diff --git a/media/img/underline.gif b/media/img/underline.gif
new file mode 100644
index 0000000..86a73a8
--- /dev/null
+++ b/media/img/underline.gif
Binary files differ
diff --git a/templates/404.html b/templates/404.html
new file mode 100644
index 0000000..56b58a4
--- /dev/null
+++ b/templates/404.html
@@ -0,0 +1,30 @@
+{% extends 'base.html' %}
+{% load typogrify %}
+{% block pagetitle %}Luxagraf | Error 404 {% endblock %}
+
+
+ {% block title %}404 Page Not Found{% endblock %}
+
+
+ {% block primary %}
+
+ <p><b>Oh my god you broke the internet.</b></p>
+
+<p><b>Al Gore is pissed.</b></p>
+<p><b>So is the hamster</b></p>
+<p>This is probably because of one or more of the following:</p>
+<ol class="generic">
+ <li>The hamster who fetches these pages has stepped out for a smoke break (he earns extra travel money over at the Philip Morris Labs where he poses as a rat and gets paid under the table).</li>
+ <li>The hamster who fetches these pages is actually at Phillip Morris Labs working right now in which case you'll just have to wait until he comes back here.</li>
+ <li>The hamster who fetches the pages finally made enough extra travel money working nights at the Philip Morris Labs to actually travel and is no longer running this site at all, in fact he's sipping Mai Tai's in Indonesia even as we speak, laughing that semi-sinister but always endearing high pitched squeak of a laugh.</li>
+ <li>The hamster may be innocent. Perhaps I was drunk and left the page in the back of a cab.</li>
+ <li>Wait, why is this our fault? Why are you so quick to blame the hamster? This could be your fault. You might have man hands or thick, clumsy fingers or that led you to type the wrong address. Or you might just be an idiot. Or you might be following the links of an idiot. See what happens when you visit other sites? Keep it simple, make the hamster happy. Limit your internet usage to luxagraf only.</li>
+ <li>Of course its possible that you're ahead of me and the page simply hasn't been invented yet, which makes you a genius. And explains why the hamster coouldn't find it.</li>
+ <li>It's also entirely possible that the page exists but the hamster doesn't want to show it to you. It maybe one of those "backroom" pages he has where secret stuff beyond your wildest imaginings are happening even now, right this second, just behind this blank white curtain. Stuff which you can only guess at. You can ask the hamster for an invite. Just email a full body shot, two forms of ID and a credit card number for verification purposes.</li>
+ </ol>
+
+ <p>Whatever the case you may <a href="javascript:history.go(-1)">return from whence you came</a>, <a href="/" title="Luxagraf Homepage">Head for the main page</a> or try searching again for whatever it is you wanted to find.</p>
+ {% endblock %}
+
+
+
diff --git a/templates/500.html b/templates/500.html
new file mode 100644
index 0000000..84954d9
--- /dev/null
+++ b/templates/500.html
@@ -0,0 +1,37 @@
+{% extends 'base.html' %}
+{% load typogrify %}
+{% block pagetitle %}Luxagraf | Internal Server Error {% endblock %}
+{% block metadescription %}Luxagraf: {{object.dek|striptags|safe}}{% endblock %}
+
+
+ {% block title %}500 Internal Server Error{% endblock %}
+
+
+ {% block primary %}
+
+ <p>Holy crap, you broke the internet. The proper authorities have been notified and it will most likely be working again soon.</p>
+
+ {% endblock %}
+
+
+
+{% block sidebar %}
+<div id="sidebar">
+ <div id="nav" class="first"><a href="{{featured.get_previous_published.get_absolute_url}}" title="">&laquo;Previous</a></div>
+ <div class="blok">
+ <h4>Topography</h4>
+ {% chunk "regions_sidebar" %}
+ </div>
+ <div class="blok">
+ <h4>About Luxagraf</h4>
+ {% chunk "about_sidebar" %}
+
+ </div>
+
+ <div class="blok">
+ <h4>Follow Along</h4>
+ {% chunk "follow_sidebar" %}
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/archives/homepage.html b/templates/archives/homepage.html
new file mode 100644
index 0000000..aceb846
--- /dev/null
+++ b/templates/archives/homepage.html
@@ -0,0 +1,60 @@
+{% extends 'base.html' %}
+{% load chunks %}
+{% load typogrify %}
+
+{%block bodyid%}id="home"{%endblock%}
+
+{% block title %}<a href="{{featured.get_absolute_url}}">{{featured.title|smartypants|safe}}</a>{% endblock %}
+
+{% block date %}{{featured.pub_date|date:"F j, Y"}}{% endblock %}
+
+{% block primary %}
+{{featured.lede|smartypants|widont|safe}}
+<span class="date"><a href="{{featured.get_absolute_url}}" title="{{object.title}}">More &raquo;</a></span>
+{% endblock %}
+
+{% block extrabody %}
+<div class="archives">
+ <h4 id="archive-header">Recently</h4>
+ <ul>
+ {% for object in object_list %}
+ <li>
+ <dl>
+ <dt>
+ <span class="post-image"><img src="{{object.get_thumbnail_url}}" alt="{{ object.title }}"/></span>
+ <h3><a href="{{object.get_absolute_url}}" title="{{object.title}}">{{object.title|smartypants|widont|safe}}</a></h3>
+ </dt>
+ <dd>
+ <span class="date">{{object.pub_date|date:"F j, Y"}} {% ifequal object.location.state.country.name "United States" %}({{object.location.name|smartypants|safe}}, {{object.location.state.name}}){%else%}({{object.location.name|smartypants|safe}}, {{object.location.state.country.name}}){%endifequal%}</span>
+ {{object.dek|safe}}
+ <span class="more"><a href="{{object.get_absolute_url}}" title="{{object.title}}">Read&nbsp;it&nbsp;&raquo;</a></span>
+ </dd>
+ </dl>
+ </li>
+ {% endfor %}
+ </ul>
+</div>
+{% endblock %}
+
+
+
+{% block sidebar %}
+<div id="sidebar">
+ <div id="nav" class="first"><a href="{{featured.get_previous_published.get_absolute_url}}" title="">&laquo;Previous</a></div>
+ <div class="blok">
+ <h4>Topography</h4>
+ {% chunk "regions_sidebar" %}
+ </div>
+ <div class="blok">
+ <h4>About Luxagraf</h4>
+ {% chunk "about_sidebar" %}
+
+ </div>
+
+ <div class="blok">
+ <h4>Follow Along</h4>
+ {% chunk "follow_sidebar" %}
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/archives/map.html b/templates/archives/map.html
new file mode 100644
index 0000000..2714861
--- /dev/null
+++ b/templates/archives/map.html
@@ -0,0 +1,150 @@
+{% extends 'base.html' %}
+{% load typogrify %}
+{% load truncateletters %}
+{% load slugify_under %}
+
+{% block pagetitle %}Luxagraf | Map and Trips{% endblock %}
+{% block metadescription %}Writing Archive, Luxagraf{% endblock %}
+
+{#==============================================
+Google Maps code
+==============================================#}
+{% block extrahead %}
+
+<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key={{map_key}}" type="text/javascript"></script>
+
+
+
+
+{% endblock %}
+{%block bodyid%}id="location"{%endblock%}
+{% block bodyevents %}onload="initialize()" onunload="GUnload()"{% endblock %}
+
+
+
+
+
+{% block primary %}
+ <div id="map-canvas">
+
+</div>
+ {% endblock %}
+
+{% block titleoverride %} {% endblock %}
+
+{% block sidebar %}
+<div id="sidebar">
+ <div class="blok">
+ <h4 class="first">Trips</h4>
+ <ul>
+ <li><a onclick="addRoute('yi_iAp}mmOlzd@egy@njcCcpOq{hDxyqAai_@kvhSio[b|zVjhNbmZ','BBBBBBB','#FF0000',12.0554, -85.1880, 8);" href="#">Nicaragua (2008)</a></li>
+ </ul>
+ <h4>Regions</h4>
+ <ul>
+ {%for region in region_list %}
+ <li><a href="#{{region.slug}}" onclick="focusCountry({{region.lat}}, {{region.lon}}, {{region.zoom_level}});" title="See all writing from {{region.name|title}}">{{region.name}}</a></li>
+ {% endfor %}
+ </ul>
+
+ <h4>Countries</h4>
+ <ul>
+ <li><a onclick="focusCountry(19.311143,2.460938,2);" href="#">All</a></li>
+ {%for country in country_list %}
+ <li><a href="#{{country.slug}}" onclick="focusCountry({{country.lat}}, {{country.lon}}, {{country.zoom_level}});" title="See all writing from {{country.name|title}}">{{country.name}}</a></li>
+ {% endfor %}
+ </ul>
+
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %}
+{% block js %}
+
+<script type="text/javascript">
+ var map = null;
+ function JLngLat(a,b) {
+ return new GLatLng(b,a)
+ }
+ function initialize() {
+ if (GBrowserIsCompatible()) {
+ var tinyIcon = new GIcon();
+ tinyIcon.image = "http://media.luxagraf.net/img/marker-entry.png";
+ tinyIcon.shadow = "http://media.luxagraf.net/img/shadow.png";
+ tinyIcon.iconSize = new GSize(12, 20);
+ tinyIcon.shadowSize = new GSize(22, 20);
+ tinyIcon.iconAnchor = new GPoint(6, 20);
+ tinyIcon.infoWindowAnchor = new GPoint(5, 5);
+
+ //var iconOptions = {};
+ //iconOptions.primaryColor = "#a53503";
+ //iconOptions.strokeColor = "#201a11";
+ //var icon = MapIconMaker.createLabeledMarkerIcon(iconOptions);
+
+ var location = window.location.hash;
+ var pts = new Array();
+ {%for c in country_list%}pts[{{forloop.counter0}}] = ["#{{c.slug}}", {{c.lat}},{{c.lon}},{{c.zoom_level}}];{% endfor %}
+ {%for c in region_list%}pts[pts.length] = ["#{{c.slug}}", {{c.lat}},{{c.lon}},{{c.zoom_level}}];{% endfor %}
+ if (location.length>1) {
+ for (i=0;i<pts.length;i++) {
+ if (location == pts[i][0]) {
+ point = new GLatLng(pts[i][1],pts[i][2]);
+ zoom = pts[i][3];
+ break;
+ } else {
+ point = new GLatLng(19.311143,2.460938);
+ zoom = 2;
+ }
+ }
+ } else {
+ point = new GLatLng(19.311143,2.460938);
+ zoom = 2;
+ }
+
+ // create a new map.
+ map = new GMap2(document.getElementById("map-canvas"));
+ map.enableContinuousZoom()
+ map.setCenter(point, zoom, G_PHYSICAL_MAP);
+
+ // basic control and overview (closed by default)
+ map.addControl(new GSmallZoomControl());
+ var ov = new GOverviewMapControl(new GSize(100,100));
+ map.addControl(ov);
+ ov.hide(true);
+
+ // Add a marker for each project
+
+ {% for entry in object_list %}
+ point_{{entry.title|truncatewords:2|slugify_under}} = JLngLat{{entry.point.coords}};
+ markerOptions = { clickable:true, draggable:false, icon:tinyIcon};
+ marker_{{entry.title|truncatewords:2|slugify_under}} = new GMarker(point_{{entry.title|truncatewords:2|slugify_under}}, markerOptions);
+ map.addOverlay(marker_{{entry.title|truncatewords:2|slugify_under}});
+ marker_{{entry.title|truncatewords:2|slugify_under}}.info_window_content = '<div class="mcanvas"><h4>{{entry.title}}<\/h4><span>{{entry.pub_date|date:"F j, Y"}} ({% ifequal entry.location.state.country.name "United States" %}{{entry.location.name|smartypants|safe}}, {{entry.location.state.name}}){%else%}{{entry.location.name|smartypants|safe}}, {{entry.location.state.country.name}}){%endifequal%}<\/span><p><img src="{{entry.get_thumbnail_url}}" height="100" alt="{{ entry.title }}" \/>{{entry.dek|escapejs}} <a href="{{entry.get_absolute_url}}">Read it &raquo;<\/a><\/p><\/div>'
+ marker_{{entry|truncatewords:2|slugify_under}}.bindInfoWindowHtml(marker_{{entry|truncatewords:2|slugify_under}}.info_window_content, {maxWidth:400});
+ GEvent.addListener(marker_{{entry.title|truncatewords:2|slugify_under}}, "click", function() {
+ map.panTo(point_{{entry.title|truncatewords:2|slugify_under}}, 2);
+ });
+
+ {% endfor %}
+ }
+ }
+
+ // center on a country
+ function focusCountry(latitude, longitude, zoom) {
+ map.setZoom(zoom);
+ map.panTo(new GLatLng(latitude, longitude))
+ }
+ function addRoute(line,levels,color,lat,lon,zoom){
+ var encodedPolyline = new GPolyline.fromEncoded({
+ color: color,
+ weight: 5,
+ points: line,
+ levels: levels,
+ zoomFactor: 32,
+ numLevels: 4
+ });
+ focusCountry(lat,lon,zoom);
+ map.addOverlay(encodedPolyline);
+ }
+ </script>
+
+{%endblock%} \ No newline at end of file
diff --git a/templates/archives/photos.html b/templates/archives/photos.html
new file mode 100644
index 0000000..425e375
--- /dev/null
+++ b/templates/archives/photos.html
@@ -0,0 +1,77 @@
+{% extends 'base.html' %}
+{% load chunks %}
+{% load typogrify %}
+{% load pagination_tags %}
+
+{% block pagetitle %}Luxagraf | {% if region %}Photos from {{region.name|title|smartypants|safe}}{%else%}Photos from Around the World {%endif%}{% endblock %}
+{% block metadescription %}Photo Archive, Luxagraf{% endblock %}
+
+
+{%block bodyid%}id="writing-archive"{%endblock%}
+
+{% block title %}Photos from {% endblock %}
+
+{% block date %}{% endblock %}
+
+{% block primaryoverride %}<h2>{% if region %}Photos from {{region.name|title|smartypants|safe}}{%else%}Photos {%endif%}</h2>{% endblock %}
+{% block extrabody %}
+<div class="photo-archives">
+ <ul>
+ {% autopaginate object_list 20 %}
+ {% for object in object_list %}
+ <li>
+ <dl>
+ <dt>
+ <span class="post-image"><a href="{%comment%}{{object.get_absolute_url}}{%endcomment%}http://www.flickr.com/photos/luxagraf/sets/{{object.set_id}}/show/"><img src="{{object.get_main_image}}" alt="{{ object.set_title }}"/></a></span>
+ </dt>
+ <dd>
+ <span class="date">{{object.set_title}} {%comment%}{% ifequal object.location.state.country.name "United States" %}({{object.location.name|smartypants|safe}}, {{object.location.state.name}}){%else%}({{object.location.name|smartypants|safe}}, {{object.location.state.country.name}}){%endifequal%}{%endcomment%}</span>
+ {{object.set_desc|truncatewords:30|smartypants|safe}}
+ </dd>
+ </dl>
+ </li>
+ {% endfor %}
+ </ul>
+
+ <div class="pagination-wrapper">{% paginate %}</div>
+</div>
+
+{% endblock %}
+
+
+
+{% block sidebar %}
+<div id="sidebar">
+ <div class="blok">
+ <h4 class="first">Regions</h4>
+ <ul>
+ {%for region in region_list %}
+ <li><a href="/photos/{{region.slug}}/1/" title="See all photos from {{region.name|title}}">{{region.name}}</a></li>
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="blok">
+ <h4>Countries</h4>
+ <ul>
+ {%for country in country_list %}
+ <li><a href="/photos/{{country.slug}}/1/" title="See all photos from {{country.name|title}}">{{country.name}}</a></li>
+ </li>
+ {% endfor %}
+ </ul>
+
+ </div>
+
+ <div class="blok">
+ <h4>About Luxagraf</h4>
+ {% chunk "about_sidebar" %}
+
+ </div>
+
+ <div class="blok">
+ <h4>Follow Along</h4>
+ {% chunk "follow_sidebar" %}
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/archives/region.html b/templates/archives/region.html
new file mode 100644
index 0000000..d4b8c4a
--- /dev/null
+++ b/templates/archives/region.html
@@ -0,0 +1,110 @@
+{% extends 'base.html' %}
+{% load chunks %}
+{% load truncateletters %}
+{% load slugify_under %}
+
+{% block pagetitle %}Luxagraf | Stories from {{region.name}}{% endblock %}
+{% block metadescription %}Writing Archive, Luxagraf{% endblock %}
+
+{#==============================================
+Google Maps code
+==============================================#}
+{% block extrahead %}
+
+<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key={{map_key}}" type="text/javascript" type="text/javascript"></script>
+<script src="http://gmaps-utility-library.googlecode.com/svn/trunk/mapiconmaker/1.1/src/mapiconmaker.js" type="text/javascript" type="text/javascript"></script>
+
+<script type="text/javascript">
+ var map = null;
+ function JLngLat(a,b) {
+ return new GLatLng(b,a)
+ }
+ function initialize() {
+ if (GBrowserIsCompatible()) {
+ var iconOptions = {};
+ iconOptions.primaryColor = "#a53503";
+ iconOptions.strokeColor = "#201a11";
+ var icon = MapIconMaker.createLabeledMarkerIcon(iconOptions);
+
+ point = new GLatLng({{region.lat}},{{region.lon}})
+ // create a new map.
+ map = new GMap2(document.getElementById("map-canvas"));
+ map.setCenter(point, {{region.zoom_level}}, G_PHYSICAL_MAP);
+
+ // basic control and overview (closed by default)
+ map.addControl(new GSmallZoomControl());
+ var ov = new GOverviewMapControl(new GSize(100,100));
+ map.addControl(ov);
+ ov.hide(true);
+
+ // Add a marker for each project
+
+ {% for entry in object_list %}
+ point_{{entry.title|truncatewords:2|slugify_under}} = JLngLat{{entry.point.coords}};
+ markerOptions = { clickable:true, draggable:false, icon:icon};
+ marker_{{entry.title|truncatewords:2|slugify_under}} = new GMarker(point_{{entry.title|truncatewords:2|slugify_under}}, markerOptions);
+ map.addOverlay(marker_{{entry.title|truncatewords:2|slugify_under}});
+ marker_{{entry.title|truncatewords:2|slugify_under}}.info_window_content = '<h4>{{entry.title}}<\/h4><span>{{entry.location|safe}}, {{entry.location.state.country.name|safe}}<\/span><p><img src="{{entry.thumbnail.url}}" height="100" alt="{{ entry.title }}" \/>{{entry.dek|escapejs}} <a href="{{entry.get_absolute_url}}">Read it &raquo;<\/a><\/p>'
+ marker_{{entry|truncatewords:2|slugify_under}}.bindInfoWindowHtml(marker_{{entry|truncatewords:2|slugify_under}}.info_window_content, {maxWidth:400});
+ GEvent.addListener(marker_{{entry.title|truncatewords:2|slugify_under}}, "click", function() {
+ map.panTo(point_{{entry.title|truncatewords:2|slugify_under}}, 2);
+ });
+
+ {% endfor %}
+ }
+ }
+
+ // center on a city
+ function focusCity(marker, latitude, longitude) {
+ point = new GLatLng(latitude, longitude)
+ map.panTo(point)
+ map.setZoom(6);
+ marker.openInfoWindowHtml(marker.info_window_content)
+ }
+ // center on a country
+ function focusCountry(latitude, longitude, zoom) {
+ p = new GLatLng(latitude, longitude)
+ map.panTo(p)
+ map.setZoom(zoom);
+ }
+ function addRoute(line,levels,color,lat,lon,zoom){
+ var encodedPolyline = new GPolyline.fromEncoded({
+ color: color,
+ weight: 5,
+ points: line,
+ levels: levels,
+ zoomFactor: 32,
+ numLevels: 4
+});
+focusCountry(lat,lon,zoom);
+map.addOverlay(encodedPolyline);
+
+ }
+ </script>
+
+{% endblock %}
+{%block bodyid%}id="location"{%endblock%}
+{% block bodyevents %}onload="initialize()" onunload="GUnload()"{% endblock %}
+
+
+
+
+
+{% block primary %}
+ <div id="map-canvas">
+
+</div>
+ {% endblock %}
+
+{% block titleoverride %} {% endblock %}
+
+{% block sidebar %}
+<div id="sidebar">
+ <div class="blok">
+ <h4 class="first">Topography</h4>
+ {% chunk "regions_sidebar" %}
+
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/archives/robots.html b/templates/archives/robots.html
new file mode 100644
index 0000000..ac2bc1f
--- /dev/null
+++ b/templates/archives/robots.html
@@ -0,0 +1 @@
+User-agent: * Disallow: /stats/ Disallow: /media/js/ Disallow: /media/img/ \ No newline at end of file
diff --git a/templates/archives/writing.html b/templates/archives/writing.html
new file mode 100644
index 0000000..f3bc288
--- /dev/null
+++ b/templates/archives/writing.html
@@ -0,0 +1,79 @@
+{% extends 'base.html' %}
+{% load chunks %}
+{% load typogrify %}
+{% load pagination_tags %}
+
+{% block pagetitle %}Luxagraf | {% if region %}Writings from {{region.name|title|smartypants|safe}}{%else%}Writing Archive {%endif%}{% endblock %}
+{% block metadescription %}Writing Archive, Luxagraf{% endblock %}
+
+
+{%block bodyid%}id="writing-archive"{%endblock%}
+
+{% block title %}Writing Archive{% endblock %}
+
+{% block date %}{% endblock %}
+
+{% block primaryoverride %}<h2>{% if region %}Writings from {{region.name|title|smartypants|safe}}{%else%}Writing Archive {%endif%}</h2>{% endblock %}
+{% block extrabody %}
+<div class="archives">
+ <ul>
+ {% autopaginate object_list 10 %}
+ {% for object in object_list %}
+ <li>
+ <dl>
+ <dt>
+ <span class="post-image"><img src="{%if object.thumbnail%}{{object.get_thumbnail_url}}" alt="{{ object.title }}{%endif%}"/></span>
+ <h3><a href="{{object.get_absolute_url}}" title="{{object.title}}">{{object.title|smartypants|widont|safe}}</a></h3>
+ </dt>
+ <dd>
+ <span class="date">{{object.pub_date|date:"F j, Y"}} {% ifequal object.location.state.country.name "United States" %}({{object.location.name|smartypants|safe}}, {{object.location.state.name}}){%else%}({{object.location.name|smartypants|safe}}, {{object.location.state.country.name}}){%endifequal%}</span>
+ {{object.dek|safe}}
+ <span class="more"><a href="{{object.get_absolute_url}}" title="{{object.title}}">Read it &raquo;</a></span>
+ </dd>
+ </dl>
+ </li>
+ {% endfor %}
+ </ul>
+
+ <div class="pagination-wrapper">{% paginate %}</div>
+</div>
+
+{% endblock %}
+
+
+
+{% block sidebar %}
+<div id="sidebar">
+ <div class="blok">
+ <h4 class="first">Regions</h4>
+ <ul>
+ {%for region in region_list %}
+ <li><a href="/writing/{{region.slug}}/1/" title="See all writing from {{region.name|title}}">{{region.name}}</a></li>
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="blok">
+ <h4>Countries</h4>
+ <ul>
+ {%for country in country_list %}
+ <li><a href="/writing/{{country.slug}}/1/" title="See all writing from {{country.name|title}}">{{country.name}}</a></li>
+ </li>
+ {% endfor %}
+ </ul>
+
+ </div>
+
+ <div class="blok">
+ <h4>About Luxagraf</h4>
+ {% chunk "about_sidebar" %}
+
+ </div>
+
+ <div class="blok">
+ <h4>Follow Along</h4>
+ {% chunk "follow_sidebar" %}
+ </div>
+</div><!-- sidebar -->
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/base.html b/templates/base.html
new file mode 100644
index 0000000..190175a
--- /dev/null
+++ b/templates/base.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+ <title>{% block pagetitle %}Luxagraf - Topografical Writings{% endblock %}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+
+ <link rel="alternate"
+ type="application/rss+xml"
+ title="RSS 2.0"
+ href="http://feeds.feedburner.com/luxagraf/everything">
+
+
+ <link rel="stylesheet"
+ href="{{media_url}}css/base.css"
+ type="text/css"
+ media="screen"
+ charset="utf-8">
+
+<!--[if IE 6]><link rel="stylesheet" href="http://media.luxagraf.net/new/css/ie6.css" type="text/css" media="screen, projection"><![endif]-->
+
+ <link rel="shortcut icon"
+ href="http://media.luxagraf.net/img/favicon.ico"
+ type="image/vnd.microsoft.icon">
+
+ <link rel="apple-touch-icon"
+ href="http://media.luxagraf.net/img/luxagrafiphoneicon.png">
+
+ <meta name="author" content="luxagraf">
+ <meta name="description"
+ content="{% block metadescription %}Luxagraf: a travelogue of sorts, Recording journeys around the world and just next door.{% endblock %}">
+ <meta name="keywords"
+ content="luxagraf writing travel authors philosophy ramblings">
+ <meta name="copyright"
+ content="Licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 License">
+
+
+ <link rel="openid.server"
+ href="http://www.myopenid.com/server" >
+
+ <link rel="openid.delegate"
+ href="http://luxagraf.myopenid.com/" >
+
+<meta name="verify-v1" content="ZCZSYGNdjeLCPx5trSQELyhY9kq9N7CznTcv5JFkpnM=">
+{%block extrahead%}{%endblock%}
+</head>
+
+<body {%block bodyid%}{%endblock%}{%block bodyevents%}{%endblock%}>
+
+<div id="header">
+ <h1><a href="/" title="home">Luxagraf, a travelgue</a></h1>
+ <ul id="menu">
+ <li id="stories"><a href="/writing/1/" title="An archive of previous writings from around the world">Stories</a></li>
+ <li id="photos" title="Photos from travels around the world"><a href="/photos/1/">Photos</a></li>
+ <li id="map" title="luxagraf stories plotted on a map"><a href="/map/">Map</a></li>
+ <!--<li id="books"><a href="/books/">Books</a></li>-->
+ </ul>
+</div>
+
+
+<div class="container">
+
+ <div id="primary">
+
+ {% block primaryoverride %}
+ <div class="content">
+ {% block titleoverride %}<h2>{% block title %}{% endblock %}</h2>{% endblock %}
+
+ {% block primary %}
+ {% endblock %}
+
+ </div>
+ {% endblock %}
+
+
+ <div class="meta">
+ <p class="date">{% block date %}{% endblock %}</p>
+
+ </div>
+
+ {% block extrabody %}
+
+ {% endblock %}
+
+
+
+
+
+ </div>
+{% block sidebar %}
+
+{% endblock %}
+<div class="push"></div>
+</div><!-- end of main top content -->
+
+<div id="foot">
+ <div id="footer">
+ <span id="foot-float">Other stuff:</span>
+ <ul>
+ <li><a href="/about/" title="About Luxagraf">About</a></li>
+ <li><a href="/contact/" title="Get in touch">Contact</a></li>
+ <li><a href="/colophon/" title="How Luxagraf is made">Colophon</a></li>
+ </ul>
+ <p>All content licensed under the Creative Commons (<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en" title="read the Attribution-Noncommercial-Share Alike 3.0 deed">details</a>). <span>Built with <a href="http://geodjango.org/" title="a GeoDjango joint">GeoDjango</a> and hosted on <a href="http://www.webfaction.com/" title="webfaction">Webfaction</a>.</span></p>
+ </div>
+</div>
+{% block js %}{% endblock%}
+</body>
+</html> \ No newline at end of file
diff --git a/templates/contact_form/contact_form.html b/templates/contact_form/contact_form.html
new file mode 100644
index 0000000..4864085
--- /dev/null
+++ b/templates/contact_form/contact_form.html
@@ -0,0 +1,73 @@
+{% extends 'base.html' %}
+
+{#==============================================
+Load up the various metadata add-ins
+================================================#}
+
+{% block meta_description %} Contact, Get in touch with corriegreathouse.com.{%endblock%}
+{% block metatitle %} - Get in Touch{% endblock %}
+{% block metakeywords %}contact, get in touch, drop a line{%endblock%}
+
+{#==============================================
+Fill in the Title And Dateline Blocks
+================================================#}
+
+{%block title %}
+Contact Me
+{%endblock%}
+
+
+{% block dateline %}
+Share your thoughts, ask a question, etc
+{% endblock%}
+
+
+{#==============================================
+ Primary Content
+================================================#}
+
+
+{%block primary%}
+<div class="form-holder">
+<form method="post" action="" class="contact-form">
+<dl>
+{% for field in form %}
+ <dt>{{ field.label_tag }}</dt>
+ <dd>{{ field }}</dd>
+ {% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
+ {% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
+{% endfor %}
+</dl>
+<input type="submit" class="button" value="Contact" />
+</form>
+</div>
+{%endblock%}
+
+
+{#==============================================
+ Secondary Content
+================================================#}
+
+{% block right %}
+<h4>Thanks for visting luxagraf</h4>
+ <p class="graf">
+ If you've got a question, comment, or thought you'd like to share, I'd love to hear it. But keep in mind that I'm not the best correspondent, however, rest assured that I do read every email I get even if I don't always respond in a timely fashion.
+ </p>
+{%endblock%}
+
+
+{#==============================================
+This page shows Photos in the bottom left column
+so we need to override the books block
+==============================================#}
+
+{% block books %}
+{% endblock %}
+
+
+
+
+{% block photos %}
+
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/contact_form/contact_form.txt b/templates/contact_form/contact_form.txt
new file mode 100644
index 0000000..701b8bb
--- /dev/null
+++ b/templates/contact_form/contact_form.txt
@@ -0,0 +1,5 @@
+Message from luxagraf:
+
+Name: {{name}}
+
+Wrote: {{body}} \ No newline at end of file
diff --git a/templates/contact_form/contact_form_sent.html b/templates/contact_form/contact_form_sent.html
new file mode 100644
index 0000000..adeabb6
--- /dev/null
+++ b/templates/contact_form/contact_form_sent.html
@@ -0,0 +1,25 @@
+{% extends 'contact_form/contact_form.html' %}
+
+{#==============================================
+Fill in the Title And Dateline Blocks
+================================================#}
+
+{%block title %}
+Thank You
+{%endblock%}
+
+
+{% block dateline %}
+Thanks for sharing your thoughts
+{% endblock%}
+
+
+{#==============================================
+ Primary Content
+================================================#}
+
+{%block primary%}
+
+<p>Thanks for sharing your thoughts, I will make an effort to respond promptly</p>
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/contact_form/contact_form_subject.txt b/templates/contact_form/contact_form_subject.txt
new file mode 100644
index 0000000..9719f2c
--- /dev/null
+++ b/templates/contact_form/contact_form_subject.txt
@@ -0,0 +1 @@
+[luxagraf] {{subject_line}} \ No newline at end of file
diff --git a/templates/details/about.html b/templates/details/about.html
new file mode 100644
index 0000000..66ea623
--- /dev/null
+++ b/templates/details/about.html
@@ -0,0 +1,42 @@
+{% extends 'base.html' %}
+{% load chunks %}
+{% load typogrify %}
+{% block pagetitle %}Luxagraf | {{flatpage.title|title|smartypants|safe}}{% endblock %}
+{% block metadescription %}About the site, luxagraf.net {% endblock %}
+
+
+
+ {% block title %}{{flatpage.title|smartypants|safe}}{% endblock %}
+
+
+ {% block primary %}
+
+ {{flatpage.content|smartypants|widont|safe}}
+
+
+ {% endblock %}
+
+
+
+{% block sidebar %}
+ <div id="sidebar">
+
+ <h4 class="first">Topography</h4>
+ <div class="blok">
+ {% chunk "regions_sidebar" %}
+ </div>
+
+ <div class="blok">
+ <h4>Follow Along</h4>
+ {% chunk "follow_sidebar" %}
+ </div>
+ {% ifequal flatpage.title 'Some Background on Luxagraf'%}
+ <div class="blok">
+ <h4>Travel Sites that Don't Suck</h4>
+ {% chunk "other_sites_sidebar" %}
+ </div>
+ {% endifequal %}
+</div><!-- sidebar -->
+
+
+{% endblock %} \ No newline at end of file
diff --git a/templates/details/entry.html b/templates/details/entry.html
new file mode 100644
index 0000000..d9f7cb7
--- /dev/null
+++ b/templates/details/entry.html
@@ -0,0 +1,66 @@
+{% extends 'base.html' %}
+{% load typogrify %}
+{% block pagetitle %}Luxagraf | {{object.title|title|smartypants|safe}}{% endblock %}
+{% block metadescription %}Luxagraf: {{object.dek|striptags|safe}}{% endblock %}
+{% block date %}{{object.pub_date|date:"F j, Y"}}<span class="small byline">{% ifequal object.location.state.country.name "United States" %}{{object.location.name|smartypants|safe}}, {{object.location.state.name}}{%else%}{{object.location.name|smartypants|safe}}, {{object.location.state.country.name}}{%endifequal%}</span>{% endblock %}
+
+
+
+ {% block title %}{{object.title|smartypants|safe}}{% endblock %}
+
+
+ {% block primary %}
+
+ {{object.body_html|smartypants|widont|safe}}
+
+
+
+ <div id="extra">
+ <p><span>{{object.title|title|smartypants|safe}}</span> was posted {{ object.pub_date|timesince }} ago from <!--<a href="{{object.location.get_absolute_url}}" title="see other entries from {{object.location.name}}">-->{{object.location.name|smartypants|safe}}<!--</a>-->, which is in {%ifequal object.location.state.country.name 'United States'%}<a href="/maps/#{{object.location.state.slug}}" title="see other entries from {{object.location.state.name}}">{{object.location.state.name|smartypants|safe}}</a>,{%endifequal%} <a href="/writing/{{object.location.state.country.slug}}/1/" title="see other entries from {{object.location.state.country.name}}">{{object.location.state.country.name|smartypants|safe}}</a>. You can find nearby entries by browsing the <a href="/map/">Map</a>.
+
+
+ <p>If you enjoyed reading this, you can follow along on <a href="http://www.facebook.com/profile.php?id=730956404" title="Facebook" rel="me">Facebook</a>, <a href="http://friendfeed.com/luxagraf" title="friendfeed" rel="me">FriendFeed</a> or by subscribing to the <a href="http://feeds.feedburner.com/luxagraf/blog" title="writing RSS 2.0 feed">RSS Feed</a>. For more about luxagraf, see the <a href="/about/" title="about luxagraf">about page</a>. To get in touch please use the <a href="/contact/" title="contact me">contact form</a> or leave a comment below.</p>
+ </div>
+
+ <div id="nav">
+ <ul>
+ {% if object.get_previous_published%}
+ <li>
+ <a href="{{ object.get_previous_published.get_absolute_url }}" title=" {{object.get_previous_published.title}}">&laquo;previous</a>
+ </li>
+ {%endif%}
+ {% if object.get_next_published%}
+ <li class="next">
+ <a href="{{ object.get_next_published.get_absolute_url }}" title=" {{object.get_next_published.title}}">next&raquo;</a>
+
+ </li>
+ {%endif%}
+ </ul>
+ </div>
+ <h4 id="comment-header">comments</h4>
+ {# Load and display comments #}
+ <div id="disqus_thread"></div><script type="text/javascript" src="http://disqus.com/forums/luxagraf/embed.js"></script><noscript><a href="http://luxagraf.disqus.com/?url=ref">View the discussion thread.</a></noscript><a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>
+
+ {% endblock %}
+
+
+
+{% block sidebar %}
+ <div id="sidebar">
+ <div id="nav">
+ <ul>
+ {% if object.get_previous_published%}
+ <li>
+ <a href="{{ object.get_previous_published.get_absolute_url }}" title=" {{object.get_previous_published.title}}">&laquo; previous</a>
+ </li>
+ {%endif%}
+ {% if object.get_next_published%}
+ <li class="next">
+ <a href="{{ object.get_next_published.get_absolute_url }}" title=" {{object.get_next_published.title}}">next &raquo;</a>
+
+ </li>
+ {%endif%}
+ </ul>
+ </div>
+ </div>
+{% endblock %} \ No newline at end of file
diff --git a/templates/details/photo.html b/templates/details/photo.html
new file mode 100644
index 0000000..22adeb9
--- /dev/null
+++ b/templates/details/photo.html
@@ -0,0 +1,85 @@
+{% extends 'base.html' %}
+{% load typogrify %}
+{% block pagetitle %}Luxagraf | {{object.title|title|smartypants|safe}}{% endblock %}
+{% block metadescription %}Luxagraf: Photo, {{object.title}}, Photographer: Scott Gilbertson, Published: {{ object.pub_date|date:"N j, Y" }} {{ object.pub_date|date:"h:i a" }}Camera:{%if object.exif_make%}{%ifnotequal object.exif_make 'Canon'%}{{ object.exif_make }}{%endifnotequal%} {{ object.exif_model }}{% else %}Canon Powershot S45{%endif%}, Aperture: {%if object.exif_aperture%}{{ object.exif_aperture }}{%else%}Not Recorded{%endif%}, Shutter Speed: {%if object.exif_shutter%}{{ object.exif_shutter }} sec{%else%}Not Recorded{%endif%}, Film Speed: {%if object.exif_iso%}{{ object.exif_iso }} ISO{%else%}Not Recorded{%endif%}.{% endblock %}
+{% block date %}{{object.pub_date|date:"F j, Y"}}<span class="small byline">{% ifequal object.location.state.country.name "United States" %}{{object.location.name|smartypants|safe}}, {{object.location.state.name}}{%else%}{{object.location.name|smartypants|safe}}, {{object.location.state.country.name}}{%endifequal%}</span>{% endblock %}
+
+
+
+ {% block title %}{{object.title|smartypants|safe}}{% endblock %}
+
+
+ {% block primary %}
+
+ <a href="http://flickr.com/photos/luxagraf/{{object.flickr_id}}/" title="View {{object.flickr_title}} on Flickr.com"><img class="flickr-image" src="{{ object.get_medium_url }}" alt="{{object.title}}" title="{{object.title}}" /></a>
+ {% ifnotequal object.description 'None' %}
+ <p>{{ object.description|smartypants|widont|safe }}</p>
+ {%endifnotequal %}
+ <p>Other Sizes: <a href="{{object.get_large_url}}" title="see large image">Large</a> and
+ <a href="http://flickr.com/photo_zoom.gne?id={{object.flickr_id}}&size=o" title="see original image">Original</a></p>
+
+
+
+ <div id="extra">
+
+
+
+ <p>If you enjoy this photo, you can follow along on <a href="http://flickr.com/photos/luxagraf/" title="Flickr" rel="me">Flickr</a>, <a href="http://www.facebook.com/profile.php?id=730956404" title="Facebook" rel="me">Facebook</a>, <a href="http://friendfeed.com/luxagraf" title="friendfeed" rel="me">FriendFeed</a> or by subscribing to the <a href="http://feeds.feedburner.com/luxagraf/blog" title="writing RSS 2.0 feed">RSS Feed</a>. For more about luxagraf, see the <a href="/about/" title="about luxagraf">about page</a>. To get in touch please use the <a href="/contact/" title="contact me">contact form</a> or leave a comment below.</p>
+ </div>
+
+ <div id="nav">
+ <ul>
+ {% if object.get_previous_published%}
+ <li>
+ <a href="{{ object.get_previous_published.get_absolute_url }}" title=" {{object.get_previous_published.title}}">&laquo;previous</a>
+ </li>
+ {%endif%}
+ {% if object.get_next_published%}
+ <li class="next">
+ <a href="{{ object.get_next_published.get_absolute_url }}" title=" {{object.get_next_published.title}}">next&raquo;</a>
+
+ </li>
+ {%endif%}
+ </ul>
+ </div>
+ <h4 id="comment-header">comments</h4>
+ <p>If you'd like to leave a comment, you may do so on <a href="http://flickr.com/photos/luxagraf/{{object.flickr_id}}/" title="leave a comment on Flickr">Flickr</a>.</p>
+
+ {% endblock %}
+
+
+
+{% block sidebar %}
+ <div id="sidebar">
+ <div id="nav">
+ <ul>
+ {% if object.get_previous_published%}
+ <li>
+ <a href="{{ object.get_previous_published.get_absolute_url }}" title=" {{object.get_previous_published.title}}">&laquo; previous</a>
+ </li>
+ {%endif%}
+ {% if object.get_next_published%}
+ <li class="next">
+ <a href="{{ object.get_next_published.get_absolute_url }}" title=" {{object.get_next_published.title}}">next &raquo;</a>
+
+ </li>
+ {%endif%}
+ </ul>
+ </div>
+
+ <div class="blok">
+ <h4>Image Data</h4>
+
+ <dl class="sidebar meta">
+ <dt>Camera:</dt>
+ <dd>{%if object.exif_make%}{%ifnotequal object.exif_make 'Canon'%}{{ object.exif_make }}{%endifnotequal%} {{ object.exif_model }}{% else %}Canon Powershot S45{%endif%}</dd>
+ <dt>Aperture:</dt>
+ <dd>{%if object.exif_aperture%}{{ object.exif_aperture }}{%else%}Not Recorded{%endif%}</dd>
+ <dt>Shutter Speed:</dt>
+ <dd>{%if object.exif_shutter%}{{ object.exif_shutter }} sec{%else%}Not Recorded{%endif%}</dd>
+ <dt>Film Speed:</dt>
+ <dd>{%if object.exif_iso%}{{ object.exif_iso }} ISO{%else%}Not Recorded{%endif%}</dd>
+ </dl>
+ </div>
+ </div>
+{% endblock %} \ No newline at end of file
diff --git a/templates/gis/admin/google.html b/templates/gis/admin/google.html
new file mode 100644
index 0000000..460d28d
--- /dev/null
+++ b/templates/gis/admin/google.html
@@ -0,0 +1,5 @@
+{% extends "gis/admin/openlayers.html" %}
+{% block extrastyle %}{{ block.super }}
+<style type="text/css">v\:* {behavior:url(#default#VML);}</style>
+{% endblock %}
+{% block openlayers %}{% include "gis/admin/google.js" %}{% endblock %} \ No newline at end of file
diff --git a/templates/gis/admin/google.js b/templates/gis/admin/google.js
new file mode 100644
index 0000000..a7d1467
--- /dev/null
+++ b/templates/gis/admin/google.js
@@ -0,0 +1,2 @@
+{% extends "gis/admin/openlayers.js" %}
+{% block base_layer %}new OpenLayers.Layer.Google("Google Base Layer", {'type': G_NORMAL_MAP, 'sphericalMercator' : true});{% endblock %} \ No newline at end of file