From: Marcin Koziej <marcin@lolownia.org> Date: Thu, 5 Dec 2013 13:24:01 +0000 (+0100) Subject: tags wired to pictures X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/1f9103b1e752a6c41d2304bf5e41a7d6ae0c45c8?ds=sidebyside tags wired to pictures --- diff --git a/apps/catalogue/migrations/0007_auto__add_field_collection_kind.py b/apps/catalogue/migrations/0007_auto__add_field_collection_kind.py new file mode 100644 index 000000000..1fef5e47b --- /dev/null +++ b/apps/catalogue/migrations/0007_auto__add_field_collection_kind.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Collection.kind' + db.add_column(u'catalogue_collection', 'kind', + self.gf('django.db.models.fields.CharField')(default='book', max_length=10, db_index=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Collection.kind' + db.delete_column(u'catalogue_collection', 'kind') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'catalogue.book': { + 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'}, + '_related_info': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'cover': ('catalogue.fields.EbookField', [], {'max_length': '100', 'null': 'True', 'format_name': "'cover'", 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'epub_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'epub'", 'blank': 'True'}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'fb2_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'fb2'", 'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'html_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'html'", 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}), + 'mobi_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'mobi'", 'blank': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}), + 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'pdf_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'pdf'", 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'txt_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'txt'", 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'xml_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'xml'", 'blank': 'True'}) + }, + 'catalogue.bookmedia': { + 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'}, + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}), + 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'", 'db_index': 'True'}), + 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}) + }, + 'catalogue.collection': { + 'Meta': {'ordering': "('title',)", 'object_name': 'Collection'}, + 'book_slugs': ('django.db.models.fields.TextField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'kind': ('django.db.models.fields.CharField', [], {'default': "'book'", 'max_length': '10', 'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}) + }, + 'catalogue.fragment': { + 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'}, + 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'short_text': ('django.db.models.fields.TextField', [], {}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'catalogue.tag': { + 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'}, + 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}) + }, + 'catalogue.tagrelation': { + 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "u'catalogue_tag_relation'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/apps/catalogue/migrations/0008_auto__add_field_tag_picture_count.py b/apps/catalogue/migrations/0008_auto__add_field_tag_picture_count.py new file mode 100644 index 000000000..f186ae1e0 --- /dev/null +++ b/apps/catalogue/migrations/0008_auto__add_field_tag_picture_count.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Tag.picture_count' + db.add_column(u'catalogue_tag', 'picture_count', + self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Tag.picture_count' + db.delete_column(u'catalogue_tag', 'picture_count') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'catalogue.book': { + 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'}, + '_related_info': ('jsonfield.fields.JSONField', [], {'null': 'True', 'blank': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'cover': ('catalogue.fields.EbookField', [], {'max_length': '100', 'null': 'True', 'format_name': "'cover'", 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'epub_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'epub'", 'blank': 'True'}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'fb2_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'fb2'", 'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'html_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'html'", 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}), + 'mobi_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'mobi'", 'blank': 'True'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}), + 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'pdf_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'pdf'", 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'txt_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'txt'", 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + 'xml_file': ('catalogue.fields.EbookField', [], {'default': "''", 'max_length': '100', 'format_name': "'xml'", 'blank': 'True'}) + }, + 'catalogue.bookmedia': { + 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'}, + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}), + 'extra_info': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}), + 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}), + 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'", 'db_index': 'True'}), + 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}) + }, + 'catalogue.collection': { + 'Meta': {'ordering': "('title',)", 'object_name': 'Collection'}, + 'book_slugs': ('django.db.models.fields.TextField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'kind': ('django.db.models.fields.CharField', [], {'default': "'book'", 'max_length': '10', 'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}) + }, + 'catalogue.fragment': { + 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'}, + 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}), + 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'short_text': ('django.db.models.fields.TextField', [], {}), + 'text': ('django.db.models.fields.TextField', [], {}) + }, + 'catalogue.tag': { + 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'}, + 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), + 'picture_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120'}), + 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}) + }, + 'catalogue.tagrelation': { + 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "u'catalogue_tag_relation'"}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['catalogue'] \ No newline at end of file diff --git a/apps/catalogue/models/collection.py b/apps/catalogue/models/collection.py index 8f67f88e0..acb01b6a3 100644 --- a/apps/catalogue/models/collection.py +++ b/apps/catalogue/models/collection.py @@ -15,6 +15,8 @@ class Collection(models.Model): models.SlugField(_('slug'), max_length=120, unique=True, db_index=True) book_slugs = models.TextField(_('book slugs')) + kind = models.CharField(_('kind'), max_length=10, blank=False, default='book', db_index=True, choices=((('book'), _('book')), (('picture'), ('picture')))) + class Meta: ordering = ('title',) verbose_name = _('collection') diff --git a/apps/catalogue/models/tag.py b/apps/catalogue/models/tag.py index a6f395cee..5b99b8f0b 100644 --- a/apps/catalogue/models/tag.py +++ b/apps/catalogue/models/tag.py @@ -37,6 +37,7 @@ class Tag(TagBase): user = models.ForeignKey(User, blank=True, null=True) book_count = models.IntegerField(_('book count'), blank=True, null=True) + picture_count = models.IntegerField(_('picture count'), blank=True, null=True) gazeta_link = models.CharField(blank=True, max_length=240) wiki_link = models.CharField(blank=True, max_length=240) @@ -53,6 +54,7 @@ class Tag(TagBase): 'gatunek': 'genre', 'motyw': 'theme', 'polka': 'set', + 'obiekt': 'thing', } categories_dict = dict((item[::-1] for item in categories_rev.iteritems())) @@ -109,6 +111,22 @@ class Tag(TagBase): objects = objects.exclude(pk__in=descendants_keys) return objects.count() + # I shouldn't break the get_count() api + # just to include pictures. + def get_picture_count(self): + from picture.models import Picture + + if self.category == 'book': + # never used + objects = Book.objects.none() + elif self.category == 'theme': + objects = Picture.tagged.with_all((self,)) + elif self.category == 'thing': + objects = Picture.tagged.with_all((self,)) + else: + objects = Picture.tagged.with_all((self,)).order_by() + return objects.count() + @staticmethod def get_tag_list(tags): if isinstance(tags, basestring): diff --git a/apps/catalogue/tasks.py b/apps/catalogue/tasks.py index d5e8529b1..cb6fd6432 100644 --- a/apps/catalogue/tasks.py +++ b/apps/catalogue/tasks.py @@ -13,9 +13,10 @@ from wolnelektury.utils import localtime_to_utc def touch_tag(tag): update_dict = { 'book_count': tag.get_count(), + 'picture_count': tag.get_picture_count(), 'changed_at': localtime_to_utc(datetime.now()), } - + print update_dict type(tag).objects.filter(pk=tag.pk).update(**update_dict) diff --git a/apps/catalogue/templates/catalogue/tag_list.html b/apps/catalogue/templates/catalogue/tag_list.html index a5ce71e37..87097b193 100644 --- a/apps/catalogue/templates/catalogue/tag_list.html +++ b/apps/catalogue/templates/catalogue/tag_list.html @@ -10,7 +10,7 @@ {% endfor %} {% else %} {% for tag in tags %} - <li><a href="{{ tag.get_absolute_url }}">{{ tag }} ({{ tag.book_count }})</a></li> + <li><a href="{{ tag.get_absolute_url }}">{{ tag }} ({{ tag.count }})</a></li> {% endfor %} {% endif %} </ul> diff --git a/apps/catalogue/templates/catalogue/tag_list_split.html b/apps/catalogue/templates/catalogue/tag_list_split.html new file mode 100644 index 000000000..b800d70d4 --- /dev/null +++ b/apps/catalogue/templates/catalogue/tag_list_split.html @@ -0,0 +1,10 @@ +{% load i18n %} +{% if books %} +<p class="mono">{% trans "Literatura" %} +{{books|safe}} +{% endif %} + +{% if pictures %} +<p class="mono">{% trans "Obrazy" %} +{{pictures|safe}} +{% endif %} diff --git a/apps/catalogue/views.py b/apps/catalogue/views.py index e9b1465dd..27d141fb5 100644 --- a/apps/catalogue/views.py +++ b/apps/catalogue/views.py @@ -29,6 +29,7 @@ from pdcounter import models as pdcounter_models from pdcounter import views as pdcounter_views from suggest.forms import PublishingSuggestForm from picture.models import Picture +from picture.views import picture_list_thumb staff_required = user_passes_test(lambda user: user.is_staff) permanent_cache = get_cache('permanent') @@ -38,20 +39,36 @@ permanent_cache = get_cache('permanent') def catalogue(request): cache_key='catalogue.catalogue' output = permanent_cache.get(cache_key) + if output is None: tags = models.Tag.objects.exclude( - category__in=('set', 'book')).exclude(book_count=0) + category__in=('set', 'book')).exclude(book_count=0, picture_count=0) tags = list(tags) for tag in tags: - tag.count = tag.book_count + tag.count = tag.book_count + tag.picture_count categories = split_tags(tags) fragment_tags = categories.get('theme', []) collections = models.Collection.objects.all() + render_tag_list = lambda x: render_to_string( 'catalogue/tag_list.html', tag_list(x)) - output = {'theme': render_tag_list(fragment_tags)} + has_pictures = lambda x: filter(lambda y: y.picture_count>0, x) + has_books = lambda x: filter(lambda y: y.book_count>0, x) + def render_split(tags): + with_books = has_books(tags) + with_pictures = has_pictures(tags) + ctx = {} + if with_books: + ctx['books'] = render_tag_list(with_books) + if with_pictures: + ctx['pictures'] = render_tag_list(with_pictures) + return render_to_string('catalogue/tag_list_split.html', ctx) + + output = {'theme': {}} + output['theme'] = render_split(fragment_tags) for category, tags in categories.items(): - output[category] = render_tag_list(tags) + output[category] = render_split(tags) + output['collections'] = render_to_string( 'catalogue/collection_list.html', collection_list(collections)) permanent_cache.set(cache_key, output) @@ -103,8 +120,16 @@ def daisy_list(request): def collection(request, slug): coll = get_object_or_404(models.Collection, slug=slug) - return book_list(request, get_filter=coll.get_query, - template_name='catalogue/collection.html', + if coll.kind == 'book': + view = book_list + tmpl = "catalogue/collection.html" + elif coll.kind == 'picture': + view = picture_list_thumb + tmpl = "picture/collection.html" + else: + raise ValueError('How do I show this kind of collection? %s' % coll.kind) + return view(request, get_filter=coll.get_query, + template_name=tmpl, cache_key='catalogue.collection:%s' % coll.slug, context={'collection': coll}) diff --git a/apps/picture/models.py b/apps/picture/models.py index cd91a3f8a..fa602e66c 100644 --- a/apps/picture/models.py +++ b/apps/picture/models.py @@ -40,7 +40,7 @@ class Picture(models.Model): xml_file = models.FileField('xml_file', upload_to="xml", storage=picture_storage) image_file = ImageField(_('image_file'), upload_to="images", storage=picture_storage) html_file = models.FileField('html_file', upload_to="html", storage=picture_storage) - areas = jsonfield.JSONField(_('picture areas'), default='{}', editable=False) + areas = jsonfield.JSONField(_('picture areas'), default={}, editable=False) objects = models.Manager() tagged = managers.ModelTaggedItemManager(catalogue.models.Tag) diff --git a/apps/picture/templates/picture/collection.html b/apps/picture/templates/picture/collection.html new file mode 100644 index 000000000..f794fbfeb --- /dev/null +++ b/apps/picture/templates/picture/collection.html @@ -0,0 +1,10 @@ +{% extends "picture/picture_list_thumb.html" %} +{% load i18n %} + +{% block titleextra %}{{ context.collection.title }}{% endblock %} + +{% block book_list_header %}{{ context.collection.title }}{% endblock %} + +{% block book_list_info %} +{{ context.collection.description|safe }} +{% endblock %} diff --git a/apps/picture/templates/picture/picture_info.html b/apps/picture/templates/picture/picture_info.html new file mode 100644 index 000000000..c2d2c9aaa --- /dev/null +++ b/apps/picture/templates/picture/picture_info.html @@ -0,0 +1,17 @@ + +<div id="picture-themes" class="dropdown-body"> + <ul> +{% for slug, theme in themes.items %} +<li><a href="#theme-{{slug}}" data-coords="{{theme.coords}}">{{theme.theme}}</a></li> +{% endfor %} + </ul> +</div> + +<div id="picture-objects" class="dropdown-body"> + <ul> +{% for slug, thing in things.items %} +<li><a href="#object-{{slug}}" data-coords="{{thing.coords}}">{{thing.object}}</a></li> +{% endfor %} + </ul> +</div> + diff --git a/apps/picture/templates/picture/picture_list_thumb.html b/apps/picture/templates/picture/picture_list_thumb.html index eeaab78aa..647afb7d5 100644 --- a/apps/picture/templates/picture/picture_list_thumb.html +++ b/apps/picture/templates/picture/picture_list_thumb.html @@ -12,11 +12,14 @@ {% block body %} <h1>{% block book_list_header %}{% trans "Listing of all pictures" %}{% endblock %}</h1> + <div class="left-column"><div class="normal-text"> + {% block book_list_info %}{% endblock %} + </div></div> <div class='clearboth'></div> <div id="books-list"> <ol class="work-list">{% spaceless %} -{% for picture in picture_list %} +{% for picture in book_list %} <li class="Book-item"> {% picture_short picture %} </li> diff --git a/apps/picture/templates/picture/picture_viewer.html b/apps/picture/templates/picture/picture_viewer.html index df0160cd1..fbf361030 100644 --- a/apps/picture/templates/picture/picture_viewer.html +++ b/apps/picture/templates/picture/picture_viewer.html @@ -52,5 +52,6 @@ </div> </div> {{ piwik_tag|safe }} + <div id="spinner"></div> </body> </html diff --git a/apps/picture/views.py b/apps/picture/views.py index 27ddaf18f..65e5fa4b5 100644 --- a/apps/picture/views.py +++ b/apps/picture/views.py @@ -6,12 +6,13 @@ from django.template import RequestContext from django.core.paginator import Paginator from picture.models import Picture - -def picture_list(request, filter=None, template_name='catalogue/picture_list.html'): +# was picture/picture_list.html list (without thumbs) +def picture_list(request, filter=None, get_filter=None, template_name='catalogue/picture_list.html', cache_key=None, context=None): """ generates a listing of all books, optionally filtered with a test function """ - pictures_by_author, orphans = Picture.picture_list( - filter={'image_file__isnull':False}) + if get_filter: + filt = get_filter() + pictures_by_author, orphans = Picture.picture_list(filt) books_nav = SortedDict() for tag in pictures_by_author: if pictures_by_author[tag]: @@ -21,8 +22,12 @@ def picture_list(request, filter=None, template_name='catalogue/picture_list.htm context_instance=RequestContext(request)) -def picture_list_thumb(request, filter=None, template_name='picture/picture_list_thumb.html'): - picture_list = Picture.objects.filter(image_file__isnull=False) +def picture_list_thumb(request, filter=None, get_filter=None, template_name='picture/picture_list_thumb.html', cache_key=None, context=None): + book_list = Picture.objects.all() + if filter: + book_list = book_list.filter(filter) + if get_filter: + book_list = book_list.filter(get_filter()) return render_to_response(template_name, locals(), context_instance=RequestContext(request)) diff --git a/apps/wolnelektury_core/static/js/picture.js b/apps/wolnelektury_core/static/js/picture.js index bcbdbc177..7cbb67547 100644 --- a/apps/wolnelektury_core/static/js/picture.js +++ b/apps/wolnelektury_core/static/js/picture.js @@ -1,212 +1,234 @@ (function($) { - $.widget('wl.pictureviewer', { - - options: { - steps: 6, // steps of zoom - max: -1, // max zoom in percent - plus_button: undefined, - minus_button: undefined, - height: 500, // height to scale to initially - }, - - - _create: function() { - var self = this; - /* Calibrate */ - self._zoom = 0; - - // the initial thumbnailed picture - - - var img = self.element.find('img.initial').get(0); - - self.initial_size = [ - img.naturalWidth, - img.naturalHeight - ]; - - self.element.width(self.initial_size[0]); - self.element.height(self.initial_size[1]); - - self.initial_position = self.element.offset(); - - var original = self.element.find('img.original').get(0); - self._original = false; - - if (self.options.max <= 0) { - self.options.max = original.naturalWidth - * 100 / self.initial_size[0]; - } - - self.element.css({ - 'margin': 0, - }); - - self.element.offset(self.initial_position); - self.element.draggable({containment:"parent"}); - - if (self.options.plus_button) - self.options.plus_button.click( - function(ev) { self.zoom(1); }); - if (self.options.minus_button) - self.options.minus_button.click( - function(ev) { self.zoom(-1); }); - - self.options.areas_links.hover(function() { - $this = $(this); - var coords = $this.data("coords"); - this._picture_mark = self.createMark({ - label: $this.text(), - coords: coords, - }); - }, function() { - $(this._picture_mark).remove(); - this._picture_mark = undefined; - }); - return self; - }, - - natural_size: function() { - var img = this.element.find('img').get(0); - return [ img.naturalWidth, img.naturalHeight ] - }, - - currentZoom: function() { return this._zoom; }, - - initOriginal: function() { - if (!this._original) { - this.element.find("img.initial").remove(); - this.element.find("img.loading").removeClass("loading"); - this._original = true; - } - - }, - - zoom: function(steps) { - this.initOriginal(); - var t = this._zoom + steps; - return this.zoomTo(t); - }, - - zoomForStep: function(step) { - // 0 => initial - // max_step-1 => max % - return 100 + (this.options.max - 100) / this.options.steps * step - }, - - zoomTo: function(level) { - if (level < 0 || level > this.options.steps) - return; - var ratio = this.zoomForStep(level) / 100; - var new_width = ratio * this.initial_size[0]; - var new_height = ratio * this.initial_size[1]; - var target = { - 'width': new_width, - 'left': Math.max(0, - this.initial_position.left - - (new_width - this.initial_size[0])/2), - 'top': Math.max(0, - this.initial_position.top - - (new_height - this.initial_size[1])/2), - }; - - this._zoom = level; - this.element.animate(target, 200); // default duration=400 - }, - - allowedPosition: function(off) { - var x = undefined, fix_x = undefined; - var y = undefined, fix_y = undefined; - var w = this.element.width(); - var h = this.element.height(); - var cw = $(window).width(); - var ch = $(window).height(); - var off = off || this.element.offset(); - - if (w <= cw) { - var x = off.left; - if (x < 0) - fix_x = 0; - if (x + w > cw) - fix_x = cw - w; - } else { - if (x > 0) - fix_x = 0; - if (x + w < cw) - fix_x = cw - w; - } - - if (h <= ch) { - var y = off.top; - if (y < 0) - fix_y = 0; - if (y + h > ch) - fix_y = ch - h; - } else { - if (y > 0) - fix_y = 0; - if (y + h < ch) - fix_y = ch - h; - } - if (fix_x !== undefined || fix_y !== undefined) - return { top: fix_y, left: fix_x }; - return undefined; - - }, - - // mark - // { - // label: "...", - // coords: [x, y, w, h] - // } - createMark: function(mark) { - var $mark = $('<div class="mark"><div class="label">' + - mark.label + '</div></div>'); - var ratio = this.zoomForStep(this.currentZoom()) * - this.initial_size[0] / (100 * this.natural_size()[0]); - var scale = function (v) { - return v * ratio; - } - if (mark.coords[1][0] < 0 || mark.coords[1][1] < 0) { // whole - var s = self.natural_size(); - if (mark.coords[1][0] < 0) mark.coords[1][0] = s[0]; - if (mark.coords[1][1] < 0) mark.coords[1][1] = s[1]; - } - - var coords = [[scale(mark.coords[0][0]), scale(mark.coords[0][1])], - [scale(mark.coords[1][0]), scale(mark.coords[1][1])]]; - this.element.append($mark); - $mark.width(coords[1][0] - coords[0][0]); - $mark.height(coords[1][1] - coords[0][1]); - $mark.css({left: coords[0][0], top: coords[0][1]}); - return $mark.get(0); - }, - }); + $.widget('wl.pictureviewer', { + + options: { + steps: 6, // steps of zoom + max: -1, // max zoom in percent + plus_button: undefined, + minus_button: undefined, + height: 500, // height to scale to initially + }, + + + _create: function() { + var self = this; + /* Calibrate */ + self._zoom = 0; + + // the initial thumbnailed picture + + + var img = self.element.find('img.initial').get(0); + + self.initial_size = [ + img.naturalWidth, + img.naturalHeight + ]; + + self.element.width(self.initial_size[0]); + self.element.height(self.initial_size[1]); + + self.initial_position = self.element.offset(); + + var original = self.element.find('img.original').get(0); + self._original = false; + self.original_loeaded = undefined; // callback + self._original_loaded = false; + + self.spinner = $("#spinner").progressSpin(); + + $(original).load(function() { + self._original_loaded = true; + self.spinner.stop(); + var cb = self.original_loaded; + self.original_loaded = undefined; + if (cb) + cb() + }); + + if (self.options.max <= 0) { + self.options.max = original.naturalWidth + * 100 / self.initial_size[0]; + } + + self.element.css({ + 'margin': 0, + }); + + self.element.offset(self.initial_position); + self.element.draggable({containment:"parent"}); + + if (self.options.plus_button) + self.options.plus_button.click( + function(ev) { self.zoom(1); }); + if (self.options.minus_button) + self.options.minus_button.click( + function(ev) { self.zoom(-1); }); + + self.options.areas_links.hover(function() { + $this = $(this); + var coords = $this.data("coords"); + this._picture_mark = self.createMark({ + label: $this.text(), + coords: coords, + }); + }, function() { + $(this._picture_mark).remove(); + this._picture_mark = undefined; + }); + return self; + }, + + natural_size: function() { + var img = this.element.find('img').get(0); + return [ img.naturalWidth, img.naturalHeight ] + }, + + currentZoom: function() { return this._zoom; }, + + initOriginal: function() { + var self = this; + function subst_original() { + self.element.find("img.initial").remove(); + self.element.find("img.loading").removeClass("loading"); + self._original = true; + } + if (!this._original) { + if (this._original_loaded) { + return subst_original(); + } else { + self.original_loaded = subst_original; + self.spinner.start(); + } + } + + }, + + zoom: function(steps) { + this.initOriginal(); + var t = this._zoom + steps; + return this.zoomTo(t); + }, + + zoomForStep: function(step) { + // 0 => initial + // max_step-1 => max % + return 100 + (this.options.max - 100) / this.options.steps * step + }, + + zoomTo: function(level) { + if (level < 0 || level > this.options.steps) + return; + var ratio = this.zoomForStep(level) / 100; + var new_width = ratio * this.initial_size[0]; + var new_height = ratio * this.initial_size[1]; + var target = { + 'width': new_width, + 'left': Math.max(0, + this.initial_position.left + - (new_width - this.initial_size[0])/2), + 'top': Math.max(0, + this.initial_position.top + - (new_height - this.initial_size[1])/2), + }; + + this._zoom = level; + this.element.animate(target, 200); // default duration=400 + }, + + allowedPosition: function(off) { + var x = undefined, fix_x = undefined; + var y = undefined, fix_y = undefined; + var w = this.element.width(); + var h = this.element.height(); + var cw = $(window).width(); + var ch = $(window).height(); + var off = off || this.element.offset(); + + if (w <= cw) { + var x = off.left; + if (x < 0) + fix_x = 0; + if (x + w > cw) + fix_x = cw - w; + } else { + if (x > 0) + fix_x = 0; + if (x + w < cw) + fix_x = cw - w; + } + + if (h <= ch) { + var y = off.top; + if (y < 0) + fix_y = 0; + if (y + h > ch) + fix_y = ch - h; + } else { + if (y > 0) + fix_y = 0; + if (y + h < ch) + fix_y = ch - h; + } + if (fix_x !== undefined || fix_y !== undefined) + return { top: fix_y, left: fix_x }; + return undefined; + + }, + + // mark + // { + // label: "...", + // coords: [x, y, w, h] + // } + createMark: function(mark) { + var $mark = $('<div class="mark"><div class="label">' + + mark.label + '</div></div>'); + var ratio = this.zoomForStep(this.currentZoom()) * + this.initial_size[0] / (100 * this.natural_size()[0]); + var scale = function (v) { + return v * ratio; + } + if (mark.coords[1][0] < 0 || mark.coords[1][1] < 0) { // whole + var s = self.natural_size(); + if (mark.coords[1][0] < 0) mark.coords[1][0] = s[0]; + if (mark.coords[1][1] < 0) mark.coords[1][1] = s[1]; + } + + var coords = [[scale(mark.coords[0][0]), scale(mark.coords[0][1])], + [scale(mark.coords[1][0]), scale(mark.coords[1][1])]]; + this.element.append($mark); + $mark.width(coords[1][0] - coords[0][0]); + $mark.height(coords[1][1] - coords[0][1]); + $mark.css({left: coords[0][0], top: coords[0][1]}); + return $mark.get(0); + }, + }); }(jQuery)); $(document).ready(function(){ - $(".picture-wrap").pictureviewer({ - plus_button: $(".toolbar .button.plus"), - minus_button: $(".toolbar .button.minus"), - areas_links: $("#picture-objects a, #picture-themes a"), - }); - - $.highlightFade.defaults.speed = 3000; - - $('.toolbar a.dropdown').each(function() { - $t = $(this); - $($t.attr('href')).hide().insertAfter(this); - }); - - $('.toolbar a.dropdown').toggle(function() { - $(this).addClass('selected'); - $($(this).attr('href')).slideDown('fast'); - }, function() { - $(this).removeClass('selected'); - $($(this).attr('href')).slideUp('fast'); - }); + $(".picture-wrap").pictureviewer({ + plus_button: $(".toolbar .button.plus"), + minus_button: $(".toolbar .button.minus"), + areas_links: $("#picture-objects a, #picture-themes a"), + }); + + $.highlightFade.defaults.speed = 3000; + + $('.toolbar a.dropdown').each(function() { + $t = $(this); + $($t.attr('href')).hide().insertAfter(this); + }); + + $('.toolbar a.dropdown').toggle(function() { + $(this).addClass('selected'); + $($(this).attr('href')).slideDown('fast'); + }, function() { + $(this).removeClass('selected'); + $($(this).attr('href')).slideUp('fast'); + }); }); diff --git a/apps/wolnelektury_core/static/js/progressSpin.min.js b/apps/wolnelektury_core/static/js/progressSpin.min.js new file mode 100644 index 000000000..d87ce8ca6 --- /dev/null +++ b/apps/wolnelektury_core/static/js/progressSpin.min.js @@ -0,0 +1 @@ +(function(e){e.fn.progressSpin=function(t){function f(e,t){var i=1-t;var s=Raphael.getRGB(n.activeColor);var o=Raphael.getRGB(n.fillColor);var u=Math.floor(s.r*t+o.r*i);var a=Math.floor(s.g*t+o.g*i);var f=Math.floor(s.b*t+o.b*i);var l=Raphael.rgb(u,a,f);r[e].attr("fill",l)}function l(e){e=e%12;if(e<0){e+=12}return e}if(this.getOptions){return this}var n=e.extend({},e.fn.progressSpin.defaults,t);var r=[];var i=false;var s=null;var o=0;var u=null;var a=this;this.getOptions=function(){return n};this.getVisible=function(){return i};this.getAnimating=function(){return s!=null};this.getCurrentStep=function(){return o};this.setCurrentStep=function(e){if(this.getAnimating()){this.stop(false);o=l(e);this.start()}else{o=l(e)}};this.start=function(){if(this.getAnimating()){}else{this.show();f(o,1);var e=1/(n.tailCount+1);var t=0;var r=n.tailCount;s=setInterval(function(){if(t<r){t++}o=l(o+1);var n=1;for(var i=0;i<=t+1;i++){var s=l(o-i);f(s,1-i*e)}},Math.floor(n.cycleTime/12))}};this.stop=function(e){if(e==null){e=true}if(s){clearInterval(s);s=null}var t=n.fillColor;r.forEach(function(e){e.attr("fill",t)});if(e){this.hide()}};this.show=function(){if(r.length==0){this.render()}else{if(i){}else{r.forEach(function(e){e.show()});i=true}}};this.hide=function(){if(this.getAnimating()){this.stop(false)}if(i){r.forEach(function(e){e.hide()})}i=false};this.render=function(){if(this.getAnimating()){this.stop(false)}if(u){r=[];u.clear();u.setSize(this.width(),this.height())}else{u=Raphael(this.get(0),this.width(),this.height())}var e=Math.floor(this.width()/2);var t=Math.floor(this.height()/2);var s=e;if(t<s){s=t}var o=e-Math.floor(n.stepWidth/2);var a=t-s;var f=s-Math.floor(s*n.knockOutRatio);var l=u.rect(o,a,n.stepWidth,f,n.cornerRadius);l.attr("fill",n.fillColor);l.attr("stroke-width",0);r[0]=l;var c=30;for(var h=1;h<=11;h++){var p=l.clone();p.transform("r"+c+","+e+","+t);r[h]=p;c+=30}i=true};return this};e.fn.progressSpin.defaults={activeColor:"#000000",fillColor:"#aaaaaa",cycleTime:1e3,tailCount:6,stepWidth:5,cornerRadius:2,knockOutRatio:.5}})(jQuery) \ No newline at end of file diff --git a/lib/librarian b/lib/librarian index 6ab2b1634..5b1dcc7d2 160000 --- a/lib/librarian +++ b/lib/librarian @@ -1 +1 @@ -Subproject commit 6ab2b1634713a84c9c73905893b25abaa643c08a +Subproject commit 5b1dcc7d247996752fa566c7150a45037b068565 diff --git a/wolnelektury/settings/static.py b/wolnelektury/settings/static.py index 7dd1a82e3..b78340dc8 100644 --- a/wolnelektury/settings/static.py +++ b/wolnelektury/settings/static.py @@ -111,6 +111,7 @@ PIPELINE_JS = { 'js/book.js', 'js/picture.js', 'player/openplayer.js', + 'js/progressSpin.min.js', ], 'output_filename': 'js/book.min.js', },