Dodanie aplikacji sponsors do zarządzania logami sponsorów w stopce.
authorMarek Stępniowski <marek@stepniowski.com>
Fri, 9 Oct 2009 15:09:14 +0000 (17:09 +0200)
committerMarek Stępniowski <marek@stepniowski.com>
Fri, 9 Oct 2009 15:18:03 +0000 (17:18 +0200)
13 files changed:
apps/sponsors/__init__.py [new file with mode: 0644]
apps/sponsors/admin.py [new file with mode: 0644]
apps/sponsors/models.py [new file with mode: 0644]
apps/sponsors/static/css/sponsors.css [new file with mode: 0644]
apps/sponsors/static/js/ordered_select_multiple.js [new file with mode: 0644]
apps/sponsors/templates/sponsors/sponsors.html [new file with mode: 0644]
apps/sponsors/templatetags/__init__.py [new file with mode: 0644]
apps/sponsors/templatetags/sponsor_tags.py [new file with mode: 0644]
apps/sponsors/widgets.py [new file with mode: 0644]
wolnelektury/media/css/sponsors.css [new file with mode: 0644]
wolnelektury/media/js/ordered_select_multiple.js [new file with mode: 0644]
wolnelektury/settings.py
wolnelektury/templates/base.html

diff --git a/apps/sponsors/__init__.py b/apps/sponsors/__init__.py
new file mode 100644 (file)
index 0000000..f39d8b4
--- /dev/null
@@ -0,0 +1,3 @@
+# -*- encoding: utf-8 -*-
+__author__ = u'Marek Stępniowski, <marek@stepniowski.com>'
+__version__ = '0.1'
diff --git a/apps/sponsors/admin.py b/apps/sponsors/admin.py
new file mode 100644 (file)
index 0000000..c66a086
--- /dev/null
@@ -0,0 +1,21 @@
+from django.db import models
+from django.contrib import admin
+
+from sponsors.models import Sponsor, SponsorGroup
+from sponsors.widgets import OrderedSelectMultiple
+
+class SponsorGroupAdmin(admin.ModelAdmin):
+    formfield_overrides = {
+        models.CommaSeparatedIntegerField: {'widget': OrderedSelectMultiple},
+    }   
+    list_display = ('name',)
+    search_fields = ('name',)
+    ordering = ('name',)
+
+class SponsorAdmin(admin.ModelAdmin):
+    list_display = ('name',)
+    search_fields = ('name',)
+    ordering = ('name',)
+
+admin.site.register(SponsorGroup, SponsorGroupAdmin)
+admin.site.register(Sponsor, SponsorAdmin)
diff --git a/apps/sponsors/models.py b/apps/sponsors/models.py
new file mode 100644 (file)
index 0000000..ffad8e7
--- /dev/null
@@ -0,0 +1,35 @@
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class Sponsor(models.Model):
+    name = models.CharField(_('name'), max_length=120)
+    _description = models.CharField(_('description'), blank=True, max_length=255)
+    logo = models.ImageField(_('logo'), upload_to='sponsors/sponsor/logo')
+    url = models.URLField(_('url'), blank=True, verify_exists=False)
+    
+    def __unicode__(self):
+        return self.name
+
+    def description(self):
+        if len(self._description):
+            return self._description
+        else:
+            return self.name
+
+
+class SponsorGroup(models.Model):
+    name = models.CharField(_('name'), max_length=120)
+    order = models.IntegerField(_('order'), default=0)
+    column_width = models.PositiveIntegerField(_('column width'))
+    sponsor_ids = models.CommaSeparatedIntegerField(_('sponsors'), max_length=255)
+    
+    def sponsors(self):
+        ids = [int(pk) for pk in self.sponsor_ids.split(',')]
+        result = Sponsor.objects.in_bulk(ids)
+        return [result[pk] for pk in ids]
+    sponsors.changes_data = False
+    
+    def __unicode__(self):
+        return self.name
+
diff --git a/apps/sponsors/static/css/sponsors.css b/apps/sponsors/static/css/sponsors.css
new file mode 100644 (file)
index 0000000..f3d7ed9
--- /dev/null
@@ -0,0 +1,4 @@
+.sponsor-group {
+    float: left;
+    overflow: hidden;
+}
diff --git a/apps/sponsors/static/js/ordered_select_multiple.js b/apps/sponsors/static/js/ordered_select_multiple.js
new file mode 100644 (file)
index 0000000..e4fd74d
--- /dev/null
@@ -0,0 +1,63 @@
+(function($) {
+  $.fn.orderedSelectMultiple = function(options) {
+    var settings = {
+      choices: []
+    };
+    $.extend(settings, options);
+    
+    var input = $(this).hide();
+    var values = input.val().split(',');
+    
+    var container = $('<div></div>').insertAfter($(this));
+    var choicesList = $('<ol class="choices connectedSortable"></ol>').appendTo(container).css({
+      width: 200, float: 'left', minHeight: 200, backgroundColor: '#eee', margin: 0, padding: 0
+    });
+    var valuesList = $('<ol class="values connectedSortable"></ol>').appendTo(container).css({
+      width: 200, float: 'left', minHeight: 200, backgroundColor: '#eee', margin: 0, padding: 0
+    });
+    var choiceIds = [];
+    $.each(settings.choices, function() {
+      choiceIds.push('' + this.id);
+    });
+    
+    function createItem(hash) {
+      return $('<li>' + hash.name + '</li>').css({
+        backgroundColor: '#cff',
+        display: 'block',
+        border: '1px solid #cdd',
+        padding: 2,
+        margin: 0
+      }).data('obj-id', hash.id);
+    }
+    
+    $.each(settings.choices, function() {
+      if ($.inArray('' + this.id, values) == -1) {
+        choicesList.append(createItem(this));
+      }
+    });
+    
+    $.each(values, function() {
+      var index = $.inArray('' + this, choiceIds); // Why this[0]?
+      if (index != -1) {
+        valuesList.append(createItem(settings.choices[index]));
+      }
+    });
+    
+    choicesList.sortable({
+               connectWith: '.connectedSortable'
+       }).disableSelection();
+       
+       valuesList.sortable({
+               connectWith: '.connectedSortable',
+               update: function() {
+                 values = [];
+                 $('li', valuesList).each(function(index) {
+          values.push($(this).data('obj-id'));
+          console.log($(this).data('obj-id'));
+                 });
+                 console.log('update', values.join(','), input);
+                 input.val(values.join(','));
+               }
+       }).disableSelection();
+  };
+})(jQuery);
diff --git a/apps/sponsors/templates/sponsors/sponsors.html b/apps/sponsors/templates/sponsors/sponsors.html
new file mode 100644 (file)
index 0000000..d5decae
--- /dev/null
@@ -0,0 +1,11 @@
+<div class="sponsors">
+{% for group in sponsor_groups %}
+       <div class="sponsor-group" style="width: {{ group.column_width }}px">
+               <p class="sponsor-group-name">{{ group.name }}</p>
+               {% for sponsor in group.sponsors %}
+                       <div class="sponsor">{% if sponsor.url %}<a style="sponsor-link" href="{{ sponsor.url }}" >{% endif %}<img class="sponsor-logo" src="{{ sponsor.logo.url }}" alt="{{ sponsor.description }}"/>{% if sponsor.url %}</a>{% endif %}</div>
+               {% endfor %}
+       </div>
+{% endfor %}
+<div style="clear: both" />
+</div>
diff --git a/apps/sponsors/templatetags/__init__.py b/apps/sponsors/templatetags/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/sponsors/templatetags/sponsor_tags.py b/apps/sponsors/templatetags/sponsor_tags.py
new file mode 100644 (file)
index 0000000..87289e8
--- /dev/null
@@ -0,0 +1,12 @@
+from django import template
+
+from sponsors import models
+
+
+register = template.Library()
+
+
+def sponsors():
+    return {'sponsor_groups': models.SponsorGroup.objects.all()}
+    
+compressed_js = register.inclusion_tag('sponsors/sponsors.html')(sponsors)
diff --git a/apps/sponsors/widgets.py b/apps/sponsors/widgets.py
new file mode 100644 (file)
index 0000000..2ed5793
--- /dev/null
@@ -0,0 +1,30 @@
+from django import forms
+from django.conf import settings
+from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext_lazy as _
+
+from sponsors import models
+
+
+class OrderedSelectMultiple(forms.TextInput):
+    """
+    A SelectMultiple with a JavaScript interface.
+    """
+    class Media:
+        js = (
+            'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js',
+            'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js',
+            settings.MEDIA_URL + 'js/ordered_select_multiple.js',
+        )
+
+    def render(self, name, value, attrs=None, choices=()):
+        output = [super(OrderedSelectMultiple, self).render(name, value, attrs)]
+        choices = [(unicode(obj), obj.pk) for obj in models.Sponsor.objects.all()]
+        choices_js = ', '.join('{name: "%s", id: %d}' % choice for choice in choices)
+        output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
+        # TODO: "id_" is hard-coded here. This should instead use the correct
+        # API to determine the ID dynamically.
+        output.append(u'$("#id_%s").orderedSelectMultiple({choices: [%s]}); });</script>\n' % 
+            (name, choices_js))
+        return mark_safe(u''.join(output))
+
diff --git a/wolnelektury/media/css/sponsors.css b/wolnelektury/media/css/sponsors.css
new file mode 100644 (file)
index 0000000..f5497c1
--- /dev/null
@@ -0,0 +1,8 @@
+.sponsor-group {
+    float: left;
+    overflow: hidden;
+}
+
+.sponsor-logo {
+    float: left;
+}
\ No newline at end of file
diff --git a/wolnelektury/media/js/ordered_select_multiple.js b/wolnelektury/media/js/ordered_select_multiple.js
new file mode 100644 (file)
index 0000000..e4fd74d
--- /dev/null
@@ -0,0 +1,63 @@
+(function($) {
+  $.fn.orderedSelectMultiple = function(options) {
+    var settings = {
+      choices: []
+    };
+    $.extend(settings, options);
+    
+    var input = $(this).hide();
+    var values = input.val().split(',');
+    
+    var container = $('<div></div>').insertAfter($(this));
+    var choicesList = $('<ol class="choices connectedSortable"></ol>').appendTo(container).css({
+      width: 200, float: 'left', minHeight: 200, backgroundColor: '#eee', margin: 0, padding: 0
+    });
+    var valuesList = $('<ol class="values connectedSortable"></ol>').appendTo(container).css({
+      width: 200, float: 'left', minHeight: 200, backgroundColor: '#eee', margin: 0, padding: 0
+    });
+    var choiceIds = [];
+    $.each(settings.choices, function() {
+      choiceIds.push('' + this.id);
+    });
+    
+    function createItem(hash) {
+      return $('<li>' + hash.name + '</li>').css({
+        backgroundColor: '#cff',
+        display: 'block',
+        border: '1px solid #cdd',
+        padding: 2,
+        margin: 0
+      }).data('obj-id', hash.id);
+    }
+    
+    $.each(settings.choices, function() {
+      if ($.inArray('' + this.id, values) == -1) {
+        choicesList.append(createItem(this));
+      }
+    });
+    
+    $.each(values, function() {
+      var index = $.inArray('' + this, choiceIds); // Why this[0]?
+      if (index != -1) {
+        valuesList.append(createItem(settings.choices[index]));
+      }
+    });
+    
+    choicesList.sortable({
+               connectWith: '.connectedSortable'
+       }).disableSelection();
+       
+       valuesList.sortable({
+               connectWith: '.connectedSortable',
+               update: function() {
+                 values = [];
+                 $('li', valuesList).each(function(index) {
+          values.push($(this).data('obj-id'));
+          console.log($(this).data('obj-id'));
+                 });
+                 console.log('update', values.join(','), input);
+                 input.val(values.join(','));
+               }
+       }).disableSelection();
+  };
+})(jQuery);
index bdbc992..9e9f6a5 100644 (file)
@@ -96,6 +96,7 @@ INSTALLED_APPS = [
     
     # external
     'south',
+    'sponsors',
     'newtagging',
     'pagination',
     'chunks',
@@ -108,7 +109,7 @@ CACHE_BACKEND = 'locmem:///?max_entries=3000'
 # CSS and JavaScript file groups
 COMPRESS_CSS = {
     'all': {
-        'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/master.plain.css',),
+        'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/master.plain.css', 'css/sponsors.css',),
         'output_filename': 'css/all.min.css',
     },
     'book': {
index 4e7a6fa..ec75d63 100644 (file)
@@ -1,4 +1,4 @@
-{% load chunks compressed catalogue_tags %}
+{% load chunks compressed catalogue_tags sponsor_tags %}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
                 Fundacja Nowoczesna Polska, 00-514 Warszawa, ul. Marszałkowska 84/92 lok. 125, tel/fax: (22) 621-30-17,
                 e-mail: <a href="mailto:fundacja@nowoczesnapolska.org.pl">fundacja@nowoczesnapolska.org.pl</a>
             </p>
-<p>
-    <img src="{% attachment 'footer-img' %}" usemap="#footermap" alt="Partnerzy serwisu" />
-<MAP NAME="footermap">{% chunk 'footer-map' %}</MAP>
-</p>
 
+                       {% sponsors %}
         </div>
         <div id="login-register-window">
             <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>