2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2024-11-25 08:41:51 +00:00

[svn] Remove old subcave model, along with mptt and feincms. Also move OtherCaveNames admin representation to an inline in Cave.

This commit is contained in:
substantialnoninfringinguser 2009-07-04 19:26:51 +01:00
parent 4f0271ad49
commit 38a545e174
45 changed files with 9 additions and 1930 deletions

View File

@ -1,6 +1,5 @@
from troggle.core.models import *
from django.contrib import admin
from feincms.admin import editor
from django.forms import ModelForm
import django.forms as forms
from core.forms import LogbookEntryForm
@ -31,6 +30,10 @@ class ScannedImageInline(admin.TabularInline):
model = ScannedImage
extra = 4
class OtherCaveInline(admin.TabularInline):
model = OtherCaveName
extra = 1
class SurveyAdmin(TroggleModelAdmin):
inlines = (ScannedImageInline,)
search_fields = ('expedition__year','wallet_number')
@ -90,17 +93,13 @@ class PersonExpeditionAdmin(TroggleModelAdmin):
class CaveAdmin(TroggleModelAdmin):
search_fields = ('official_name','kataster_number','unofficial_number')
#inlines = (QMInline,)
inlines = (OtherCaveInline,)
extra = 4
class SubcaveAdmin(editor.TreeEditorMixin,TroggleModelAdmin):
pass
admin.site.register(Photo)
admin.site.register(Subcave, SubcaveAdmin)
admin.site.register(Cave, CaveAdmin)
admin.site.register(Area)
admin.site.register(OtherCaveName)
#admin.site.register(OtherCaveName)
admin.site.register(CaveAndEntrance)
admin.site.register(SurveyStation)
admin.site.register(NewSubCave)
@ -131,9 +130,4 @@ def export_as_xml(modeladmin, request, queryset):
return response
admin.site.add_action(export_as_xml)
admin.site.add_action(export_as_json)
try:
mptt.register(Subcave, order_insertion_by=['name'])
except mptt.AlreadyRegistered:
print "mptt already registered"
admin.site.add_action(export_as_json)

View File

@ -1,10 +1,4 @@
import urllib, urlparse, string, os, datetime, logging
try:
import mptt
except ImportError:
#I think we should be having troggle directory as the base import place
#but I am leaving the following line in to make sure I do not break anything
import troggle.mptt as mptt
from django.forms import ModelForm
from django.db import models
from django.contrib import admin
@ -502,15 +496,6 @@ class Entrance(TroggleModel):
if f[0] == self.findability:
return f[1]
class Subcave(TroggleModel):
description = models.TextField(blank=True, null=True)
title = models.CharField(max_length=200, )
cave = models.ForeignKey('Cave', blank=True, null=True, help_text="Only the top-level subcave should be linked to a cave!")
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
#adjoining = models.ManyToManyField('Subcave',blank=True, null=True,)
legacy_description_path = models.CharField(max_length=600, blank=True, null=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
@ -522,28 +507,6 @@ class Subcave(TroggleModel):
res = '/'.join((self.get_root().cave.get_absolute_url(), self.title))
return res
# This was the old way, before we were using django-mptt
# def get_absolute_url(self):
# urlString=self.name
# if self.parent:
# parent=self.parent
# while parent: #recursively walk up the tree, adding parents to the left of the URL
# urlString=parent.name+'/'+urlString
# if parent.cave:
# cave=parent.cave
# parent=parent.parent
# urlString='cave/'+unicode(cave.kataster_number)+'/'+urlString
# else:
# urlString='cave/'+unicode(self.cave.kataster_number)+'/'+urlString
# return urlparse.urljoin(settings.URL_ROOT, urlString)
try:
mptt.register(Subcave, order_insertion_by=['title'])
except mptt.AlreadyRegistered:
print "mptt already registered"
class CaveDescription(TroggleModel):
short_name = models.CharField(max_length=50, unique = True)
@ -666,7 +629,7 @@ class Survey(TroggleModel):
wallet_letter = models.CharField(max_length=1,blank=True,null=True)
comments = models.TextField(blank=True,null=True)
location = models.CharField(max_length=400,blank=True,null=True) #REDUNDANT
subcave = models.ForeignKey('Subcave', blank=True, null=True)
subcave = models.ForeignKey('NewSubCave', blank=True, null=True)
#notes_scan = models.ForeignKey('ScannedImage',related_name='notes_scan',blank=True, null=True) #Replaced by contents field of ScannedImage model
survex_block = models.OneToOneField('SurvexBlock',blank=True, null=True)
logbook_entry = models.ForeignKey('LogbookEntry')

View File

@ -56,19 +56,6 @@ def survexblock(request, survexpath):
ftext = survexblock.text
return render_with_context(request,'survexblock.html', {'survexblock':survexblock, 'ftext':ftext, })
def subcave(request, cave_id, subcave):
print subcave
subcaveSeq=re.findall('(?:/)([^/]*)',subcave)
print subcaveSeq
cave=models.Cave.objects.get(kataster_number = cave_id)
subcave=models.Subcave.objects.get(title=subcaveSeq[0], cave=cave)
if len(subcaveSeq)>1:
for subcaveUrlSegment in subcaveSeq[1:]:
if subcaveUrlSegment:
subcave=subcave.children.get(title=subcaveUrlSegment)
print subcave
return render_with_context(request,'subcave.html', {'subcave': subcave,'cave':cave})
def surveyindex(request):
surveys=Survey.objects.all()
expeditions=Expedition.objects.order_by("-year")

View File

View File

@ -1,12 +0,0 @@
from django.contrib import admin
from feincms.models import Region, Template
admin.site.register(Region,
list_display=('title', 'key', 'inherited'),
)
admin.site.register(Template,
list_display=('title', 'path'),
)

View File

@ -1,183 +0,0 @@
import re
from django import forms, template
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.util import unquote
from django.core import serializers
from django.core.exceptions import ImproperlyConfigured
from django.db import connection, transaction
from django.forms.formsets import all_valid
from django.forms.models import inlineformset_factory
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render_to_response
from django.utils import simplejson
from django.utils.encoding import force_unicode
from django.utils.functional import update_wrapper
from django.utils.translation import ugettext_lazy as _
FEINCMS_ADMIN_MEDIA = getattr(settings, 'FEINCMS_ADMIN_MEDIA', '/media/sys/feincms/')
class ItemEditorMixin(object):
"""
This mixin needs an attribute on the ModelAdmin class:
show_on_top::
A list of fields which should be displayed at the top of the form.
This does not need to (and should not) include ``template''
"""
def change_view(self, request, object_id, extra_context=None):
if not hasattr(self.model, '_feincms_content_types'):
raise ImproperlyConfigured, 'You need to create at least one content type for the %s model.' % (self.model.__name__)
class ModelForm(forms.ModelForm):
class Meta:
model = self.model
class SettingsFieldset(forms.ModelForm):
# This form class is used solely for presentation, the data will be saved
# by the ModelForm above
class Meta:
model = self.model
exclude = self.show_on_top+('template',)
inline_formset_types = [(
content_type,
inlineformset_factory(self.model, content_type, extra=1)
) for content_type in self.model._feincms_content_types]
opts = self.model._meta
app_label = opts.app_label
obj = self.model._default_manager.get(pk=unquote(object_id))
if not self.has_change_permission(request, obj):
raise PermissionDenied
if request.method == 'POST':
model_form = ModelForm(request.POST, request.FILES, instance=obj)
inline_formsets = [
formset_class(request.POST, request.FILES, instance=obj,
prefix=content_type.__name__.lower())
for content_type, formset_class in inline_formset_types]
if model_form.is_valid() and all_valid(inline_formsets):
model_form.save()
for formset in inline_formsets:
formset.save()
return HttpResponseRedirect(".")
settings_fieldset = SettingsFieldset(request.POST, instance=obj)
settings_fieldset.is_valid()
else:
model_form = ModelForm(instance=obj)
inline_formsets = [
formset_class(instance=obj, prefix=content_type.__name__.lower())
for content_type, formset_class in inline_formset_types]
settings_fieldset = SettingsFieldset(instance=obj)
content_types = []
for content_type in self.model._feincms_content_types:
content_name = content_type._meta.verbose_name
content_types.append((content_name, content_type.__name__.lower()))
context = {
'title': _('Change %s') % force_unicode(opts.verbose_name),
'opts': opts,
'page': obj,
'page_form': model_form,
'inline_formsets': inline_formsets,
'content_types': content_types,
'settings_fieldset': settings_fieldset,
'top_fieldset': [model_form[field] for field in self.show_on_top],
'FEINCMS_ADMIN_MEDIA': FEINCMS_ADMIN_MEDIA,
}
return render_to_response([
'admin/feincms/%s/%s/item_editor.html' % (app_label, opts.object_name.lower()),
'admin/feincms/%s/item_editor.html' % app_label,
'admin/feincms/item_editor.html',
], context, context_instance=template.RequestContext(request))
class TreeEditorMixin(object):
def changelist_view(self, request, extra_context=None):
# handle AJAX requests
if request.is_ajax():
cmd = request.POST.get('__cmd')
if cmd=='save_tree':
return self._save_tree(request)
elif cmd=='delete_item':
return self._delete_item(request)
return HttpResponse('Oops. AJAX request not understood.')
from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
opts = self.model._meta
app_label = opts.app_label
if not self.has_change_permission(request, None):
raise PermissionDenied
try:
cl = ChangeList(request, self.model, self.list_display,
self.list_display_links, self.list_filter, self.date_hierarchy,
self.search_fields, self.list_select_related, self.list_per_page,
self.list_editable, self)
except IncorrectLookupParameters:
# Wacky lookup parameters were given, so redirect to the main
# changelist page, without parameters, and pass an 'invalid=1'
# parameter via the query string. If wacky parameters were given and
# the 'invalid=1' parameter was already in the query string, something
# is screwed up with the database, so display an error page.
if ERROR_FLAG in request.GET.keys():
return render_to_response('admin/invalid_setup.html', {'title': _('Database error')})
return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
context = {
'FEINCMS_ADMIN_MEDIA': FEINCMS_ADMIN_MEDIA,
'title': cl.title,
'is_popup': cl.is_popup,
'cl': cl,
'has_add_permission': self.has_add_permission(request),
'root_path': self.admin_site.root_path,
'app_label': app_label,
'object_list': self.model._tree_manager.all(),
}
context.update(extra_context or {})
return render_to_response([
'admin/feincms/%s/%s/tree_editor.html' % (app_label, opts.object_name.lower()),
'admin/feincms/%s/tree_editor.html' % app_label,
'admin/feincms/tree_editor.html',
], context, context_instance=template.RequestContext(request))
def _save_tree(self, request):
pagetree = simplejson.loads(request.POST['tree'])
# 0 = tree_id, 1 = parent_id, 2 = left, 3 = right, 4 = level, 5 = item_id
sql = "UPDATE %s SET %s=%%s, %s_id=%%s, %s=%%s, %s=%%s, %s=%%s WHERE %s=%%s" % (
self.model._meta.db_table,
self.model._meta.tree_id_attr,
self.model._meta.parent_attr,
self.model._meta.left_attr,
self.model._meta.right_attr,
self.model._meta.level_attr,
self.model._meta.pk.column)
connection.cursor().executemany(sql, pagetree)
transaction.commit_unless_managed()
return HttpResponse("OK", mimetype="text/plain")
def _delete_item(self, request):
page_id = request.POST['item_id']
obj = self.model._default_manager.get(pk=unquote(page_id))
obj.delete()
return HttpResponse("OK", mimetype="text/plain")

View File

@ -1,20 +0,0 @@
from django.db import models
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
class FileContent(models.Model):
title = models.CharField(max_length=200)
file = models.FileField(_('file'), upload_to='filecontent')
class Meta:
abstract = True
verbose_name = _('file')
verbose_name_plural = _('files')
def render(self, **kwargs):
return render_to_string([
'content/file/%s.html' % self.region.key,
'content/file/default.html',
], {'content': self})

View File

@ -1,32 +0,0 @@
from django.db import models
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
class ImageContent(models.Model):
"""
Create an ImageContent like this:
Cls.create_content_type(ImageContent, POSITION_CHOICES=(
('left', 'Left'),
('right', Right'),
))
"""
image = models.ImageField(_('image'), upload_to='imagecontent')
class Meta:
abstract = True
verbose_name = _('image')
verbose_name_plural = _('images')
def render(self, **kwargs):
return render_to_string([
'content/image/%s.html' % self.position,
'content/image/default.html',
], {'content': self})
@classmethod
def handle_kwargs(cls, POSITION_CHOICES=()):
models.CharField(_('position'), max_length=10, choices=POSITION_CHOICES
).contribute_to_class(cls, 'position')

View File

@ -1,16 +0,0 @@
from django.db import models
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
class RichTextContent(models.Model):
text = models.TextField(_('text'), blank=True)
class Meta:
abstract = True
verbose_name = _('rich text')
verbose_name_plural = _('rich texts')
def render(self, **kwargs):
return mark_safe(self.text)

View File

@ -1,39 +0,0 @@
from datetime import datetime
from django.db import models
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
import feedparser
class RSSContent(models.Model):
title = models.CharField(help_text=_('The rss field is updated several times a day. A change in the title will only be visible on the home page after the next feed update.'), max_length=50)
link = models.URLField(_('link'))
rendered_content = models.TextField(_('Pre-rendered content'), blank=True, editable=False)
last_updated = models.DateTimeField(_('Last updated'), blank=True, null=True)
max_items = models.IntegerField(_('Max. items'), default=5)
class Meta:
abstract = True
verbose_name = _('RSS feed')
verbose_name_plural = _('RSS feeds')
def render(self, **kwargs):
return mark_safe(self.rendered_content)
def cache_content(self):
print u"Getting RSS feed at %s" % (self.link,)
feed = feedparser.parse(self.link)
print u"Pre-rendering content"
self.rendered_content = render_to_string('content/rss/content.html', {
'feed_title': self.title,
'feed_link': feed['feed']['link'],
'entries': feed['entries'][:self.max_items],
})
self.last_updated = datetime.now()
self.save()

View File

@ -1,26 +0,0 @@
from django.db import models
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
import re
class VideoContent(models.Model):
video = models.URLField(_('video link'),help_text=_('This should be a link to a youtube video, i.e.: http://www.youtube.com/watch?v=zmj1rpzDRZ0'))
class Meta:
abstract = True
verbose_name = _('video')
verbose_name_plural = _('videos')
def render(self, **kwargs):
vid = re.search('(?<==)\w+',self.video)
ret = """
<div class="videocontent">
<object width="400" height="330">
<param name="movie" value="http://www.youtube.com/v/%s&hl=de&fs=1"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/%s&hl=de&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="400" height="330"></embed>
</object>
</div>
""" % (vid.group(0), vid.group(0))
return ret

View File

@ -1,281 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-04-23 11:12+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: models.py:33 module/page/models.py:131
msgid "title"
msgstr "Titel"
#: models.py:34
msgid "key"
msgstr "Schlüssel"
#: models.py:35
msgid "inherited"
msgstr "Vererbt"
#: models.py:36
msgid ""
"Should the content be inherited by subpages if they do not define any "
"content for this region?"
msgstr ""
"Soll der Inhalt dieser Region durch Unterseiten geerbt werden, sofern diese "
"keinen eigenen Inhalt definieren?"
#: models.py:39
msgid "region"
msgstr "Region"
#: models.py:40
msgid "regions"
msgstr "Regionen"
#: models.py:57
msgid "template"
msgstr "Template"
#: models.py:58
msgid "templates"
msgstr "Templates"
#: models.py:135
msgid "ordering"
msgstr "Sortierung"
#: admin/editor.py:139
msgid "Database error"
msgstr "Datenbankfehler"
#: content/file/models.py:8 content/file/models.py:12
msgid "file"
msgstr "Datei"
#: content/file/models.py:13
msgid "files"
msgstr "Dateien"
#: content/image/models.py:15 content/image/models.py:19
msgid "image"
msgstr "Bild"
#: content/image/models.py:20
msgid "images"
msgstr "Bilder"
#: content/image/models.py:30
msgid "position"
msgstr "Position"
#: content/richtext/models.py:7
msgid "text"
msgstr "Text"
#: content/richtext/models.py:11
msgid "rich text"
msgstr "Text"
#: content/richtext/models.py:12
msgid "rich texts"
msgstr "Texte"
#: content/rss/models.py:12
msgid ""
"The rss field is updated several times a day. A change in the title will "
"only be visible on the home page after the next feed update."
msgstr ""
"Der RSS Feed wird mehrmals täglich aktualisiert. Eine Änderung des Titels "
"erscheint erst nach der nächsten Feed-Aktualisierung auf der Webseite."
#: content/rss/models.py:13
msgid "link"
msgstr "Link"
#: content/rss/models.py:14
msgid "Pre-rendered content"
msgstr "Vor-gerenderter Inhalt"
#: content/rss/models.py:15
msgid "Last updated"
msgstr "Letzte Aktualisierung"
#: content/rss/models.py:16
msgid "Max. items"
msgstr "Maximale Anzahl"
#: content/rss/models.py:20
msgid "RSS feed"
msgstr "RSS Feed"
#: content/rss/models.py:21
msgid "RSS feeds"
msgstr "RSS Feeds"
#: content/video/models.py:7
msgid "video link"
msgstr "Video-Link"
#: content/video/models.py:7
msgid ""
"This should be a link to a youtube video, i.e.: http://www.youtube.com/watch?"
"v=zmj1rpzDRZ0"
msgstr ""
"Dies sollte ein Link zu einem Youtube-Video sein, z.B.: http://www.youtube."
"com/watch?v=zmj1rpzDRZ0"
#: content/video/models.py:11
msgid "video"
msgstr "Video"
#: content/video/models.py:12
msgid "videos"
msgstr "Videos"
#: module/page/admin.py:17
msgid "Other options"
msgstr "Weitere Optionen"
#: module/page/models.py:36 module/page/models.py:146
msgid "navigation extension"
msgstr "Navigations-Erweiterung"
#: module/page/models.py:128 templates/admin/feincms/tree_editor.html:133
msgid "active"
msgstr "Aktiv"
#: module/page/models.py:132
msgid "This is used for the generated navigation too."
msgstr "Dies wird auch für die generierte Navigation verwendet."
#: module/page/models.py:135
msgid "in navigation"
msgstr "In der Navigation"
#: module/page/models.py:136
msgid "override URL"
msgstr "Überschriebene URL"
#: module/page/models.py:137
msgid "Override the target URL for the navigation."
msgstr "Überschreibe die Ziel-URL für die Navigation."
#: module/page/models.py:138
msgid "redirect to"
msgstr "Weiterleiten zu"
#: module/page/models.py:139
msgid "Target URL for automatic redirects."
msgstr "Ziel-URL für automatische Weiterleitungen."
#: module/page/models.py:140
msgid "Cached URL"
msgstr "Zwischengespeicherte URL"
#: module/page/models.py:148
msgid ""
"Select the module providing subpages for this page if you need to customize "
"the navigation."
msgstr "Wähle das Modul aus, welches weitere Navigationspunkte erstellt."
#: module/page/models.py:151
msgid "content title"
msgstr "Inhaltstitel"
#: module/page/models.py:152
msgid "The first line is the main title, the following lines are subtitles."
msgstr "Die erste Zeile ist der Haupttitel, die weiteren Zeilen Untertitel"
#: module/page/models.py:155
msgid "page title"
msgstr "Seitentitel"
#: module/page/models.py:156
msgid "Page title for browser window. Same as title by default."
msgstr ""
"Seitentitel für das Browser-Fenster. Standardmässig gleich wie der Titel."
#: module/page/models.py:157
msgid "meta keywords"
msgstr "Meta Begriffe"
#: module/page/models.py:158
msgid "This will be prepended to the default keyword list."
msgstr "Diese Begriffe werden vor die Standard-Begriffsliste eingefügt."
#: module/page/models.py:159
msgid "meta description"
msgstr "Meta Beschreibung"
#: module/page/models.py:160
msgid "This will be prepended to the default description."
msgstr "Diese Beschreibung wird vor der Standard-Beschreibung eingefügt."
#: module/page/models.py:163
msgid "language"
msgstr "Sprache"
#: module/page/models.py:169
msgid "page"
msgstr "Seite"
#: module/page/models.py:170
msgid "pages"
msgstr "Seiten"
#: templates/admin/feincms/item_editor.html:122
msgid "Home"
msgstr "Startseite"
#: templates/admin/feincms/item_editor.html:134
msgid "Delete"
msgstr "Löschen"
#: templates/admin/feincms/item_editor.html:139
msgid "Save"
msgstr "Speichern"
#: templates/admin/feincms/item_editor.html:143
msgid "Change Template"
msgstr "Template ändern"
#: templates/admin/feincms/item_editor.html:158
msgid "Region empty"
msgstr "Region leer"
#: templates/admin/feincms/item_editor.html:162
msgid ""
"Content from the parent site is automatically inherited. To override this "
"behaviour, add some content."
msgstr ""
"Inhalt wird von der übergeordneten Seite geerbt. Füge Inhalt hinzu, um "
"dieses Verhalten zu ändern"
#: templates/admin/feincms/tree_editor.html:121
#, python-format
msgid "Add %(name)s"
msgstr "%(name)s hinzufügen"
#: templates/admin/feincms/tree_editor.html:132
msgid "Page"
msgstr "Seite"
#: templates/admin/feincms/tree_editor.html:134
msgid "in navi"
msgstr "Im Menü"
#: templates/admin/feincms/tree_editor.html:135
msgid "delete"
msgstr "Löschen"

View File

@ -1,12 +0,0 @@
from django.core.management.base import NoArgsCommand
from feincms.content.rss.models import RSSContent
class Command(NoArgsCommand):
help = "Run this as a cronjob."
def handle_noargs(self, **options):
for cls in RSSContent._feincms_content_models:
for content in cls.objects.all():
content.cache_content()

View File

@ -1,224 +0,0 @@
import copy
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.db.models import Q
from django.http import Http404
from django.utils import translation
from django.utils.translation import ugettext_lazy as _
import mptt
class TypeRegistryMetaClass(type):
"""
You can access the list of subclasses as <BaseClass>.types
"""
def __init__(cls, name, bases, attrs):
if not hasattr(cls, 'types'):
cls.types = []
else:
cls.types.append(cls)
class Region(models.Model):
"""
A template region which will be a container for several page contents.
Often used regions might be "main" and "sidebar"
"""
title = models.CharField(_('title'), max_length=50, unique=True)
key = models.CharField(_('key'), max_length=20, unique=True)
inherited = models.BooleanField(_('inherited'), default=False,
help_text=_('Should the content be inherited by subpages if they do not define any content for this region?'))
class Meta:
verbose_name = _('region')
verbose_name_plural = _('regions')
def __unicode__(self):
return self.title
class Template(models.Model):
"""
A template file on the disk which can be used by pages to render themselves.
"""
title = models.CharField(max_length=200)
path = models.CharField(max_length=200)
regions = models.ManyToManyField(Region, related_name='templates')
class Meta:
ordering = ['title']
verbose_name = _('template')
verbose_name_plural = _('templates')
def __unicode__(self):
return self.title
def first_template():
return Template.objects.all()[0]
class Base(models.Model):
template = models.ForeignKey(Template, default=first_template)
class Meta:
abstract = True
@property
def content(self):
if not hasattr(self, '_content_proxy'):
self._content_proxy = ContentProxy(self)
return self._content_proxy
def _content_for_region(self, region):
if not hasattr(self, '_feincms_content_types'):
raise ImproperlyConfigured, 'You need to create at least one content type for the %s model.' % (self.__class__.__name__)
sql = ' UNION '.join([
'SELECT %d, COUNT(id) FROM %s WHERE parent_id=%s AND region_id=%s' % (
idx,
cls._meta.db_table,
self.pk,
region.id) for idx, cls in enumerate(self._feincms_content_types)])
from django.db import connection
cursor = connection.cursor()
cursor.execute(sql)
counts = [row[1] for row in cursor.fetchall()]
if not any(counts):
return []
contents = []
for idx, cnt in enumerate(counts):
if cnt:
contents += list(
self._feincms_content_types[idx].objects.filter(
parent=self,
region=region).select_related('parent', 'region'))
return contents
@classmethod
def _create_content_base(cls):
class Meta:
abstract = True
ordering = ['ordering']
def __unicode__(self):
return u'%s on %s, ordering %s' % (self.region, self.parent, self.ordering)
def render(self, **kwargs):
render_fn = getattr(self, 'render_%s' % self.region.key, None)
if render_fn:
return render_fn(**kwargs)
raise NotImplementedError
attrs = {
'__module__': cls.__module__,
'__unicode__': __unicode__,
'render': render,
'Meta': Meta,
'parent': models.ForeignKey(cls, related_name='%(class)s_set'),
'region': models.ForeignKey(Region, related_name='%s_%%(class)s_set' % cls.__name__.lower()),
'ordering': models.IntegerField(_('ordering'), default=0),
}
cls._feincms_content_model = type('%sContent' % cls.__name__,
(models.Model,), attrs)
cls._feincms_content_types = []
return cls._feincms_content_model
@classmethod
def create_content_type(cls, model, **kwargs):
if not hasattr(cls, '_feincms_content_model'):
cls._create_content_base()
feincms_content_base = getattr(cls, '_feincms_content_model')
class Meta:
db_table = '%s_%s' % (cls._meta.db_table, model.__name__.lower())
verbose_name = model._meta.verbose_name
verbose_name_plural = model._meta.verbose_name_plural
attrs = {
'__module__': cls.__module__,
'Meta': Meta,
}
new_type = type(
model.__name__,
(model, feincms_content_base,), attrs)
cls._feincms_content_types.append(new_type)
if not hasattr(model, '_feincms_content_models'):
model._feincms_content_models = []
model._feincms_content_models.append(new_type)
if hasattr(new_type, 'handle_kwargs'):
new_type.handle_kwargs(**kwargs)
else:
for k, v in kwargs.items():
setattr(new_type, k, v)
return new_type
class ContentProxy(object):
"""
This proxy offers attribute-style access to the page contents of regions.
Example:
>>> page = Page.objects.all()[0]
>>> page.content.main
[A list of all page contents which are assigned to the region with key 'main']
"""
def __init__(self, item):
self.item = item
def __getattr__(self, attr):
"""
Get all item content instances for the specified item and region
If no item contents could be found for the current item and the region
has the inherited flag set, this method will go up the ancestor chain
until either some item contents have found or no ancestors are left.
"""
item = self.__dict__['item']
try:
region = item.template.regions.get(key=attr)
except Region.DoesNotExist:
return []
def collect_items(obj):
contents = obj._content_for_region(region)
# go to parent if this model has a parent attribute
# TODO this should be abstracted into a property/method or something
# The link which should be followed is not always '.parent'
if not contents and hasattr(obj, 'parent_id') and obj.parent_id and region.inherited:
return collect_items(obj.parent)
return contents
contents = collect_items(item)
contents.sort(key=lambda c: c.ordering)
return contents

View File

@ -1,33 +0,0 @@
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from feincms.admin import editor
from feincms.module.page.models import Page
class PageAdmin(editor.ItemEditorMixin, editor.TreeEditorMixin, admin.ModelAdmin):
# the fieldsets config here is used for the add_view, it has no effect
# for the change_view which is completely customized anyway
fieldsets = (
(None, {
'fields': ('active', 'in_navigation', 'template', 'title', 'slug',
'parent', 'language'),
}),
(_('Other options'), {
'classes': ('collapse',),
'fields': ('override_url', 'meta_keywords', 'meta_description'),
}),
)
list_display=('__unicode__', 'active', 'in_navigation',
'language', 'template')
list_filter=('active', 'in_navigation', 'language', 'template')
search_fields = ('title', 'slug', '_content_title', '_page_title',
'meta_keywords', 'meta_description')
prepopulated_fields={
'slug': ('title',),
}
show_on_top = ('title', 'active', 'in_navigation')
admin.site.register(Page, PageAdmin)

View File

@ -1,232 +0,0 @@
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.http import Http404
from django.utils import translation
from django.utils.translation import ugettext_lazy as _
import mptt
from feincms.models import TypeRegistryMetaClass, Region, Template,\
Base, ContentProxy
def get_object(path, fail_silently=False):
dot = path.rindex('.')
try:
return getattr(__import__(path[:dot], {}, {}, ['']), path[dot+1:])
except ImportError:
if not fail_silently:
raise
return None
class PagePretender(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def get_absolute_url(self):
return self.url
class NavigationExtension(object):
__metaclass__ = TypeRegistryMetaClass
name = _('navigation extension')
def children(self, page, **kwargs):
raise NotImplementedError
class PageManager(models.Manager):
def active(self):
return self.filter(active=True)
def page_for_path(self, path, raise404=False):
"""
Return a page for a path.
Example:
Page.objects.page_for_path(request.path)
"""
stripped = path.strip('/')
try:
return self.active().filter(override_url='/%s/' % stripped)[0]
except IndexError:
pass
tokens = stripped.split('/')
count = len(tokens)
filters = {'%sisnull' % ('parent__' * count): True}
for n, token in enumerate(tokens):
filters['%sslug' % ('parent__' * (count-n-1))] = token
try:
return self.active().filter(**filters)[0]
except IndexError:
if raise404:
raise Http404
raise self.model.DoesNotExist
def page_for_path_or_404(self, path):
"""
Wrapper for page_for_path which raises a Http404 if no page
has been found for the passed path.
"""
return self.page_for_path(path, raise404=True)
def best_match_for_path(self, path, raise404=False):
"""
Return the best match for a path.
"""
tokens = path.strip('/').split('/')
for count in range(len(tokens), -1, -1):
try:
return self.page_for_path('/'.join(tokens[:count]))
except self.model.DoesNotExist:
pass
if raise404:
raise Http404
return None
def in_navigation(self):
return self.active().filter(in_navigation=True)
def toplevel_navigation(self):
return self.in_navigation().filter(parent__isnull=True)
def for_request(self, request, raise404=False):
page = self.page_for_path(request.path, raise404)
page.setup_request(request)
return page
def for_request_or_404(self, request):
return self.page_for_path_or_404(request.path, raise404=True)
def best_match_for_request(self, request, raise404=False):
page = self.best_match_for_path(request.path, raise404)
page.setup_request(request)
return page
def from_request(self, request):
if hasattr(request, '_feincms_page'):
return request._feincms_page
return self.for_request(request)
class Page(Base):
active = models.BooleanField(_('active'), default=False)
# structure and navigation
title = models.CharField(_('title'), max_length=100,
help_text=_('This is used for the generated navigation too.'))
slug = models.SlugField()
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
in_navigation = models.BooleanField(_('in navigation'), default=True)
override_url = models.CharField(_('override URL'), max_length=200, blank=True,
help_text=_('Override the target URL for the navigation.'))
redirect_to = models.CharField(_('redirect to'), max_length=200, blank=True,
help_text=_('Target URL for automatic redirects.'))
_cached_url = models.CharField(_('Cached URL'), max_length=200, blank=True,
editable=False, default='')
# navigation extensions
NE_CHOICES = [(
'%s.%s' % (cls.__module__, cls.__name__), cls.name) for cls in NavigationExtension.types]
navigation_extension = models.CharField(_('navigation extension'),
choices=NE_CHOICES, blank=True, max_length=50,
help_text=_('Select the module providing subpages for this page if you need to customize the navigation.'))
# content
_content_title = models.TextField(_('content title'), blank=True,
help_text=_('The first line is the main title, the following lines are subtitles.'))
# meta stuff TODO keywords and description?
_page_title = models.CharField(_('page title'), max_length=100, blank=True,
help_text=_('Page title for browser window. Same as title by default.'))
meta_keywords = models.TextField(_('meta keywords'), blank=True,
help_text=_('This will be prepended to the default keyword list.'))
meta_description = models.TextField(_('meta description'), blank=True,
help_text=_('This will be prepended to the default description.'))
# language
language = models.CharField(_('language'), max_length=10,
choices=settings.LANGUAGES)
translations = models.ManyToManyField('self', blank=True)
class Meta:
ordering = ['tree_id', 'lft']
verbose_name = _('page')
verbose_name_plural = _('pages')
objects = PageManager()
def __unicode__(self):
return u'%s (%s)' % (self.title, self.get_absolute_url())
def save(self, *args, **kwargs):
super(Page, self).save(*args, **kwargs)
pages = self.get_descendants(include_self=True)
for page in pages:
page._generate_cached_url()
def _generate_cached_url(self):
if self.override_url:
self._cached_url = self.override_url
if self.is_root_node():
self._cached_url = u'/%s/' % (self.slug)
else:
self._cached_url = u'/%s/%s/' % ('/'.join([page.slug for page in self.get_ancestors()]), self.slug)
super(Page, self).save()
def get_absolute_url(self):
return self._cached_url
@property
def page_title(self):
if self._page_title:
return self._page_title
return self.content_title
@property
def content_title(self):
if not self._content_title:
return self.title
try:
return self._content_title.splitlines()[0]
except IndexError:
return u''
@property
def content_subtitle(self):
return u'\n'.join(self._content_title.splitlines()[1:])
def setup_request(self, request):
translation.activate(self.language)
request.LANGUAGE_CODE = translation.get_language()
request._feincms_page = self
def extended_navigation(self):
if not self.navigation_extension:
return []
cls = get_object(self.navigation_extension, fail_silently=True)
if not cls:
return []
return cls().children(self)
mptt.register(Page)

View File

@ -1,63 +0,0 @@
from django import template
from feincms.module.page.models import Page
from feincms.templatetags.utils import *
register = template.Library()
class NavigationNode(SimpleAssignmentNodeWithVarAndArgs):
"""
Example:
{% feincms_navigation of feincms_page as sublevel level=2 %}
{% for p in sublevel %}
<a href="{{ p.get_absolute_url }}">{{ p.title }}</a>
{% endfor %}
"""
def what(self, instance, args):
level = int(args.get('level', 1))
if level <= 1:
return Page.objects.toplevel_navigation()
# mptt starts counting at 0, NavigationNode at 1; if we need the submenu
# of the current page, we have to add 2 to the mptt level
if instance.level+2 == level:
return instance.children.in_navigation()
try:
return instance.get_ancestors()[level-2].children.in_navigation()
except IndexError:
return []
register.tag('feincms_navigation', do_simple_assignment_node_with_var_and_args_helper(NavigationNode))
class ParentLinkNode(SimpleNodeWithVarAndArgs):
"""
{% feincms_parentlink of feincms_page level=1 %}
"""
def what(self, page, args):
level = int(args.get('level', 1))
if page.level+1 == level:
return page.get_absolute_url()
elif page.level+1 < level:
return '#'
try:
return page.get_ancestors()[level-1].get_absolute_url()
except IndexError:
return '#'
register.tag('feincms_parentlink', do_simple_node_with_var_and_args_helper(ParentLinkNode))
class BestMatchNode(SimpleAssignmentNodeWithVar):
"""
{% feincms_bestmatch for request.path as feincms_page %}
"""
def what(self, path):
return Page.objects.best_match_for_path(path)
register.tag('feincms_bestmatch', do_simple_assignment_node_with_var_helper(BestMatchNode))

View File

@ -1,13 +0,0 @@
from django.shortcuts import render_to_response
from django.template import RequestContext
from feincms.module.page.models import Page
def render_to_response_best_match(request, template_name, dictionary=None):
dictionary = dictionary or {}
dictionary['feincms_page'] = Page.objects.best_match_for_request(request)
return render_to_response(template_name, dictionary,
context_instance=RequestContext(request))

View File

@ -1,227 +0,0 @@
{% extends "admin/change_form.html" %}
{% load i18n admin_modify adminmedia %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %}
{% block extrahead %}{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />
<script type="text/javascript" src="../../../jsi18n/"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery-1.3.min.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.ui.all.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.livequery.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.alerts.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}helper.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}listener.js"></script>
<script type="text/javascript" src="/media/sys/feinheit/tinymce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
mode: "none",
theme: "advanced",
language: "en",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_buttons1: "fullscreen,|,formatselect,image,media,code,|,cut,copy,paste,|,bold,italic,|,bullist,numlist,|,link,unlink",
theme_advanced_buttons2: "",
theme_advanced_buttons3: "",
theme_advanced_path: false,
theme_advanced_blockformats: "p,h2,h3",
theme_advanced_resizing: true,
width: '600',
height: '300',
content_css: "/path_to_your_media/css/preview.css",
plugins: "advimage,advlink,fullscreen,table,preview,media,inlinepopups",
advimage_update_dimensions_onchange: true,
//file_browser_callback: "CustomFileBrowser",
relative_urls: false
});
function init_pagecontent() {
// handle special page content type needs
// this is not really extensible, but it works for now
$('.order-machine textarea[name*=richtext]:visible').each(function(){
tinyMCE.execCommand('mceAddControl', true, this.id);
});
}
IMG_ARROW_DOWN_PATH = "{{ FEINCMS_ADMIN_MEDIA }}img/arrow_down.gif";
IMG_ARROW_RIGHT_PATH = "{{ FEINCMS_ADMIN_MEDIA }}img/arrow_right.gif";
IMG_CIRCLE_PATH = "{{ FEINCMS_ADMIN_MEDIA }}img/circle.gif";
IMG_DELETELINK_PATH = "{{ FEINCMS_ADMIN_MEDIA }}img/icon_deletelink.gif";
IMG_MOVE_PATH = "{{ FEINCMS_ADMIN_MEDIA }}img/icon_move.gif";
REGIONS = [];
REGION_MAP = [];
{% for region in page.template.regions.all %}
REGIONS.push('{{ region.key }}');
REGION_MAP.push('{{ region.id }}');
{% endfor %}
ACTIVE_REGION = 0;
CONTENT_NAMES = {
{% for name, value in content_types %}'{{ value }}': '{{ name }}'{% if not forloop.last %},{% endif %}
{% endfor %}};
$(document).ready(function(){
// move contents into their corresponding regions and do some simple formatting
$("div[id$=_set]").children().each(function(){
if (!($(this).hasClass("header"))) {
$(this).find("select[name$=region]").addClass("region-choice-field").parents("tr").hide();
$(this).find("input[name$=DELETE]").addClass("delete-field").parents("tr").hide();
$(this).find("input[name$=ordering]").addClass("order-field").parents("tr").hide();
$(this).find("input[name$=id]").hide().prev().hide();
$(this).find("input[name$=parent]").hide().prev().hide();
var region_id = $(this).find(".region-choice-field").val();
region_id = REGION_MAP.indexOf(region_id);
var content_type = $(this).attr("id").substr(0, $(this).attr("id").indexOf("_"));
region_append(region_id,$(this), CONTENT_NAMES[content_type]);
set_item_field_value($(this),"region-choice-field",region_id)
}
});
// register regions as sortable for drag N drop
$(".order-machine").sortable({
handle: '.handle',
helper: 'clone',
stop: function(event, ui) {
richify_poor($(ui.item));
}
});
// hide content on drag n drop
$(".handle").mousedown(function(){
poorify_rich($(this).parents(".order-item"));
});
$(".handle").mouseup(function(){
richify_poor($(this).parents(".order-item"));
});
// convert text areas to rich text editors.
init_pagecontent();
if(window.location.hash) {
$(window.location.hash+'_tab').trigger('click');
}
// bring order to chaos
zucht_und_ordnung(true);
{% block extra-init-js %}{% endblock %}
});
</script>
<link rel="stylesheet" type="text/css" href="{{ FEINCMS_ADMIN_MEDIA }}css/layout.css" />
<link rel="stylesheet" type="text/css" href="{{ FEINCMS_ADMIN_MEDIA }}css/jquery.alerts.css" media="screen" />
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="../../../">{% trans "Home" %}</a> &rsaquo;
<a href="../../">{{ opts.app_label|capfirst|escape }}</a> &rsaquo;
<a href="../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
{{ page.title|truncatewords:"18" }}
</div>
{% endblock %}
{% block content %}
<div id="content-main">
{% block object-tools %}
<ul class="object-tools">
{% if page.get_absolute_url %}
<li><a target="_blank" href="{{ page.get_absolute_url }}" class="viewsitelink">{% trans "View on site" %}</a></li>
{% endif %}
</ul>
{% endblock %}
<hr/>
<form name="main_form" enctype="multipart/form-data" action="." method="post" id="{{ opts.module_name }}_form">
<div id="overview">
<p style="float:right;" class="deletelink-box"><a href="delete/" class="deletelink">{% trans "Delete" %}</a></p>
{% for field in top_fieldset %}
{{ field.label_tag }}
<span>{{ field }}{{ field.errors }}</span>
{% endfor %}
<input type="submit" class="submit_form" value="{% trans 'Save' %}" />
<hr/>
{{ page_form.template.label_tag }}
<span>{{ page_form.template }}{{ page_form.template.errors }}</span>
<input type="button" class="cancel" value="{% trans 'Change Template' %}" />
<hr/>
</div>
<div id="main_wrapper">
<div class="navi_tab tab_active" id="settings_tab">Settings</div>
{% for region in page.template.regions.all %}<div class="navi_tab tab_inactive" id="{{ region.key }}_tab">{{ region.title }}</div>{% endfor %}
<div id="main">
<div id="settings_body">
<table>
{{ settings_fieldset.as_table }}
</table>
</div>
{% for region in page.template.regions.all %}
<div id="{{ region.key }}_body" class="panel">
<div class="empty-machine-msg">
{% trans "Region empty" %}
</div>
<div class="empty-machine-msg" style="margin-left:20px; margin-top:20px;">
{% if region.inherited %}
{% trans "Content from the parent site is automatically inherited. To override this behaviour, add some content." %}
{% endif %}
</div>
<div class="order-machine">
</div>
<div class="machine-control">
<div class="control-unit">
<span>Add New item:</span> <br/>
<select name="order-machine-add-select">
{% for n,v in content_types %} <option value="{{ v }}">{{ n }}</option> {% endfor %}
</select>
<input type="button" class="order-machine-add-button button" value="OK" />
</div>
<div class="control-unit">
<span>Move selected item to:</span> <br/>
<select name="order-machine-move-select">
{% for r in page.template.regions.all %} {% ifnotequal region r %} <option value="{{ r.key }}">{{ r.title }}</option> {% endifnotequal %} {% endfor %}
</select>
<input type="button" class="order-machine-move-button button" value="OK" />
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div id="inlines" style="display:none">
{% for formset in inline_formsets %}
<div id="{{ formset.rel_name }}">
<div class="header">
{{ formset.management_form }}
<h3>{{ formset.rel_name }}</h3>
</div>
{% for form in formset.forms %}
<div id="{{ formset.rel_name }}_item_{{ forloop.counter0 }}">
<table>
{{ form.as_table }}
</table>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</form>
</div>
{% endblock %}

View File

@ -1,145 +0,0 @@
{% extends "admin/change_list.html" %}
{% load i18n admin_modify adminmedia mptt_tags %}
{% block title %}{{ block.super }}{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="../../../jsi18n/"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery-1.3.min.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.ui.all.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.livequery.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.alerts.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}helper.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}listener.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.treeTable.js"></script>
<script type="text/javascript" src="{{ FEINCMS_ADMIN_MEDIA }}jquery.json-1.3.js"></script>
<script type="text/javascript">
ancestors = [{% for page in object_list %}'{{ page.parent_id|default_if_none:"0" }}'{% if not forloop.last %},{% endif %} {% endfor %}];
tablestr = '';
{% for page in object_list %}tablestr += add_row({{ forloop.counter }}, {{ page.id }}, "{{ page.parent_id|default_if_none:"-1" }}", "{{ page.title }}", ["{{ page.active }}", "{{ page.in_navigation }}"]);
{% endfor %}
function add_row(node_id, page_id, parent_id, page_title, attrs) {
var str = '<tr id="node-' + node_id + '" class="page-id-' + page_id + ' ';
if (parseInt(parent_id) >= 0)
str += 'child-of-node-'+ancestors.indexOf(parent_id);
str += '">';
str += '<td><div class="wrap nohover">';
str += '<div class="insert-as-child"></div>';
str += '<span class="title-col"><a href="'+page_id+'"><strong>'+page_title+'</strong></a><img class="move-node" src="{{ FEINCMS_ADMIN_MEDIA }}img/icon_move.gif" /></span>';
str += '<div class="insert-as-sibling"></div>';
str += '</div></td>';
for (key in attrs)
str += '<td>'+attrs[key]+'</td>';
str += '<td><img class="del-page" src="{{ FEINCMS_ADMIN_MEDIA }}img/icon_deletelink.gif"/></td></tr>';
return str;
}
$(document).ready(function() {
// build table
$("#sitetree tbody").append(tablestr);
// register
$("#sitetree").treeTable();
// configure draggable
$("#sitetree .title-col").draggable({
helper: function(){ return $(this).parent().clone(); } ,
handle: ".move-node",
opacity: .75,
refreshPositions: true,
revert: "invalid",
revertDuration: 300,
scroll: true
});
// configure droppable to insert as child
$("#sitetree .insert-as-child").each(function() {
$(this).droppable({
accept: ".title-col",
tolerance: "intersect",
drop: function(e, ui) {
handle_drop_event($(ui.draggable).parents("tr"), $(this).parents("tr"), "child")
},
over: function(e, ui) {
$(this).parent().removeClass("nohover").addClass("hover-as-child");
},
out: function(e, ui) {
$(this).parent().removeClass("hover-as-child").addClass("nohover");
}
});
});
// configure droppable to insert as sibling
$("#sitetree .insert-as-sibling").each(function() {
$(this).droppable({
accept: ".title-col",
tolerance: "intersect",
drop: function(e, ui) {
handle_drop_event($(ui.draggable).parents("tr"), $(this).parents("tr"), "sibling")
},
over: function(e, ui) {
var row = '<div style="background-color:#bcf; height:4px; width:100%; margin:-8px 0px 4px -5px; position:relative; z-index:10;"></div>'
$(row).insertBefore($(this).parent());
},
out: function(e, ui) {
$(this).parent().prev().remove();
}
});
});
$(".wrap").live('click',function() {
if ($(this).find(".expander").length > 0)
$(this).parents("tr").toggleBranch();
});
$(".save_tree").click(function(){
save_page_tree();
});
$(".del-page").click(function(){
handle_page_delete($(this).parents("tr"));
});
});
</script>
<link rel="stylesheet" type="text/css" href="{{ FEINCMS_ADMIN_MEDIA }}css/layout.css" />
<link rel="stylesheet" type="text/css" href="{{ FEINCMS_ADMIN_MEDIA }}css/jquery.alerts.css" media="screen" />
<link href="{{ FEINCMS_ADMIN_MEDIA }}css/jquery.treeTable.css" rel="stylesheet" type="text/css" />
{% endblock %}
{% block content %}
<div id="content-main">
{% block object-tools %}
{% if has_add_permission %}
<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}</a></li></ul>
{% endif %}
{% endblock %}
</div>
<input type="button" value="save tree" class="save_tree" style="margin: 20px 5px -10px 460px;"/>
<div id="sitetree-wrapper">
<table id="sitetree" border="1">
<thead>
<tr id="table_header">
<th width="400">{% trans "Page" %}</th>
<th>{% trans "active" %}</th>
<th>{% trans "in navi" %}</th>
<th>{% trans "delete" %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{% endblock %}

View File

@ -1,8 +0,0 @@
<h2><a href="{{ feed_link }}">{{ feed_title }}</a></h2>
<ul>
{% for entry in entries %}
<li><a href="{{ entry.link }}">{{ entry.title }}</a></li>
{% endfor %}
</ul>

View File

@ -1,75 +0,0 @@
from django import template
from feincms.module.page.models import Page
register = template.Library()
@register.simple_tag
def feincms_render_region(page, region, request):
"""
{% feincms_render_region feincms_page "main" request %}
"""
contents = getattr(page.content, region)
return u''.join(content.render(request=request) for content in contents)
@register.simple_tag
def feincms_render_content(content, request):
"""
{% feincms_render_content pagecontent request %}
"""
return content.render(request=request)
class NaviLevelNode(template.Node):
""" Gets navigation based on current page OR request, dependant on choice of second parameter (of vs. from).
Top navigation level is 1.
If navigation level + 1 > page.level, the ouput is none, because there is no well-defined sub-sub-navigation for a page.
Example usage:
1) {% feincms_get_navi_level 1 of page as pages %}
2) {% feincms_get_navi_level 1 from request as pages %}
Side-note: If not using mptt to retrieve pages, the ordering cannot be dertermined by 'id'.
Instead, as a "hack", we can sort by field 'lft', because we understand how mptt works :-)
"""
def __init__(self, level, switch, obj, dummy, varname):
self.level = long(int(level) - 1)
self.obj = template.Variable(obj)
self.varname = varname
self.switch = switch
def render(self, context):
if self.switch == 'of':
# obj is a Page
page = self.obj.resolve(context)
else: # self.switch == 'from'
# obj is a request
page = Page.objects.from_request(self.obj.resolve(context))
if int(self.level) == 0:
# top level
pages = Page.objects.filter(in_navigation=True, level=long(0)).order_by('lft')
elif self.level <= page.level:
ancestor = page.get_ancestors()[int(self.level) - 1]
pages = Page.objects.filter(in_navigation=True, parent__pk=ancestor.pk).order_by('lft')
elif self.level == page.level + 1:
pages = Page.objects.filter(in_navigation=True, parent__pk=page.pk).order_by('lft')
else:
pages = []
context[self.varname] = pages
return ''
@register.tag
def feincms_get_navi_level(parser, token):
try:
tag_name, level, switch, obj, dummy, varname = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires exactly five arguments" % token.contents.split()[0]
return NaviLevelNode(level, switch, obj, dummy, varname)

View File

@ -1,150 +0,0 @@
'''
I really hate repeating myself. These are helpers that avoid typing the
whole thing over and over when implementing additional template tags
They help implementing tags of the form
{% tag as var_name %} (SimpleAssignmentNode)
and
{% tag of template_var as var_name %} (SimpleAssignmentNodeWithVar)
'''
from django import template
def _parse_args(argstr):
try:
args = {}
for token in argstr.split(','):
k, v = token.split('=')
args[k] = v
return args
except TypeError:
raise template.TemplateSyntaxError('Malformed arguments')
def do_simple_node_with_var_and_args_helper(cls):
def _func(parser, token):
try:
tag_name, of_, in_var_name, args = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError
return cls(tag_name, in_var_name, args)
return _func
class SimpleNodeWithVarAndArgs(template.Node):
def __init__(self, tag_name, in_var_name, args):
self.tag_name = tag_name
self.in_var = template.Variable(in_var_name)
self.args = args
def render(self, context):
try:
instance = self.in_var.resolve(context)
except template.VariableDoesNotExist:
return ''
return self.what(instance, _parse_args(self.args))
def do_simple_node_with_var_helper(cls):
def _func(parser, token):
try:
tag_name, of_, in_var_name = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError
return cls(tag_name, in_var_name)
return _func
class SimpleNodeWithVar(template.Node):
def __init__(self, tag_name, in_var_name):
self.tag_name = tag_name
self.in_var = template.Variable(in_var_name)
def render(self, context):
try:
instance = self.in_var.resolve(context)
except template.VariableDoesNotExist:
return ''
return self.what(instance)
def do_simple_assignment_node_helper(cls):
def _func(parser, token):
try:
tag_name, as_, var_name = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError
return cls(tag_name, var_name)
return _func
class SimpleAssignmentNode(template.Node):
def __init__(self, tag_name, var_name):
self.tag_name = tag_name
self.var_name = var_name
def render(self, context):
context[self.var_name] = self.what()
return ''
def do_simple_assignment_node_with_var_helper(cls):
def _func(parser, token):
try:
tag_name, of_, in_var_name, as_, var_name = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError
return cls(tag_name, in_var_name, var_name)
return _func
class SimpleAssignmentNodeWithVar(template.Node):
def __init__(self, tag_name, in_var_name, var_name):
self.tag_name = tag_name
self.in_var = template.Variable(in_var_name)
self.var_name = var_name
def render(self, context):
try:
instance = self.in_var.resolve(context)
except template.VariableDoesNotExist:
context[self.var_name] = []
return ''
context[self.var_name] = self.what(instance)
return ''
def do_simple_assignment_node_with_var_and_args_helper(cls):
def _func(parser, token):
try:
tag_name, of_, in_var_name, as_, var_name, args = token.contents.split()
except ValueError:
raise template.TemplateSyntaxError
return cls(tag_name, in_var_name, var_name, args)
return _func
class SimpleAssignmentNodeWithVarAndArgs(template.Node):
def __init__(self, tag_name, in_var_name, var_name, args):
self.tag_name = tag_name
self.in_var = template.Variable(in_var_name)
self.var_name = var_name
self.args = args
def render(self, context):
try:
instance = self.in_var.resolve(context)
except template.VariableDoesNotExist:
context[self.var_name] = []
return ''
context[self.var_name] = self.what(instance, _parse_args(self.args))
return ''

View File

@ -1,23 +0,0 @@
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils import translation
from feincms.module.page.models import Page
def handler(request, path=None):
if path is None:
path = request.path
page = Page.objects.page_for_path_or_404(path)
if page.redirect_to:
return HttpResponseRedirect(page.redirect_to)
page.setup_request(request)
return render_to_response(page.template.path, {
'feincms_page': page,
}, context_instance=RequestContext(request))

View File

@ -1,16 +0,0 @@
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps
from feincms.module.page.models import Page
def add_page_to_extra_context(view_func):
def inner(request, *args, **kwargs):
kwargs.setdefault('extra_context', {})
kwargs['extra_context']['feincms_page'] = Page.objects.best_match_for_request(request)
return view_func(request, *args, **kwargs)
return wraps(view_func)(inner)

View File

@ -1,8 +0,0 @@
from django.views.generic import create_update
from feincms.views.decorators import add_page_to_extra_context
create_object = add_page_to_extra_context(create_update.create_object)
update_object = add_page_to_extra_context(create_update.update_object)
delete_object = add_page_to_extra_context(create_update.delete_object)

View File

@ -1,12 +0,0 @@
from django.views.generic import date_based
from feincms.views.decorators import add_page_to_extra_context
archive_index = add_page_to_extra_context(date_based.archive_index)
archive_year = add_page_to_extra_context(date_based.archive_year)
archive_month = add_page_to_extra_context(date_based.archive_month)
archive_week = add_page_to_extra_context(date_based.archive_week)
archive_day = add_page_to_extra_context(date_based.archive_day)
archive_today = add_page_to_extra_context(date_based.archive_today)
object_detail = add_page_to_extra_context(date_based.object_detail)

View File

@ -1,7 +0,0 @@
from django.views.generic import list_detail
from feincms.views.decorators import add_page_to_extra_context
object_list = add_page_to_extra_context(list_detail.object_list)
object_detail = add_page_to_extra_context(list_detail.object_detail)

View File

@ -1,6 +0,0 @@
from django.views.generic import simple
from feincms.views.decorators import add_page_to_extra_context
direct_to_template = add_page_to_extra_context(simple.direct_to_template)

View File

@ -86,8 +86,6 @@ INSTALLED_APPS = (
'troggle.profiles',
'troggle.core',
'troggle.imagekit',
'mptt', #This is django-mptt (modifed preorder tree traversal) which allows the tree structure of subcaves.
'feincms' #This is a little content management app that does the javascript admin page for mptt.
)
FEINCMS_ADMIN_MEDIA=MEDIA_URL + 'feincms/'

View File

@ -67,7 +67,7 @@ urlpatterns = patterns('',
url(r'^logbook/?$',views_other.downloadLogbook, name="downloadlogbook"),
url(r'^cave/(?P<cave_id>[^/]+)/qm\.csv/?$', views_other.downloadQMs, name="downloadqms"),
(r'^downloadqms$', views_other.downloadQMs),
url(r'^cave/(?P<cave_id>[^/]+)(?P<subcave>/.*)/?$', subcave, name="subcave"),
url(r'^eyecandy$', views_other.eyecandy),
(r'^admin/doc/?', include('django.contrib.admindocs.urls')),