From: Frédéric Péters Date: Sat, 20 Feb 2016 10:56:53 +0000 (+0100) Subject: add gallery support (taken from #7344) X-Git-Tag: v2021~53 X-Git-Url: https://git.0d.be/?p=django-panik-combo.git;a=commitdiff_plain;h=2a5ea1bb05d540df24e8241e78f906252116354f add gallery support (taken from #7344) --- diff --git a/MANIFEST.in b/MANIFEST.in index 7f82931..1690b3f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,6 @@ include AUTHORS include COPYING include README + +recursive-include combo/static *.js +recursive-include combo/templates *.html diff --git a/gallery/__init__.py b/gallery/__init__.py new file mode 100644 index 0000000..d98cf04 --- /dev/null +++ b/gallery/__init__.py @@ -0,0 +1,26 @@ +# combo - content management system +# Copyright (C) 2015 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import django.apps + +class AppConfig(django.apps.AppConfig): + name = 'gallery' + + def get_after_manager_urls(self): + from . import urls + return urls.manager_urlpatterns + +default_app_config = 'gallery.AppConfig' diff --git a/gallery/forms.py b/gallery/forms.py new file mode 100644 index 0000000..c4a1420 --- /dev/null +++ b/gallery/forms.py @@ -0,0 +1,31 @@ +# combo - content management system +# Copyright (C) 2015 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import Image + +class ImageAddForm(forms.ModelForm): + class Meta: + model = Image + fields = ('image', 'title',) + + +class ImageEditForm(forms.ModelForm): + class Meta: + model = Image + fields = ('title',) diff --git a/gallery/migrations/0001_initial.py b/gallery/migrations/0001_initial.py new file mode 100644 index 0000000..d7e05d0 --- /dev/null +++ b/gallery/migrations/0001_initial.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0001_initial'), + ('data', '0005_auto_20150226_0903'), + ] + + operations = [ + migrations.CreateModel( + name='GalleryCell', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('placeholder', models.CharField(max_length=20)), + ('order', models.PositiveIntegerField()), + ('slug', models.SlugField(verbose_name='Slug', blank=True)), + ('public', models.BooleanField(default=True, verbose_name='Public')), + ('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)), + ('page', models.ForeignKey(to='data.Page')), + ], + options={ + 'verbose_name': 'Gallery', + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='Image', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('image', models.ImageField(upload_to=b'uploads/gallery/%Y/%m/', verbose_name='Image')), + ('order', models.PositiveIntegerField()), + ('gallery', models.ForeignKey(verbose_name='Gallery', to='gallery.GalleryCell')), + ], + options={ + 'ordering': ['order'], + }, + bases=(models.Model,), + ), + ] diff --git a/gallery/migrations/0002_image_title.py b/gallery/migrations/0002_image_title.py new file mode 100644 index 0000000..32bd732 --- /dev/null +++ b/gallery/migrations/0002_image_title.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('gallery', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='image', + name='title', + field=models.CharField(max_length=50, verbose_name='Title', blank=True), + preserve_default=True, + ), + ] diff --git a/gallery/migrations/0003_gallerycell_title.py b/gallery/migrations/0003_gallerycell_title.py new file mode 100644 index 0000000..57cb09c --- /dev/null +++ b/gallery/migrations/0003_gallerycell_title.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('gallery', '0002_image_title'), + ] + + operations = [ + migrations.AddField( + model_name='gallerycell', + name='title', + field=models.CharField(max_length=50, null=True, verbose_name='Title', blank=True), + preserve_default=True, + ), + ] diff --git a/gallery/migrations/__init__.py b/gallery/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gallery/models.py b/gallery/models.py new file mode 100644 index 0000000..9d4a8d3 --- /dev/null +++ b/gallery/models.py @@ -0,0 +1,51 @@ +# combo - content management system +# Copyright (C) 2015 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django import template +from django.db import models +from django.forms import models as model_forms +from django.utils.translation import ugettext_lazy as _ + +from combo.data.models import CellBase +from combo.data.library import register_cell_class + +@register_cell_class +class GalleryCell(CellBase): + title = models.CharField(_('Title'), max_length=50, blank=True, null=True) + manager_form_template = 'combo/gallery_manager.html' + + class Meta: + verbose_name = _('Gallery') + + def render(self, context): + gallery_template = template.loader.get_template('combo/gallery.html') + return gallery_template.render(context) + + def get_additional_label(self): + if self.title: + return self.title + return '' + + +class Image(models.Model): + gallery = models.ForeignKey(GalleryCell, verbose_name=_('Gallery')) + image = models.ImageField(_('Image'), + upload_to='uploads/gallery/%Y/%m/') + order = models.PositiveIntegerField() + title = models.CharField(_('Title'), max_length=50, blank=True) + + class Meta: + ordering = ['order'] diff --git a/gallery/static/js/combo.gallery.js b/gallery/static/js/combo.gallery.js new file mode 100644 index 0000000..a91e714 --- /dev/null +++ b/gallery/static/js/combo.gallery.js @@ -0,0 +1,29 @@ +function gallery(element) { + var element_id = '#' + $(element).attr('id'); + $(element).sortable({ + items: '> li', + containment: 'parent', + placeholder: 'empty-image', + update: function(event, ui) { + var new_order = $(element).find('> li').map(function() { return $(this).data('object-id'); }).get().join(); + $.ajax({ + url: $(element).data('order-url'), + data: {'new-order': new_order}, + success: function(data, status) { + $(element).replaceWith($(data).find(element_id)); + gallery($(element_id)); + } + }); + } + }); + $('.image-delete').on('click', function() { + $.ajax({ + url: $(this).attr('href'), + success: function(data, status) { + $(element).replaceWith($(data).find(element_id)); + gallery($(element_id)); + } + }); + return false; + }); +}; diff --git a/gallery/templates/combo/gallery.html b/gallery/templates/combo/gallery.html new file mode 100644 index 0000000..627ab10 --- /dev/null +++ b/gallery/templates/combo/gallery.html @@ -0,0 +1,29 @@ +{% load thumbnail %} + + diff --git a/gallery/templates/combo/gallery_image_form.html b/gallery/templates/combo/gallery_image_form.html new file mode 100644 index 0000000..e38d101 --- /dev/null +++ b/gallery/templates/combo/gallery_image_form.html @@ -0,0 +1,26 @@ +{% extends "combo/manager_base.html" %} +{% load i18n %} + +{% block appbar %} +{% if object.id %} +

{% trans "Edit Image" %}

+{% else %} +

{% trans "New Image" %}

+{% endif %} +{% endblock %} + +{% block content %} + +
+ {% csrf_token %} + {{ form.as_p }} +
+ + {% if object.id %} + {% trans 'Cancel' %} + {% else %} + {% trans 'Cancel' %} + {% endif %} +
+
+{% endblock %} diff --git a/gallery/templates/combo/gallery_manager.html b/gallery/templates/combo/gallery_manager.html new file mode 100644 index 0000000..438a7e3 --- /dev/null +++ b/gallery/templates/combo/gallery_manager.html @@ -0,0 +1,34 @@ +{% extends 'combo/cell_form.html' %} +{% load static thumbnail i18n %} + +{% block cell-form %} +
+{% csrf_token %} + {{ form.as_p }} + + + + + + +{% endblock %} + + +{% block cell-buttons %} +{% trans 'New Image' %} +| +{{ block.super }} +
+{% endblock %} diff --git a/gallery/templates/combo/manager/gallery/gallerycell.html b/gallery/templates/combo/manager/gallery/gallerycell.html new file mode 100644 index 0000000..900eedd --- /dev/null +++ b/gallery/templates/combo/manager/gallery/gallerycell.html @@ -0,0 +1 @@ +HLLOW diff --git a/gallery/urls.py b/gallery/urls.py new file mode 100644 index 0000000..9737a15 --- /dev/null +++ b/gallery/urls.py @@ -0,0 +1,30 @@ +# combo - content management system +# Copyright (C) 2015 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.conf.urls import patterns, url + +from . import views + +manager_urlpatterns = patterns('', + url('^gallery/(?P\w+)/images/add/$', views.image_add, + name='combo-gallery-image-add'), + url('^gallery/(?P\w+)/order$', views.image_order, + name='combo-gallery-image-order'), + url('^gallery/(?P\w+)/images/(?P\w+)/edit$', views.image_edit, + name='combo-gallery-image-edit'), + url('^gallery/(?P\w+)/images/(?P\w+)/delete$', views.image_delete, + name='combo-gallery-image-delete'), +) diff --git a/gallery/views.py b/gallery/views.py new file mode 100644 index 0000000..76ca351 --- /dev/null +++ b/gallery/views.py @@ -0,0 +1,68 @@ +# combo - content management system +# Copyright (C) 2015 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.core.urlresolvers import reverse, reverse_lazy +from django.shortcuts import redirect +from django.views.generic import (TemplateView, RedirectView, DetailView, + CreateView, UpdateView, ListView, DeleteView, FormView) + +from .models import Image, GalleryCell +from .forms import ImageAddForm, ImageEditForm + +class ImageAddView(CreateView): + model = Image + template_name = 'combo/gallery_image_form.html' + form_class = ImageAddForm + + def form_valid(self, form): + form.instance.gallery_id = self.kwargs.get('gallery_pk') + other_images = form.instance.gallery.image_set.all() + if other_images: + form.instance.order = max([x.order for x in other_images]) + 1 + else: + form.instance.order = 0 + return super(ImageAddView, self).form_valid(form) + + def get_success_url(self): + return reverse('combo-manager-page-view', kwargs={'pk': self.object.gallery.page.id}) + +image_add = ImageAddView.as_view() + + +class ImageEditView(UpdateView): + model = Image + template_name = 'combo/gallery_image_form.html' + form_class = ImageEditForm + + def get_success_url(self): + return reverse('combo-manager-page-view', kwargs={'pk': self.object.gallery.page.id}) + +image_edit = ImageEditView.as_view() + + +def image_delete(request, gallery_pk, pk): + gallery = GalleryCell.objects.get(id=gallery_pk) + Image.objects.get(id=pk).delete() + return redirect(reverse('combo-manager-page-view', kwargs={'pk': gallery.page.id})) + + +def image_order(request, gallery_pk): + gallery = GalleryCell.objects.get(id=gallery_pk) + new_order = [int(x) for x in request.GET['new-order'].split(',')] + for image in gallery.image_set.all(): + image.order = new_order.index(image.id)+1 + image.save() + return redirect(reverse('combo-manager-page-view', kwargs={'pk': gallery.page.id})) diff --git a/setup.py b/setup.py index 232076e..e94e158 100644 --- a/setup.py +++ b/setup.py @@ -18,6 +18,8 @@ setup( packages=[ 'panikombo', 'panikombo.migrations', + 'gallery', + 'gallery.migrations', ], classifiers=[ 'Development Status :: 4 - Beta',