Prepared for SP 4-6.
authorRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Fri, 31 Jan 2014 11:57:43 +0000 (12:57 +0100)
committerRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Fri, 31 Jan 2014 11:58:42 +0000 (12:58 +0100)
- Main and lesson list pages overhaul.
- Lessons now inform about internet requirements and publisher.
- PDF support for <obraz> (by sorl.thumnail with ImageMagick)
- Add summary and picture for Sections, description for Lesson.
- Level slug and meta dc:audience value can be different.
- Per-level lesson packages instead of global ones.
- Lesson packages are now rebuilt after import.
- Add option for allowing incomplete sections on import.
- Django 1.6, `django-piwik` replaces `piwik`.

57 files changed:
catalogue/management/commands/importlessons.py
catalogue/management/commands/repackage.py
catalogue/migrations/0014_auto__add_field_section_summary.py [new file with mode: 0644]
catalogue/migrations/0015_auto__add_field_lesson_description.py [new file with mode: 0644]
catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py [new file with mode: 0644]
catalogue/models.py
catalogue/publish.py
catalogue/static/catalogue/css/carousel.css
catalogue/static/catalogue/css/carousel.scss
catalogue/static/catalogue/css/layout.css
catalogue/static/catalogue/css/layout.scss
catalogue/static/catalogue/css/lesson.css
catalogue/static/catalogue/css/lesson.scss
catalogue/static/catalogue/css/section_list.css
catalogue/static/catalogue/css/section_list.scss
catalogue/static/catalogue/js/carousel.js
catalogue/static/catalogue/js/lesson-list.js [new file with mode: 0644]
catalogue/static/catalogue/js/lesson.js
catalogue/templates/catalogue/lesson/appendix/lesson_detail.html
catalogue/templates/catalogue/lesson/box-icons.html [new file with mode: 0644]
catalogue/templates/catalogue/lesson/course/lesson_detail.html
catalogue/templates/catalogue/lesson/lesson_detail.html
catalogue/templates/catalogue/lesson/project/lesson_detail.html
catalogue/templates/catalogue/lesson/synthetic/lesson_detail.html
catalogue/templates/catalogue/lesson_list.html [new file with mode: 0755]
catalogue/templates/catalogue/section_list.html [deleted file]
catalogue/templates/catalogue/snippets/carousel.html
catalogue/templates/catalogue/snippets/lesson_nav.html
catalogue/templates/catalogue/snippets/lesson_or_stub.html [new file with mode: 0644]
catalogue/templates/catalogue/snippets/level_box.html [new file with mode: 0755]
catalogue/templates/catalogue/snippets/levels_main.html [new file with mode: 0644]
catalogue/templates/catalogue/snippets/section_box.html [deleted file]
catalogue/templates/catalogue/snippets/section_buttons.html [deleted file]
catalogue/templatetags/catalogue_tags.py
catalogue/urls.py
catalogue/views.py
contact/forms.py
curriculum/migrations/0010_auto__add_field_level_meta_name.py [new file with mode: 0644]
curriculum/migrations/0011_meta_name.py [new file with mode: 0644]
curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py [new file with mode: 0644]
curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py [new file with mode: 0644]
curriculum/models.py
curriculum/templates/curriculum/snippets/course_boxes_toc.html
curriculum/templatetags/curriculum_tags.py
edumed/settings.d/30-apps.py
edumed/settings.d/40-middleware.py
edumed/settings.d/50-contrib.py
edumed/settings.d/50-static.py
edumed/settings.d/60-custom.py
edumed/static/css/main.css
edumed/static/css/main.scss
edumed/static/img/icons/internet_black.png [new file with mode: 0644]
edumed/static/img/icons/nointernet_black.png [new file with mode: 0644]
edumed/templates/base_super.html
edumed/templates/home.html
edumed/views.py
requirements.txt

index 4e7a38c..83bf68b 100755 (executable)
@@ -23,15 +23,17 @@ class Command(BaseCommand):
             help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
         make_option('-a', '--attachments', dest='attachments', metavar="PATH", default='materialy',
             help='Attachments dir path.'),
+        make_option('--ignore-incomplete', action='store_true', dest='ignore_incomplete', default=False,
+            help='Attachments dir path.'),
     )
     help = 'Imports lessons from the specified directories.'
     args = 'directory [directory ...]'
 
-    def import_book(self, file_path, options, attachments):
+    def import_book(self, file_path, options, attachments, ignore_incomplete=False):
         verbose = options.get('verbose')
         iofile = IOFile.from_filename(os.path.join(self.curdir, file_path))
         iofile.attachments = attachments
-        lesson = Lesson.publish(iofile)
+        return Lesson.publish(iofile, ignore_incomplete)
 
     @staticmethod
     def all_attachments(path):
@@ -52,8 +54,9 @@ class Command(BaseCommand):
 
 
     def handle(self, *directories, **options):
-        from django.db import transaction
+        from django.db import connection, transaction
 
+        levels = set()
         self.style = color_style()
         
         verbose = options.get('verbose')
@@ -61,9 +64,14 @@ class Command(BaseCommand):
 
 
         # Start transaction management.
-        transaction.commit_unless_managed()
-        transaction.enter_transaction_management()
-        transaction.managed(True)
+        # SQLite will choke on generating thumbnails 
+        use_transaction = not connection.features.autocommits_when_autocommit_is_off
+        if use_transaction:
+            transaction.commit_unless_managed()
+            transaction.enter_transaction_management()
+            transaction.managed(True)
+        else:
+            print 'WARNING: Not using transaction management.'
 
         files_imported = 0
         files_skipped = 0
@@ -79,6 +87,7 @@ class Command(BaseCommand):
                 # files queue
                 files = sorted(os.listdir(abs_dir))
                 postponed = {}
+                ignore_incomplete = set()
                 while files:
                     file_name = files.pop(0)
                     file_path = os.path.join(abs_dir, file_name)
@@ -96,9 +105,8 @@ class Command(BaseCommand):
 
                     # Import book files
                     try:
-                        self.import_book(file_path, options, attachments)
-                        files_imported += 1
-                        transaction.commit()
+                        lesson = self.import_book(file_path, options, attachments,
+                                    ignore_incomplete=file_name in ignore_incomplete)
                     except Section.IncompleteError, e:
                         if file_name not in postponed or postponed[file_name] < files_imported:
                             # Push it back into the queue, maybe the missing lessons will show up.
@@ -106,6 +114,10 @@ class Command(BaseCommand):
                                 print self.style.NOTICE('Waiting for missing lessons.')
                             files.append(file_name)
                             postponed[file_name] = files_imported
+                        elif options['ignore_incomplete'] and file_name not in ignore_incomplete:
+                            files.append(file_name)
+                            ignore_incomplete.add(file_name)
+                            postponed[file_name] = files_imported
                         else:
                             # We're in a loop, nothing's being imported - some lesson is really missing.
                             raise e
@@ -113,6 +125,22 @@ class Command(BaseCommand):
                         import traceback
                         traceback.print_exc()
                         files_skipped += 1
+                    else:
+                        files_imported += 1
+                        if use_transaction:
+                            transaction.commit()
+                        if hasattr(lesson, 'level'):
+                            levels.add(lesson.level)
+                    finally:
+                        if verbose > 0:
+                            print
+
+
+        if levels:
+            print "Rebuilding level packages:"
+            for level in levels:
+                print level.name
+                level.build_packages()
 
         # Print results
         print
@@ -120,5 +148,6 @@ class Command(BaseCommand):
             files_imported, files_skipped, files_imported + files_skipped)
         print
 
-        transaction.commit()
-        transaction.leave_transaction_management()
+        if use_transaction:
+            transaction.commit()
+            transaction.leave_transaction_management()
index 3946e82..f3ae5e8 100755 (executable)
@@ -2,61 +2,15 @@
 # This file is part of EduMed, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
-import os
 from optparse import make_option
-from django.conf import settings
 from django.core.management.base import BaseCommand
-from catalogue.models import Section
-import zipfile
 
 
 class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
-    )
     help = 'Rebuilds downloadable packages.'
 
-    def build_package(self, zippath, student, verbose):
-        with open(zippath, 'w') as outf:
-            zipf = zipfile.ZipFile(outf, 'w', zipfile.ZIP_STORED)
-            
-            for si, section in enumerate(Section.objects.all()):
-                li = 1
-                li_adv = 1
-                for lesson in section.lesson_set.all():
-                    advanced = lesson.level.slug == "liceum"
-                    section_dir = "%d_%s%s" % (
-                        si + 1, section.slug,
-                        " (zaawansowane)" if advanced else "")
-                    if lesson.type == 'course':
-                        if advanced:
-                            ind = li_adv
-                            li_adv += 1
-                        else:
-                            ind = li
-                            li += 1
-                        prefix = "%s/%02d_%s/" % (
-                                section_dir, ind, lesson.slug,
-                            )
-                    elif lesson.type == 'synthetic':
-                        prefix = "%s/%s (synteza)/" % (
-                                section_dir, lesson.slug)
-                    elif lesson.type == 'project':
-                        prefix = "%s/%s (projekt)/" % (
-                                section_dir, lesson.slug)
-                    else:
-                        prefix = "%s/%s/" % (
-                                section_dir, lesson.slug)
-                    lesson.add_to_zip(zipf, student, prefix)
-            zipf.close()
-
     def handle(self, **options):
-        verbose = options.get('verbose')
+        from curriculum.models import Level
 
-        self.build_package(
-            os.path.join(settings.MEDIA_ROOT, settings.CATALOGUE_PACKAGE), 
-            False, verbose)
-        self.build_package(
-            os.path.join(settings.MEDIA_ROOT, settings.CATALOGUE_PACKAGE_STUDENT),
-            True, verbose)
+        for level in Level.objects.all():
+            level.build_packages()
diff --git a/catalogue/migrations/0014_auto__add_field_section_summary.py b/catalogue/migrations/0014_auto__add_field_section_summary.py
new file mode 100644 (file)
index 0000000..7805ec7
--- /dev/null
@@ -0,0 +1,94 @@
+# -*- 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 'Section.summary'
+        db.add_column(u'catalogue_section', 'summary',
+                      self.gf('django.db.models.fields.TextField')(null=True, blank=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Section.summary'
+        db.delete_column(u'catalogue_section', 'summary')
+
+
+    models = {
+        u'catalogue.attachment': {
+            'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'},
+            'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}),
+            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'catalogue.lesson': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'},
+            'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}),
+            'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.lessonstub': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'})
+        },
+        u'catalogue.part': {
+            'Meta': {'object_name': 'Part'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        }
+    }
+
+    complete_apps = ['catalogue']
\ No newline at end of file
diff --git a/catalogue/migrations/0015_auto__add_field_lesson_description.py b/catalogue/migrations/0015_auto__add_field_lesson_description.py
new file mode 100644 (file)
index 0000000..6d7dd5d
--- /dev/null
@@ -0,0 +1,95 @@
+# -*- 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 'Lesson.description'
+        db.add_column(u'catalogue_lesson', 'description',
+                      self.gf('django.db.models.fields.TextField')(null=True, blank=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Lesson.description'
+        db.delete_column(u'catalogue_lesson', 'description')
+
+
+    models = {
+        u'catalogue.attachment': {
+            'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'},
+            'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}),
+            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'catalogue.lesson': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'},
+            'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}),
+            'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.lessonstub': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'})
+        },
+        u'catalogue.part': {
+            'Meta': {'object_name': 'Part'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        }
+    }
+
+    complete_apps = ['catalogue']
\ No newline at end of file
diff --git a/catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py b/catalogue/migrations/0016_auto__add_field_section_pic__add_field_section_pic_attribution__add_fi.py
new file mode 100644 (file)
index 0000000..6be3fcf
--- /dev/null
@@ -0,0 +1,114 @@
+# -*- 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 'Section.pic'
+        db.add_column(u'catalogue_section', 'pic',
+                      self.gf('django.db.models.fields.files.ImageField')(max_length=100, null=True, blank=True),
+                      keep_default=False)
+
+        # Adding field 'Section.pic_attribution'
+        db.add_column(u'catalogue_section', 'pic_attribution',
+                      self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True),
+                      keep_default=False)
+
+        # Adding field 'Section.pic_src'
+        db.add_column(u'catalogue_section', 'pic_src',
+                      self.gf('django.db.models.fields.URLField')(max_length=200, null=True, blank=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Section.pic'
+        db.delete_column(u'catalogue_section', 'pic')
+
+        # Deleting field 'Section.pic_attribution'
+        db.delete_column(u'catalogue_section', 'pic_attribution')
+
+        # Deleting field 'Section.pic_src'
+        db.delete_column(u'catalogue_section', 'pic_src')
+
+
+    models = {
+        u'catalogue.attachment': {
+            'Meta': {'ordering': "['slug', 'ext']", 'unique_together': "(['lesson', 'slug', 'ext'],)", 'object_name': 'Attachment'},
+            'ext': ('django.db.models.fields.CharField', [], {'max_length': '15'}),
+            'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'catalogue.lesson': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'Lesson'},
+            'curriculum_courses': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['curriculum.CurriculumCourse']", 'symmetrical': 'False', 'blank': 'True'}),
+            'dc': ('jsonfield.fields.JSONField', [], {'default': "'{}'"}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.lessonstub': {
+            'Meta': {'ordering': "['section', 'level', 'order']", 'object_name': 'LessonStub'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"}),
+            'order': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Section']", 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'})
+        },
+        u'catalogue.part': {
+            'Meta': {'object_name': 'Part'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'lesson': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['catalogue.Lesson']"}),
+            'pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'student_pdf': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+        },
+        u'catalogue.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'pic': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'pic_attribution': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'pic_src': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '255'}),
+            'summary': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        }
+    }
+
+    complete_apps = ['catalogue']
\ No newline at end of file
index 239f60c..4af4810 100644 (file)
@@ -1,8 +1,11 @@
+# -*- coding: utf-8
 from django.core.files import File
 from django.core.urlresolvers import reverse
 from django.db import models
 from jsonfield import JSONField
 from curriculum.models import Level, Curriculum, CurriculumCourse
+import logging
+
 
 
 class Section(models.Model):
@@ -14,6 +17,12 @@ class Section(models.Model):
     image = models.ImageField(upload_to="catalogue/section/image",
         null=True, blank=True)
 
+    pic = models.ImageField(upload_to="catalogue/section/pic", null=True, blank=True)
+    pic_attribution = models.CharField(max_length=255, null=True, blank=True)
+    pic_src = models.URLField(null=True, blank=True)
+    
+    summary = models.TextField(blank=True, null=True)
+
     class Meta:
         ordering = ['order']
 
@@ -24,20 +33,22 @@ class Section(models.Model):
         return self.title
 
     def get_absolute_url(self):
-        return "%s#%s" % (reverse("catalogue_lessons"), self.slug)
+        return "%s#gimnazjum_%s" % (reverse("catalogue_lessons"), self.slug)
 
     @classmethod
-    def publish(cls, infile):
+    def publish(cls, infile, ignore_incomplete=False):
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
         wldoc = WLDocument.from_string(xml)
 
-        try:
-            lessons = [Lesson.objects.get(slug=part.slug)
-                        for part in wldoc.book_info.parts]
-        except Lesson.DoesNotExist, e:
-            raise cls.IncompleteError(part.slug)
+        lessons = []
+        for part in wldoc.book_info.parts:
+            try:
+                lessons.append(Lesson.objects.get(slug=part.slug))
+            except Lesson.DoesNotExist, e:
+                if not ignore_incomplete:
+                    raise cls.IncompleteError(part.slug)
 
         slug = wldoc.book_info.url.slug
         try:
@@ -74,6 +85,7 @@ class Lesson(models.Model):
     order = models.IntegerField(db_index=True)
     dc = JSONField(default='{}')
     curriculum_courses = models.ManyToManyField(CurriculumCourse, blank=True)
+    description = models.TextField(null=True, blank=True)
 
     xml_file = models.FileField(upload_to="catalogue/lesson/xml",
         null=True, blank=True, max_length=255)
@@ -99,7 +111,7 @@ class Lesson(models.Model):
         return ('catalogue_lesson', [self.slug])
 
     @classmethod
-    def publish(cls, infile):
+    def publish(cls, infile, ignore_incomplete=False):
         from librarian.parser import WLDocument
         from django.core.files.base import ContentFile
         xml = infile.get_string()
@@ -107,8 +119,8 @@ class Lesson(models.Model):
 
         # Check if not section metadata block.
         if wldoc.book_info.parts:
-            return Section.publish(infile)
-        
+            return Section.publish(infile, ignore_incomplete=ignore_incomplete)
+
         slug = wldoc.book_info.url.slug
         try:
             lesson = cls.objects.get(slug=slug)
@@ -120,13 +132,14 @@ class Lesson(models.Model):
         lesson.xml_file.save('%s.xml' % slug, ContentFile(xml), save=False)
         lesson.title = wldoc.book_info.title
 
-        lesson.level = Level.objects.get(slug=wldoc.book_info.audience)
+        lesson.level = Level.objects.get(meta_name=wldoc.book_info.audience)
         lesson.populate_dc()
+        lesson.populate_description(wldoc=wldoc)
         lesson.build_html(infile=infile)
-        lesson.build_pdf(infile=infile)
+        lesson.build_pdf()
         lesson.build_package()
         if lesson.type != 'project':
-            lesson.build_pdf(student=True, infile=infile)
+            lesson.build_pdf(student=True)
             lesson.build_package(student=True)
         return lesson
 
@@ -135,18 +148,34 @@ class Lesson(models.Model):
         wldoc = WLDocument.from_file(self.xml_file.path)
         self.dc = wldoc.book_info.to_dict()
         self.type = self.dc["type"]
+        assert self.type in ('appendix', 'course', 'synthetic', 'project'), \
+            u"Unknown lesson type: %s" % self.type
         self.save()
 
         courses = set()
         for identifier in wldoc.book_info.curriculum:
+            identifier = (identifier or "").replace(' ', '')
+            if not identifier: continue
             try:
-                curr = Curriculum.objects.get(identifier=identifier)
+                curr = Curriculum.objects.get(identifier__iexact=identifier)
             except Curriculum.DoesNotExist:
+                logging.warn('Unknown curriculum course %s in lesson %s' % (identifier, self.slug))
                 pass
             else:
                 courses.add(curr.course)
         self.curriculum_courses = courses
 
+    def populate_description(self, wldoc=None, infile=None):
+        if wldoc is None:
+            wldoc = self.wldocument(infile)
+        for nagl in wldoc.edoc.findall('.//naglowek_rozdzial'):
+            if (nagl.text or '').strip() == u'Pomysł na lekcję':
+                from lxml import etree
+                self.description = etree.tostring(nagl.getnext(),
+                        method='text', encoding='unicode').strip()
+                self.save()
+                return
+
     def wldocument(self, infile=None):
         from librarian import IOFile
         from librarian.parser import WLDocument
@@ -166,9 +195,11 @@ class Lesson(models.Model):
         self.html_file.save("%s.html" % self.slug,
             File(open(html.get_filename())))
 
-    def build_pdf(self, student=False, infile=None):
+    def build_pdf(self, student=False):
         from .publish import PdfFormat
-        wldoc = self.wldocument(infile)
+        # PDF uses document with attachments already saved as media,
+        # otherwise sorl.thumbnail complains about SuspiciousOperations.
+        wldoc = self.wldocument()
         if student:
             pdf = PdfFormat(wldoc).build()
             self.student_pdf.save("%s.pdf" % self.slug,
@@ -230,6 +261,9 @@ class Lesson(models.Model):
         except IndexError:
             return None
 
+    def requires_internet(self):
+        return 'internet' in self.dc.get('requires', [])
+
 
 class Attachment(models.Model):
     slug = models.CharField(max_length=255)
@@ -265,3 +299,10 @@ class LessonStub(models.Model):
 
     def __unicode__(self):
         return self.title
+
+    @property
+    def slug(self):
+        return ''
+
+    def add_to_zip(self, *args, **kwargs):
+        pass
index 9f79dae..cca25de 100755 (executable)
@@ -1,13 +1,56 @@
 # -*- coding: utf-8
 from django.core.files.base import ContentFile
 from django.core.files import File
+from django.core.urlresolvers import reverse
 from librarian import DocProvider, IOFile
 from librarian.pyhtml import EduModuleFormat
 from librarian.pypdf import EduModulePDFFormat
 from .models import Lesson, Attachment
+from fnpdjango.utils.text.slughifi import slughifi
+
+
+# TODO: Using sorl.thumbnail for now,
+# but this should be done in Librarian,
+# directly using convert or PIL as a fallback.
+def get_image(src_img_path, width=None,
+        default_width=1600, formats=('PNG', 'JPEG', 'GIF')):
+    """ Returns an object with `url` and `storage` attributes,
+        or None if using the original image is OK.
+    """
+    
+    from PIL import Image
+    from sorl.thumbnail import get_thumbnail
+    
+    # Does it need converting?
+    # Yes, if width is given explicitly.
+    convert = width is not None
+    if not convert:
+        # Looks like it doesn't need converting.
+        # But let's try opening it and checking its type.
+        try:
+            simg = Image.open(src_img_path)
+        except IOError:
+            # It doesn't look like image,
+            # but maybe it's convertable to one.
+            convert = True
+        else:
+            if simg.format not in formats:
+                # It's an image, but it's in some weird format.
+                convert = True
+                width = simg.size[0]
+
+    if convert:
+        if width is None:
+            width = default_width
+        return get_thumbnail(src_img_path, '%sx%s' % (width, 10*width))
+    else:
+        return None
 
 
 class HtmlFormat(EduModuleFormat):
+    IMAGE_FORMATS = ('PNG', 'JPEG', 'GIF')
+    DEFAULT_IMAGE_WIDTH = 1600
+
     def find_attachment(self, slug, fmt):
         lesson_slug = self.wldoc.book_info.url.slug
         try:
@@ -34,35 +77,45 @@ class HtmlFormat(EduModuleFormat):
         return self.find_attachment(slug, fmt).file.url
 
     def url_for_image(self, slug, fmt, width=None):
-        if width is None:
-            return self.url_for_material(slug, fmt)
-
-        lesson_slug = self.wldoc.book_info.url.slug
-        th_slug = "thumb/%s__th%d" % (slug, width)
         try:
-            # If already saved, use it.
-            att = Attachment.objects.get(lesson__slug=lesson_slug,
-                                         slug=th_slug, ext=fmt)
-        except Attachment.DoesNotExist, e:
-            from PIL import Image
-            from StringIO import StringIO
-            # Find full image, create thumbnail, save.
-            src_att = self.find_attachment(slug, fmt)
-            simg = Image.open(src_att.file.path)
-            size = (width, simg.size[1]*width/simg.size[0])
-            simg = simg.resize(size, Image.ANTIALIAS)
-
-            tempfile = StringIO()
-            img_format = "JPEG" if fmt.upper() == "JPG" else fmt
-            simg.save(tempfile, format=img_format)
-            att_name = "%s.%s" % (th_slug, fmt)
-            lesson = Lesson.objects.get(slug=lesson_slug)
-            att = lesson.attachment_set.create(slug=th_slug, ext=fmt)
-            att.file.save(att_name, ContentFile(tempfile.getvalue()))
-        return att.file.url
+            src_img = self.find_attachment(slug, fmt).file
+        except self.MaterialNotFound:
+            return ''
+        img = get_image(src_img.path, width,
+            self.DEFAULT_IMAGE_WIDTH, self.IMAGE_FORMATS)
+        return (img or src_img).url
+
+    def text_to_anchor(self, text):
+        return slughifi(text)
+
+    def get_forma_url(self, forma):
+        return '%s#%s' % (
+            reverse('catalogue_lesson', args=['metody']),
+            self.text_to_anchor(forma)
+        )
+
+    def get_help_url(self, naglowek):
+        return '%s%s#%s' % (
+            '//edukacjamedialna.edu.pl',
+            reverse('info', args=['jak-korzystac/']),
+            self.naglowek_to_anchor(naglowek)
+        )
+
 
 class PdfFormat(EduModulePDFFormat):
-    pass
+    IMAGE_FORMATS = ('PNG', 'JPEG', 'GIF')
+    DEFAULT_IMAGE_WIDTH = 1600
+
+    def get_image(self, name):
+        src_img = super(PdfFormat, self).get_image(name)
+        img = get_image(src_img.get_filename(),
+                default_width=self.DEFAULT_IMAGE_WIDTH,
+                formats=self.IMAGE_FORMATS
+            )
+        if img:
+            return IOFile.from_filename(img.storage.path(img))
+        else:
+            return src_img
 
 
 class OrmDocProvider(DocProvider):
index 968e8d1..a7f365c 100644 (file)
@@ -2,12 +2,12 @@
   float: left;
   position: relative;
   width: 43.75em;
-  height: 14.688em;
+  height: 14.6875em;
   overflow: hidden;
-  border-radius: 0.938em; }
+  border-radius: 0.9375em; }
   #catalogue-carousel #catalogue-carousel-links {
     width: 28.75em;
-    height: 14.688em;
+    height: 14.6875em;
     list-style: none;
     margin: 0;
     padding: 0; }
       left: 0;
       height: 100%;
       background-size: 100% 100%;
-      border-top-left-radius: 0.938em 6.38%;
-      border-bottom-left-radius: 0.938em 6.38%; }
-      #catalogue-carousel #catalogue-carousel-links li a {
+      border-top-left-radius: 0.9375em 6.38%;
+      border-bottom-left-radius: 0.9375em 6.38%;
+      z-index: 100;
+      background-color: #888; }
+      #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link {
         display: block;
         overflow: hidden;
         width: 28.75em;
         height: 100%;
         background: url(/static/catalogue/img/carousel-left.png) 100% 0 no-repeat;
         background-size: 4.375em 100%; }
-        #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note {
+        #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note {
           position: relative;
           height: 100%;
           color: white;
-          margin-top: 12em; }
-          #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p:before {
+          margin-top: 8.5em; }
+          #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div:before {
             content: " ";
             display: block;
             position: absolute;
             z-index: -1;
             background-color: black;
             opacity: 0.6; }
-          #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p {
-            margin: 0; }
-            #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p em {
-              margin: 0 .2em 0 .5em;
-              font-style: normal;
-              font-size: 1.5em; }
-            #catalogue-carousel #catalogue-carousel-links li a .catalogue-carousel-note p strong {
-              margin-left: .5em;
-              font-size: 2em; }
-      #catalogue-carousel #catalogue-carousel-links li a:active {
+          #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p {
+            padding: .4em 3em 0 .5em; }
+            #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p strong {
+              font-size: 1.2em;
+              display: block; }
+            #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link .catalogue-carousel-note div p .more {
+              position: absolute;
+              right: 4em;
+              top: 4.5em; }
+      #catalogue-carousel #catalogue-carousel-links li a.catalogue-carousel-link:active {
         outline: none; }
+      #catalogue-carousel #catalogue-carousel-links li .attribution {
+        text-align: right;
+        font-size: .75em;
+        position: absolute;
+        right: 5em;
+        top: .1em;
+        color: white;
+        font-weight: bold;
+        text-shadow: 0 0 5px #000; }
   #catalogue-carousel #catalogue-carousel-switcher {
     margin: 0;
-    padding: 3.125em 0 0 3.625em;
+    padding: 1.25em 0 0 3.625em;
     width: 11.375em;
-    height: 11.563em;
+    height: 13.4375em;
     position: absolute;
     right: 0;
     top: 0;
     list-style: none;
-    border-radius: 0 0.938em 0.938em 0;
+    border-radius: 0 0.9375em 0.9375em 0;
     background-color: #ed7831;
     background-image: url(/static/catalogue/img/carousel-right.png);
     background-position: 0 0;
     background-repeat: no-repeat;
-    background-size: auto 14.688em;
+    background-size: auto 14.6875em;
     /* right part of mask as background */ }
     #catalogue-carousel #catalogue-carousel-switcher li {
-      margin-bottom: .9em; }
+      margin-bottom: .5em;
+      font-size: .85em;
+      line-height: 1em; }
       #catalogue-carousel #catalogue-carousel-switcher li a {
         text-transform: uppercase;
-        color: #363a3e;
-        font-size: .9em;
-        font-weight: bold; }
+        color: #363a3e; }
       #catalogue-carousel #catalogue-carousel-switcher li a:before {
         vertical-align: top;
         margin-right: 1.5em; }
index 079ec3a..bc2041d 100755 (executable)
@@ -27,8 +27,10 @@ $ciemny: #363a3e;
             background-size: 100% 100%;
             border-top-left-radius: 15*$px 6.38%;
             border-bottom-left-radius: 15*$px 6.38%;
+            z-index: 100;
+            background-color: #888;
 
-            a {
+            a.catalogue-carousel-link {
                 display: block;
                 overflow: hidden;
                 width: 460*$px;
@@ -40,44 +42,58 @@ $ciemny: #363a3e;
                     position: relative;
                     height: 100%;
                     color: white;
-                    margin-top: 12em;
-
-                    p:before {
-                        content: " ";
-                        display: block;
-                        position: absolute;
-                        height: 100%;
-                        width: 100%;
-                        z-index: -1;
-                        background-color: black;
-                        opacity: 0.6;
-                    }
+                    margin-top: 8.5em;
 
-                    p {
-                        margin: 0;
-                        em {
-                            margin: 0 .2em 0 .5em;
-                            font-style: normal;
-                            font-size: 1.5em;
+                    div {
+                        &:before {
+                            content: " ";
+                            display: block;
+                            position: absolute;
+                            height: 100%;
+                            width: 100%;
+                            z-index: -1;
+                            background-color: black;
+                            opacity: 0.6;
                         }
-                        strong {
-                            margin-left: .5em;
-                            font-size: 2em;
+
+                        p {
+                            padding: .4em 3em 0 .5em;
+
+                            strong {
+                                font-size: 1.2em;
+                                display: block;
+                            }
+
+                            .more {
+                                position: absolute;
+                                right: 4em;
+                                top: 4.5em;
+                            }
                         }
-                        
                     }
                 }
             }
-            a:active {
+            a.catalogue-carousel-link:active {
                 outline: none;
             }
+            .attribution {
+                text-align: right;
+                font-size: .75em;
+                position: absolute;
+                right: 5em;
+                top: .1em;
+                color: white;
+                font-weight: bold;
+                text-shadow: 0 0 5px #000;
+            }
+
         }
     }
     #catalogue-carousel-switcher {
         margin: 0;
-        padding: 50*$px 0 0 58*$px;
+        padding: 20*$px 0 0 58*$px;
         width: 240*$px - 58*$px;
-        height: 235*$px - 50*$px;
+        height: 235*$px - 20*$px;
         position: absolute;
         right: 0;
         top: 0;
@@ -92,13 +108,13 @@ $ciemny: #363a3e;
         /* right part of mask as background */
 
         li {
-            margin-bottom: .9em;
+            margin-bottom: .5em;
+            font-size: .85em;
+            line-height: 1em;
 
             a {
                 text-transform: uppercase;
                 color: $ciemny;
-                font-size: .9em;
-                font-weight: bold;
             }
             a:before {
                 vertical-align: top;
index 09ff5af..acf699d 100644 (file)
@@ -1,4 +1,25 @@
 @charset "UTF-8";
+.box-button {
+  background-color: #ed7831;
+  border-radius: 0.9375em; }
+  .box-button .dl-button {
+    color: white;
+    padding: 1.0625em 0.75em 1.0625em 0.75em; }
+
+.dl-button {
+  color: #363a3e;
+  display: block;
+  font-weight: bold;
+  text-align: center;
+  text-transform: uppercase;
+  font-size: .9em; }
+
+.dl-button:after {
+  content: " ↓"; }
+
+#main-bar section.button {
+  margin-bottom: 1.0625em; }
+
 #sidebar {
   position: absolute;
   right: 0;
   width: 13.75em;
   color: #363a3e; }
   #sidebar section {
-    margin-bottom: 1.063em; }
+    margin-bottom: 1.0625em; }
     #sidebar section h1 {
       margin: 0; }
     #sidebar section h1.realisation {
       font-weight: normal; }
-  #sidebar .box {
-    background-color: #d4d6d8;
-    border-radius: 0.938em;
-    padding: 1.063em 0.75em 1.063em 0.75em; }
-    #sidebar .box h1 {
-      font-size: 1em;
-      text-transform: uppercase; }
-  #sidebar .box-button {
-    background-color: #ed7831;
-    border-radius: 0.938em; }
-    #sidebar .box-button .dl-button {
-      color: white;
-      padding: 1.063em 0.75em 1.063em 0.75em; }
-  #sidebar .dl-button {
-    color: #363a3e;
-    display: block;
-    font-weight: bold;
-    text-align: center;
-    text-transform: uppercase;
-    font-size: .9em; }
-  #sidebar .dl-button:after {
-    content: " ↓"; }
   #sidebar .section {
     border-top: 1px solid #c9ccce;
-    padding-top: 1.063em; }
+    padding-top: 1.0625em; }
   #sidebar .section-minor {
     border-top: 1px solid #c9ccce;
-    padding-top: 1.063em; }
+    padding-top: 1.0625em; }
     #sidebar .section-minor h1 {
       font-weight: normal;
       font-size: 1em; }
     font-size: .8em;
     color: #888;
     border-top: 1px solid #c9ccce;
-    padding-top: 1.063em; }
+    padding-top: 1.0625em; }
     #sidebar .section-micro h1 {
       font-weight: normal;
       font-size: 1em; }
     #sidebar .section-micro .link-list a {
       color: #888; }
+  #sidebar section:first-child {
+    border-top: 0;
+    padding-top: 0; }
 
 #main-bar {
   width: 40em; }
   #main-bar .top-link {
     float: right; }
+  #main-bar .box {
+    background-color: #d4d6d8;
+    border-radius: 0.9375em;
+    padding: 1.0625em; }
+    #main-bar .box h1 {
+      font-size: 1em;
+      text-transform: uppercase; }
+    #main-bar .box p {
+      margin: 0; }
+    #main-bar .box .box-icon {
+      margin: -.2em 0 -.2em 1em;
+      float: right;
+      text-align: center; }
 
 .lesson-footer {
   clear: both;
index 7bea63a..230e4aa 100755 (executable)
@@ -1,6 +1,30 @@
 $px: .0625em;
 $new_black: #363a3e;
 
+.box-button {
+    background-color: #ed7831;
+    border-radius: 15*$px;
+    .dl-button {
+        color: white;
+        padding: 17*$px 12*$px 17*$px 12*$px;
+    }
+}
+.dl-button {
+    color: $new_black;
+    display: block;
+    font-weight: bold;
+    text-align: center;
+    text-transform: uppercase;
+    font-size: .9em;
+}
+.dl-button:after {
+    content: " ↓";
+}
+
+#main-bar section.button {
+    margin-bottom: 17*$px;
+}
+
 #sidebar {
     position: absolute;
     right: 0;
@@ -18,34 +42,6 @@ $new_black: #363a3e;
         }
     }
 
-    .box {
-        background-color: #d4d6d8;
-        border-radius: 15*$px;
-        padding: 17*$px 12*$px 17*$px 12*$px;
-        h1 {
-            font-size: 1em;
-            text-transform: uppercase;
-        }
-    }
-    .box-button {
-        background-color: #ed7831;
-        border-radius: 15*$px;
-        .dl-button {
-            color: white;
-            padding: 17*$px 12*$px 17*$px 12*$px;
-        }
-    }
-    .dl-button {
-        color: $new_black;
-        display: block;
-        font-weight: bold;
-        text-align: center;
-        text-transform: uppercase;
-        font-size: .9em;
-    }
-    .dl-button:after {
-        content: " ↓";
-    }
     .section {
         border-top: 1px solid #c9ccce;
         padding-top: 17*$px;
@@ -71,6 +67,10 @@ $new_black: #363a3e;
             color: #888;
         }
     }
+    section:first-child {
+        border-top: 0;
+        padding-top: 0;
+    }
 }
 #main-bar {
     width: 640*$px;
@@ -78,6 +78,24 @@ $new_black: #363a3e;
     .top-link {
         float:right;
     }
+
+    .box {
+        background-color: #d4d6d8;
+        border-radius: 15*$px;
+        padding: 17*$px;
+        h1 {
+            font-size: 1em;
+            text-transform: uppercase;
+        }
+        p {
+            margin: 0;
+        }
+        .box-icon {
+            margin: -.2em 0 -.2em 1em;
+            float: right;
+            text-align: center;
+        }
+    }
 }
 
 .lesson-footer {
index b51e7f3..c8e73c4 100644 (file)
@@ -207,15 +207,15 @@ em.person {
     font-size: 2em; }
   .activity .info {
     float: right;
-    width: 8.438em; }
+    width: 8.4375em; }
     .activity .info .infobox {
       padding: 1em 0;
       border-top: 1px solid #c9ccce; }
       .activity .info .infobox h1 {
         text-transform: uppercase;
         font-weight: bold;
-        margin: 0 0 0.5em -2.188em;
-        padding-left: 2.188em;
+        margin: 0 0 0.5em -2.1875em;
+        padding-left: 2.1875em;
         line-height: 24px;
         font-size: 1em; }
       .activity .info .infobox p {
@@ -246,3 +246,9 @@ em.person {
 
 #book-text .top-link {
   margin-top: 1em; }
+
+.help {
+  font-size: .7em;
+  padding: 0 .5em;
+  color: #888;
+  vertical-align: super; }
index b200002..d98f1a3 100755 (executable)
@@ -318,3 +318,10 @@ em.person {
 #book-text .top-link {
     margin-top: 1em;
 }
+
+.help {
+    font-size: .7em;
+    padding: 0 .5em;
+    color: #888;
+    vertical-align: super;
+}
index 15c44ca..1a45397 100644 (file)
@@ -1,84 +1,54 @@
-.section-level {
-  width: 40em;
-  border-radius: 0.9375em;
-  margin: 1em 0;
-  overflow: hidden; }
-  .section-level a:hover {
-    text-decoration: underline; }
-
-.sections-row {
-  display: table; }
-
-.section-type {
-  display: table-cell;
-  vertical-align: top;
-  padding: 1.25em; }
-  .section-type h1 {
+#level-chooser-place {
+  min-height: 4em;
+  margin-top: 2em; }
+  #level-chooser-place ul#level-chooser {
+    margin: 0;
+    padding: 1em 0 1em 8.75em;
+    background-color: white;
+    width: 31.25em;
+    z-index: 300;
+    position: relative;
     text-transform: uppercase;
-    margin: 0 0 1em 0;
-    font-size: 1em; }
-  .section-type img {
-    float: left;
-    margin-right: 1em;
-    margin-bottom: 1em;
-    border: 0.375em solid white; }
-
-.section-type-synthetic {
-  width: 18.75em; }
-
-.section-type-course {
-  width: 16.25em; }
-
-.section-type-project {
-  width: 37.5em; }
-
-.section-level-gimnazjum {
-  background: #f4ae83;
-  color: #67584f; }
-  .section-level-gimnazjum a, .section-level-gimnazjum a:hover {
-    color: #67584f; }
-  .section-level-gimnazjum .section-type-course {
-    background: #ed7831;
-    color: #fff; }
-    .section-level-gimnazjum .section-type-course a {
-      color: #fff; }
-  .section-level-gimnazjum .section-type-project {
-    background-color: #f8cdb2; }
-
-.section-level-liceum {
-  background: #44b69f;
-  color: #363a3e; }
-  .section-level-liceum a, .section-level-liceum a:hover {
-    color: #363a3e; }
-  .section-level-liceum .section-type-course {
-    background: #16a487;
-    color: #fff; }
-    .section-level-liceum .section-type-course a {
-      color: #fff; }
-  .section-level-liceum .section-type-project {
-    background-color: #9fdbcf; }
-
-.course-boxes h1 {
-  color: #363a3e; }
-.course-boxes .section-level {
-  background: white;
-  border: 1px solid #777777; }
-  .course-boxes .section-level a, .course-boxes .section-level a:hover {
-    color: #363a3e; }
-  .course-boxes .section-level .section-type {
-    background: white; }
-.course-boxes .section-type-synthetic {
-  width: 16.25em; }
-.course-boxes .section-type-course {
-  width: 18.75em; }
-
-.section-links {
-  float: right; }
-
-h2.section-header {
-  margin: 0; }
-
-.section-list-toc {
-  display: inline-block;
-  vertical-align: top;
-  width: 18.75em; }
+    text-align: right; }
+    #level-chooser-place ul#level-chooser .home {
+      display: none;
+      position: absolute;
+      top: .5em;
+      left: 0; }
+      #level-chooser-place ul#level-chooser .home a {
+        background: none;
+        padding: 0; }
+        #level-chooser-place ul#level-chooser .home a img {
+          width: 6.25em; }
+    #level-chooser-place ul#level-chooser.fixed {
+      position: fixed;
+      top: 0;
+      border-bottom: 1px solid #c9ccce; }
+      #level-chooser-place ul#level-chooser.fixed .home {
+        display: block; }
+    #level-chooser-place ul#level-chooser li {
+      display: inline-block;
+      list-style: none; }
+      #level-chooser-place ul#level-chooser li a {
+        padding: .5em 1em;
+        border-radius: 0.3125em;
+        background: #eee; }
+        #level-chooser-place ul#level-chooser li a.active {
+          color: white;
+          background: #ED7831; }
+
+.level .link-list {
+  margin-left: 1em; }
+.level .level-toc {
+  overflow: hidden;
+  /* Because we're changing bg color lower. */ }
+  .level .level-toc.fixed {
+    position: fixed; }
+  .level .level-toc .link-list {
+    margin-left: 1em; }
+    .level .level-toc .link-list li {
+      margin-bottom: 0; }
+      .level .level-toc .link-list li.curriculumcourses {
+        margin: 10px -17px -17px;
+        padding: 10px 16px 16px;
+        background-color: #eee; }
index a9a1305..192e5b6 100755 (executable)
 $px: 0.0625em;
 
-.section-level {
-    width: 640*$px;
-    border-radius: 15*$px;
-    margin: 1em 0;
-    overflow: hidden;
-
-    a:hover {
-        text-decoration: underline;
-    }
-}
-
-.sections-row {
-    display: table;
-}
-
-.section-type {
-    display: table-cell;
-    vertical-align: top;
-    padding: 20*$px;
-
-    h1 {
+#level-chooser-place {
+    min-height: 4em;
+    margin-top: 2em;
+
+    ul#level-chooser {
+        margin: 0;
+        padding: 1em 0 1em 140*$px;
+        background-color: white;
+        width: 500*$px;
+        z-index: 300;
+        position: relative;
         text-transform: uppercase;
-        margin: 0 0 1em 0;
-        font-size: 1em;
-    }
-
-    img {
-        float: left;
-        margin-right: 16*$px;
-        margin-bottom: 16*$px;
-        border: 6*$px solid white;
-    }
-}
-.section-type-synthetic {
-    width: 340*$px - 2 * 20*$px;
-}
-.section-type-course {
-    width: 300*$px - 2 * 20*$px;
-}
-
-.section-type-project {
-    width: 640*$px - 2 * 20*$px;
-}
+        text-align: right;
+
+        .home {
+            display: none;
+            position: absolute;
+            top: .5em;
+            left: 0;
+
+            a {
+                background: none;
+                padding: 0;
+                img {
+                    width: 100*$px;
+                }
+            }
+        }
 
-.section-level-gimnazjum {
-    background: #f4ae83;
-    color: #67584f;
-    a, a:hover {
-        color: #67584f;
-    }
+        &.fixed {
+            position: fixed;
+            top: 0;
+            border-bottom: 1px solid #c9ccce;
 
-    .section-type-synthetic {
-    }
-    .section-type-course {
-        background: #ed7831;
-        color: #fff;
-        a {
-            color: #fff;
+            .home {
+                display: block;
+            }
         }
-    }
-    .section-type-project {
-        background-color: lighten(#f4ae83, 10);
-    }
-}
 
+        li {
+            display: inline-block;
+            list-style: none;
 
-.section-level-liceum {
-    background: #44b69f;
-    color: #363a3e;
-    a, a:hover {
-        color: #363a3e;
-    }
+            a {
+                padding: .5em 1em;
+                border-radius: 5*$px;
+                background: #eee;
 
-    .section-type-synthetic {
-    }
-    .section-type-course {
-        background: #16a487;
-        color: #fff;
-        a {
-            color: #fff;
+                &.active {
+                    color: white;
+                    background: #ED7831;
+                }
+            }
         }
     }
-    .section-type-project {
-        background-color: lighten(#44b69f, 25);
-    }
 }
 
-
-.course-boxes {
-    h1 {
-        color: #363a3e;
-    }
-    .section-level {
-        background: white;
-        border: 1px solid #777;
-        a, a:hover {
-            color: #363a3e;
-        }
-        .section-type {
-            background: white;
-        }
-    }
-    .section-type-synthetic {
-        width: 300*$px - 2 * 20*$px;
-    }
-    .section-type-course {
-        width: 340*$px - 2 * 20*$px;
+.level {
+    .link-list {
+        margin-left: 1em;
     }
-}
 
+    .level-toc {
+        overflow: hidden; /* Because we're changing bg color lower. */
 
-.section-links {
-    float: right;
-}
+        &.fixed {
+            position: fixed;
+        }
 
-h2.section-header {
-    margin: 0;
-}
+        .link-list {
+            margin-left: 1em;
 
+            li {
+                margin-bottom: 0;
 
-.section-list-toc {
-    display: inline-block;
-    vertical-align: top;
-    width: 300*$px;
+                &.curriculumcourses {
+                    margin: 10px -17px -17px;
+                    padding: 10px 16px 16px;
+                    background-color: #eee;
+                }
+            }
+        }
+    }
 }
index b7e5021..b2484be 100755 (executable)
@@ -2,31 +2,26 @@
 $(function() {
 
 
-$.fn.cycle.transitions.rgrowY = function($cont, $slides, opts) {
-       opts.before.push(function(curr, next, opts) {
-               $.fn.cycle.commonReset(curr,next,opts,true,false,true);
-               opts.cssBefore.top = this.cycleH/2;
-               opts.animIn.top = 0;
-               opts.animIn.height = this.cycleH;
-               opts.animOut.top = this.cycleH/2;
-        opts.animOut.height = 0;
-       });
-       opts.cssBefore.height = 0;
-       opts.cssBefore.left = 0;
-};
-
 $("#catalogue-carousel-links").each(function() {
-    $(this).cycle({
-        fx: 'rgrowY',
-        sync:false,
-        easeIn: 'easeInQuad',
-        easeOut: 'easeOutQuad',
+    $slides = $(this); 
+
+    $slides.cycle({
+        fx: 'fade',
         speed: 1000,
+        timeout: 5000,
         pager: '#catalogue-carousel-switcher',
-        pagerAnchorBuilder: function(){},
+        pagerAnchorBuilder: function() {},
     });
+
+    $("#catalogue-carousel-switcher li").each(function(i, e) {
+        $("a", e).click(function(ev) {
+            ev.preventDefault();
+            $slides.cycle(i);
+        });
+    });
+
 });
 
 
 });
-})($);
+})(jQuery);
diff --git a/catalogue/static/catalogue/js/lesson-list.js b/catalogue/static/catalogue/js/lesson-list.js
new file mode 100644 (file)
index 0000000..62bbb65
--- /dev/null
@@ -0,0 +1,60 @@
+(function($){
+$(function() {
+
+
+function scrollTo(thing) {
+    $('html, body').scrollTop($(thing).offset().top - $('#level-chooser').outerHeight());
+}
+
+function updateView() {
+    var scrolltop = $(window).scrollTop();
+
+    $('#level-chooser-place').each(function(i, el){
+        if (scrolltop > $(el).offset().top) {
+            $("#level-chooser").addClass("fixed");
+        }
+        else {
+            $("#level-chooser").removeClass("fixed");
+        }
+    });
+
+    $('.level-toc').each(function(i, el) {
+        var $sect = $($(el).parent());
+        var menu_top = $('#level-chooser').outerHeight();
+        var menu_scrolltop = scrolltop + menu_top;
+
+        if (menu_scrolltop + 2 >= $sect.offset().top && 
+                menu_scrolltop < $sect.offset().top + $sect.outerHeight()) {
+            $(el).addClass("fixed").css("top", Math.min(
+                menu_top, 
+                - scrolltop + $sect.offset().top + $sect.outerHeight() - $(el).outerHeight()
+            ));
+            $("#level-chooser a[href='#" + $sect.attr('id') + "']").addClass('active');
+        }
+        else {
+            $(el).removeClass("fixed");
+            $("#level-chooser a[href='#" + $sect.attr('id') + "']").removeClass('active');
+        }
+    });
+}
+
+
+
+$("#level-chooser a, .level-toc a").click(function(ev) {
+    ev.preventDefault();
+    scrollTo($(this).attr('href'));
+});
+
+
+
+
+
+updateView();
+$(document).scroll(updateView);
+if (window.location.hash) {
+    scrollTo(window.location.hash);
+}
+
+
+});
+})(jQuery);
index 6b22a83..080eb45 100755 (executable)
@@ -2,7 +2,10 @@
 $(function() {
 
 
-$('a.image').colorbox();
+$('a.image').colorbox({
+    maxWidth: '100%',
+    maxHeight: '100%',
+});
 
 
 });
index 7dce3c9..98b6e3b 100755 (executable)
@@ -1,22 +1,9 @@
 {% extends "catalogue/lesson/lesson_detail.html" %}
 
-{% block sidebar-top %}
-
-<section class="box">
-    <h1 class="realisation">Zebrane dla wszystkich tematów</h1>
-    
-    <p>To jest materiał wspólny dla wszystkich lekcji
-    edukacji medialnej{% if object.level.slug = "liceum" %}
-        (na poziomie zaawansowanym)
-    {% endif %}. 
-    Zobacz też
-    <strong><a href="{% url 'catalogue_lessons' %}">pełny kurs</a></strong>
-    z podziałem na poszczególne tematy.
-    </p>
-</section>
-
+{% block lesson-info %}
 {% endblock %}
 
+
 {% block suggest-link %}
 <a href="{% url 'contact_form' 'sugestie' %}?temat={{ object.title|urlencode }}">
     Zgłoś swoją uwagę na temat tej strony.
diff --git a/catalogue/templates/catalogue/lesson/box-icons.html b/catalogue/templates/catalogue/lesson/box-icons.html
new file mode 100644 (file)
index 0000000..2963698
--- /dev/null
@@ -0,0 +1,18 @@
+{% load static from staticfiles %}
+{% if object.requires_internet %}
+<div class="box-icon"><img src="{% static 'img/icons/internet_black.png' %}"
+        title="Wymaga dostępu do Internetu"
+        alt="Wymaga dostępu do Internetu"
+    ><br>Internet</div>
+{% else %}
+<div class="box-icon"><img src="{% static 'img/icons/nointernet_black.png' %}"
+        title="Nie wymaga dostępu do Internetu"
+        alt="Nie wymaga dostępu do Internetu"
+        ><br>Bez Internetu</div>
+{% endif %}
+{% if publisher %}
+<div class="box-icon"><img src="{{ publisher.logo.url }}"
+        title="{{ publisher.name }}"
+        alt="{{ publisher.name }}"
+    ></div>
+{% endif %}
index cadc580..28f6504 100755 (executable)
@@ -1,24 +1,25 @@
 {% extends "catalogue/lesson/lesson_detail.html" %}
+{% load static from staticfiles %}
 
-{% block sidebar-top %}
-
+{% block lesson-info %}
 <section class="box">
-    <h1 class="realisation">Realizacja i czas lekcji</h1>
+    <div class="box-icon"><img src="/static/img/icons/activity-time.png"><br>45m</div>
+
+    {% include "catalogue/lesson/box-icons.html" %}
+
     <p>Ta lekcja jest częścią tematu
-    <a href="{{ object.section.get_absolute_url }}"><strong>{{ object.section }}</strong></a>{% if object.level.slug = "liceum" %}
-        (na poziomie zaawansowanym)
-    {% endif %}.
-    {% with object.get_syntetic as synth %}
-    {% if synth %}
-    Dostępna jest również
-    <strong><a href="{{ object.get_syntetic.get_absolute_url }}">lekcja syntetyczna</a></strong>
-    dla tego tematu.
-    {% endif %}
-    {% endwith %}
+    <a href="{{ object.section.get_absolute_url }}"><strong>{{ object.section }}</strong></a>
+    na poziomie {{ object.level|lower }}.
     </p>
-    <p>Czas trwania: 45 minut.</p>
+    <div style="clear: right"></div>
 </section>
 
+{% endblock %}
+
+
+{% block sidebar-top %}
+<div class="buttons" style="padding-bottom: 1em; border-bottom: 1px solid red;">
+
 {% if object.package %}
     <section class="box-button"><a href="{{ object.package.url }}" class="dl-button">Pobierz całą lekcję</a></section>
 {% endif %}
@@ -26,5 +27,5 @@
     <section><a href="{{ object.student_package.url }}" class="dl-button">Pobierz lekcję w wersji dla ucznia</a></section>
 {% endif %}
 
-
+</div>
 {% endblock %}
index f08b5b8..362df10 100755 (executable)
 </aside>
 
 <div id="main-bar">
+
+{% block lesson-info %}
+{% endblock %}
+
 {{ object.html_file.read|safe }}
 
 
index 88e4a34..0c6d217 100755 (executable)
@@ -1,18 +1,25 @@
 {% extends "catalogue/lesson/lesson_detail.html" %}
 
-{% block sidebar-top %}
-
+{% block lesson-info %}
 <section class="box">
-    <h1 class="realisation">Projekt</h1>
-    <p>To jest <a href="{% url 'info' 'metoda-projektowa' %}">projekt</a> w ramach tematu
-    <strong>{{ object.section }}</strong></a>{% if object.level.slug = "liceum" %}
-        (na poziomie zaawansowanym)
-    {% endif %}.
-    Dostępny jest również
-    <strong><a href="{% url 'catalogue_lessons' %}#{{ object.section.slug }}">pełny kurs</a></strong>
-    tego tematu.
+    {% if publisher %}
+    <div class="box-icon"><img src="{{ publisher.logo.url }}"
+            title="{{ publisher.name }}"
+            alt="{{ publisher.name }}"
+        ></div>
+    {% endif %}
+
+    <p>To jest <a href="{% url 'info' 'metoda-projektowa' %}">projekt</a> 
+    na poziomie
+    <a href="{% url 'catalogue_lessons' %}#{{ object.level.slug }}_pelny">{{ object.level|lower }}</a>.
     </p>
 </section>
+{% endblock %}
+
+
+
+{% block sidebar-top %}
+
 
 {% if object.package %}
     <section class="box-button"><a href="{{ object.package.url }}" class="dl-button">Pobierz cały projekt</a></section>
index c7d04c8..df60c9f 100755 (executable)
@@ -1,19 +1,19 @@
 {% extends "catalogue/lesson/lesson_detail.html" %}
 
-{% block sidebar-top %}
-
+{% block lesson-info %}
 <section class="box">
-    <h1 class="realisation">Realizacja i czas lekcji</h1>
-    <p>Ta lekcja jest syntezą tematu
-    <strong>{{ object.section }}</strong></a>{% if object.level.slug = "liceum" %}
-        (na poziomie zaawansowanym)
-    {% endif %}.
-    Dostępny jest również
-    <strong><a href="{% url 'catalogue_lessons' %}#{{ object.section.slug }}">pełny kurs</a></strong>
-    tego tematu.
+    <div class="box-icon"><img src="/static/img/icons/activity-time.png"><br>45m</div>
+
+    {% include "catalogue/lesson/box-icons.html" %}
+
+    <p>Ta lekcja jest częścią skróconego kursu na poziomie {{ object.level|lower }}.
+        Zobacz też <a href="{% url 'catalogue_lessons' %}#{{ object.level.slug }}_pelny">pełny kurs</a>.
     </p>
-    <p>Czas trwania: 45 minut.</p>
+    <div style="clear: right"></div>
 </section>
+{% endblock %}
+
+{% block sidebar-top %}
 
 {% if object.package %}
     <section class="box-button"><a href="{{ object.package.url }}" class="dl-button">Pobierz całą lekcję</a></section>
diff --git a/catalogue/templates/catalogue/lesson_list.html b/catalogue/templates/catalogue/lesson_list.html
new file mode 100755 (executable)
index 0000000..1578aa2
--- /dev/null
@@ -0,0 +1,46 @@
+{% extends "base.html" %}
+{% load catalogue_tags %}
+{% load static from staticfiles %}
+{% load course_boxes course_boxes_toc from curriculum_tags %}
+{% load chunk from chunks %}
+
+{% block title %}Lekcje{% endblock %}
+
+{% block body %}
+    <h1>Lekcje</h1>
+
+<aside id="sidebar">
+    <section class="section-minor">
+        <h1>Zebrane dla wszystkich tematów</h1>
+        <ul class="link-list">
+            {% for lesson in appendix %}
+                <li><a href="{{ lesson.get_absolute_url }}">{{ lesson }}</a></li>
+            {% endfor %}
+            <li><a href="{% url 'info' 'infografiki' %}">Infografiki</a></li>
+        </ul>
+    </section>
+</aside>
+
+<div id="main-bar">
+    <div class="box">
+    {% chunk 'levels_disclaimer' %}
+    </div>
+
+    <div id="level-chooser-place">
+        <ul id="level-chooser">
+            <li class="home"><a href="#body"><img src="{% static 'img/logo.png' %}" /></a></li>
+            {% for object in object_list %}
+                <li><a href="#{{ object.slug }}">{{ object }}</a></li>
+            {% endfor %}
+        </ul>
+    </div>
+
+
+
+    {% for level in object_list %}
+        {% level_box level %}
+    {% endfor %}
+</div>
+
+
+{% endblock %}
diff --git a/catalogue/templates/catalogue/section_list.html b/catalogue/templates/catalogue/section_list.html
deleted file mode 100755 (executable)
index 9f48c4f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-{% extends "base.html" %}
-{% load catalogue_tags %}
-{% load course_boxes course_boxes_toc from curriculum_tags %}
-
-{% block title %}Lekcje{% endblock %}
-
-{% block body %}
-    <h1>Lekcje</h1>
-
-<aside id="sidebar">
-    <section class="box">
-        <h1 class="realisation">Realizacja i czas lekcji</h1>
-        <p>Każdy dział można zrealizować w formie lekcji syntetycznej
-        dającej przegląd danego zagadnienia, bądź w formie pełnego kursu.
-        </p>
-        <p>Czas trwania: 45 minut</p>
-    </section>
-    <section class="box-button"><a href="{{ package_url }}" class="dl-button">Pobierz wszystkie lekcje</a></section>
-    <section><a href="{{ package_student_url }}" class="dl-button">Pobierz wszystkie lekcje w&nbsp;wersji dla ucznia</a></section>
-    <section class="section-minor">
-        <h1>Zebrane dla wszystkich tematów</h1>
-        <ul class="link-list">
-            {% for lesson in appendix %}
-                <li><a href="{{ lesson.get_absolute_url }}">{{ lesson }}</a></li>
-            {% endfor %}
-            <li><a href="{% url 'info' 'infografiki' %}">Infografiki</a></li>
-        </ul>
-    </section>
-</aside>
-
-<div id="main-bar">
-    <div class="section-list-toc">
-    <h2 id='top'>Tematy</h2>
-    <ul class="link-list">
-    {% for object in object_list %}
-        <li><a href="#{{ object.slug }}">{{ object }}</a></li>
-    {% endfor %}
-    </ul>
-    </div>
-    <div class="section-list-toc">
-    <h2>Przedmioty</h2>
-    <ul class="link-list">
-        {% course_boxes_toc %}
-    </ul>
-    </div>
-    
-    {% for object in object_list %}
-        <div class="section-links">
-            <a href="#top">wróć do spisu treści</a>
-        </div>
-        <h2 id='{{ object.slug }}' class="section-header">{{ object }}</h2>
-
-        {% section_box object %}
-    {% endfor %}
-
-    <div class="course-boxes">
-    <h2>Lekcje wybrane na poszczególne przedmioty:</h2>
-    {% course_boxes %}
-    </div>
-
-</div>
-
-
-{% endblock %}
index c482556..bb31eae 100755 (executable)
@@ -1,21 +1,27 @@
-{% load static %}
-
-{% url "info" "jak-korzystac/" as jak %}
+{% load thumbnail %}
+{% url 'catalogue_lessons' as lessons %}
 <section id="catalogue-carousel">
     <ul id="catalogue-carousel-links">
-        <li style="background-image: url({% static 'catalogue/img/carousel/katarzyna-wlodarczyk.jpg' %}); z-index: 100;">
-            <a href="{% url 'info' 'dobre-praktyki/' %}" class="catalogue-carousel-link">
+        {% for section in object_list %}
+        <li style="{% if section.pic %}{% thumbnail section.pic '460x235' crop='center' as th %}background-image: url('{{ th.url }}');{% endthumbnail %}{% endif %}">
+            <a href="{{ lessons }}#gimnazjum_{{ section.slug }}" class="catalogue-carousel-link">
                 <div class="catalogue-carousel-note">
-                    <p><strong>{{ lessons_count }}</strong> <em>{{ lessons_desc }}</em>
-                    - zobacz w działaniu</p>
+                    <div>
+                        <p>
+                        <strong>{{ section }}</strong>
+                        {{ section.summary }}
+                        <span class="more">zobacz &rarr;</span>
+                        </p>
+                    </div>
                 </div>
             </a>
-        </li>
+            <a class="attribution" href="{{ section.pic_src }}">fot. {{ section.pic_attribution }}</a>
+        </li>    
+        {% endfor %}
     </ul>
     <ul id="catalogue-carousel-switcher">
-        <li><a href="{{ jak }}#wiedza-w-pigulce" class="knowledge">wiedza w pigułce</a></li>
-        <li><a href="{{ jak }}#zadania" class="activity">zadania</a></li>
-        <li><a href="{{ jak }}#scenariusze" class="lesson-plan">scenariusze</a></li>
-        <li><a href="{{ jak }}#slowniczek" class="reference">słowniczek</a></li>
+        {% for section in object_list %}
+            <li><a href="{{ section.get_absolute_url }}">{{ section }}</a></li>
+        {% endfor %}
     </ul>
 </section>
index 4e36e22..d2bcf48 100755 (executable)
@@ -1,10 +1,10 @@
 <h1>
 {% if root %}
-    <a href="{{ root.get_absolute_url }}">{{ root }}</a>
+    <a href="{{ root.get_absolute_url }}">{{ root }}, <br>{{ lesson.level }}</a>
 {% elif lesson.type == 'synthetic' %}
-    <a href="{% url 'catalogue_lessons' %}">Lekcje syntetyczne ze wszystkich tematów</a>
+    <a href="{% url 'catalogue_lessons' %}">Kurs skrócony, <br>{{ lesson.level }}</a>
 {% elif lesson.type == 'project' %}
-    <a href="{% url 'catalogue_lessons' %}">Projekty ze wszystkich tematów</a>
+    <a href="{% url 'catalogue_lessons' %}">Projekty, <br>{{ lesson.level }}</a>
 {% else %}
     <a href="{% url 'catalogue_lessons' %}">Inne</a>
 {% endif %}
     <li>
     {% if item == lesson %}
         <strong>{{ item }}</strong>
-        {% if mark_level and item.level.slug == 'liceum' %} (poziom zaawansowany){% endif %}
     {% else %}
-        <a href="{{ item.get_absolute_url }}">{{ item }}
-            {% if mark_level and item.level.slug == 'liceum' %} (poziom zaawansowany){% endif %}
-        </a>
+        <a href="{{ item.get_absolute_url }}">{{ item }}</a>
     {% endif %}
     </li>
 {% endfor %}
 </ul>
-
-{% if link_other_level %}
-{% with other=lesson.get_other_level %}
-    {% if other %}
-        <p>Ten temat jest dostępny również na 
-        <a href="{% url 'catalogue_lessons' %}#{{ lesson.section.slug }}_{{ other.slug }}">poziomie
-        {% if other.slug == 'liceum' %}zaawansowanym{% else %}podstawowym{% endif %}</a>.</p>
-    {% endif %}
-{% endwith %}
-{% endif %}
diff --git a/catalogue/templates/catalogue/snippets/lesson_or_stub.html b/catalogue/templates/catalogue/snippets/lesson_or_stub.html
new file mode 100644 (file)
index 0000000..5bb2614
--- /dev/null
@@ -0,0 +1,9 @@
+{% if lesson.slug %}
+    <a href="{{ lesson.get_absolute_url }}" title="{{ lesson.description }}">
+{% endif %}
+{{ lesson }}
+{% if lesson.slug %}
+    </a>
+{% else %}
+(w przygotowaniu)
+{% endif %}
diff --git a/catalogue/templates/catalogue/snippets/level_box.html b/catalogue/templates/catalogue/snippets/level_box.html
new file mode 100755 (executable)
index 0000000..bb2fa12
--- /dev/null
@@ -0,0 +1,142 @@
+<section id="{{ level.slug }}" class="level" style="margin-left: 20em">
+
+    <section class="box level-toc" style="float: left; margin-left: -20em; width: 15em;">
+        <strong><a href="#{{ level.slug }}">{{ level }}</a></strong>
+        <ul  class="link-list"  style="list-style: none; padding: 0; margin: 0;">
+            {% if lessons.synthetic %}
+            <li><a href="#{{ level.slug }}_skrocony">Skrócony kurs</a></li>
+            {% endif %}
+            {% if lessons.course %}
+            <li><a href="#{{ level.slug }}_pelny">Pełny kurs</a>
+                <ul style="list-style: none; padding: 0 0 0 1em; margin: 0;">
+                {% for section in lessons.course %}
+                        <li><a href="#{{ level.slug }}_{{ section.slug}}">{{ section }}</a></li>
+                {% endfor %}
+                </ul>
+            </li>
+            {% endif %}
+            {% if lessons.project %}
+            <li><a href="#{{ level.slug }}_projekt">Projekt</a></li>
+            {% endif %}
+            {% if lessons.appendix %}
+            <li><a href="#{{ level.slug }}_pozostale">Pozostałe materiały</a></li>
+            {% endif %}
+
+            {% if courses %}
+            <li class="curriculumcourses"><a href="#{{ level.slug }}_podstawa">Wg postawy programowej</a>
+                <ul style="list-style: none; padding: 0 0 0 1em; margin: 0;">
+                {% for course, lessons in courses %}
+                        <li><a href="#{{ level.slug }}_{{ course.slug}}">{{ course }}</a></li>
+                {% endfor %}
+                </ul>
+            </li>
+            {% endif %}
+        </ul>
+    </section>
+
+
+    <h1>{{ level }}</h1>
+
+    <section class="box-button button"><a href="{{ level.package.url }}" class="dl-button">Pobierz wszystkie lekcje</a></section>
+    <section class="button"><a href="{{ level.student_package.url }}" class="dl-button">Pobierz wszystkie lekcje w&nbsp;wersji dla ucznia</a></section>
+
+    {% if lessons.synthetic %}
+    <section id="{{ level.slug }}_skrocony">
+        <h1>Skrócony kurs</h1>
+
+        <p>Masz kilka godzin? Przeprowadź po jednej lekcji przeglądowej z każdego tematu.</p>
+
+        <ul class="link-list">
+            {% for lesson in lessons.synthetic %}
+                <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+            {% endfor %}
+        </ul>
+    </section>
+    {% endif %}
+
+
+    {% if lessons.course %}
+    <section id="{{ level.slug }}_pelny">
+        <h1>Pełny kurs</h1>
+
+        <p>Masz więcej czasu? Zrealizuj kompletny program edukacji medialnej.</p>
+
+        {% for section, s_lessons in lessons.course.items %}
+            <section id="{{ level.slug }}_{{ section.slug}}">
+                <h1>{{ section }}</h1>
+
+                <ul class="link-list">
+                    {% for lesson in s_lessons %}
+                        <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+                    {% endfor %}
+                </ul>
+            </section>
+        {% endfor %}
+
+    </section>
+    {% endif %}
+
+
+    {% if lessons.project %}
+    <section id="{{ level.slug }}_projekt">
+        <h1>Projekt</h1>
+
+        <p>Masz 4-6 tygodni? Zrealizuj jeden z projektów ze swoimi uczniami.</p>
+
+        <ul class="link-list">
+            {% for lesson in lessons.project %}
+                <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+            {% endfor %}
+        </ul>
+    </section>
+    {% endif %}
+
+
+    {% if courses %}
+    <section id="{{ level.slug }}_podstawa">
+        <h1>Wg podstawy programowej</h1>
+
+        {% for course, lessons in courses %}
+        <section id="{{ level.slug}}_{{ course.slug }}">
+            <h1>{{ course }}</h1>
+
+            {% if lessons.synthetic %}
+            <section>
+                <h1>Z kursu skróconego</h1>
+                <ul class="link-list">
+                    {% for lesson in lessons.synthetic %}
+                        <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+                    {% endfor %}
+                </ul>
+            </section>
+            {% endif %}
+
+            {% if lessons.course %}
+            <section>
+                <h1>Z kursu pełnego</h1>
+                <ul class="link-list">
+                    {% for lesson in lessons.course %}
+                        <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+                    {% endfor %}
+                </ul>
+            </section>
+            {% endif %}
+
+            {% if lessons.project %}
+            <section>
+                <h1>Projekt</h1>
+                <ul class="link-list">
+                    {% for lesson in lessons.project %}
+                        <li>{% include "catalogue/snippets/lesson_or_stub.html" %}</li>
+                    {% endfor %}
+                </ul>
+            </section>
+            {% endif %}
+
+        </section>
+        {% endfor %}
+        
+    </section>
+    {% endif %}
+
+</section>
diff --git a/catalogue/templates/catalogue/snippets/levels_main.html b/catalogue/templates/catalogue/snippets/levels_main.html
new file mode 100644 (file)
index 0000000..497a5c8
--- /dev/null
@@ -0,0 +1,19 @@
+{% load i18n %}
+<style type="text/css">
+#main-sections ul li {width: {{ section_width }}px;}
+#main-sections ul li a {width: {{ section_width|add:"-10" }}px;}
+.levelth {width: {{ section_width }}px;}
+</style>
+{% url 'catalogue_lessons' as les %}
+<ul class="section-buttons">
+{% for level in object_list %}
+<li class="box{{ level.pk }}">
+    <a href="{{ les }}#{{ level.slug }}">
+    <span class="in-box">
+    <span class="name">{{ level }}</span>
+    {{ level.length_synthetic }} lub {{ level.length_course }} godzin
+    </span>
+    </a>
+</li>
+{% endfor %}
+</ul>
diff --git a/catalogue/templates/catalogue/snippets/section_box.html b/catalogue/templates/catalogue/snippets/section_box.html
deleted file mode 100755 (executable)
index c505c04..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-{% load thumbnail %}
-{% for level, types in lessons.items %}
-{% if level.slug == "liceum" %}
-    <p><strong>{{section.title}}</strong>: poziom zaawansowany
-        <span class="section-links"><a href="#top">wróć do spisu treści</a></span>
-    </p>
-{% endif %}
-<section id="{{ section.slug }}_{{ level.slug }}" class="section-level section-level-{{ level.slug }}">
-    {% spaceless %}
-    <div class='sections-row'>
-    {% for lesson_type, lesson_list in types.items %}
-        {% if lesson_type == 'project' %}
-            </div><div class='sections-row'>
-        {% endif %}
-        <section class="section-type section-type-{{ lesson_type }}">
-            {% if lesson_type == 'synthetic' %}
-                {% if section.image %}
-                    {% thumbnail section.image "120x160" as im %}
-                        <a class="image" href="{{ section.image.url }}">
-                            <img src="{{ im.url }}" />
-                        </a>
-                    {% endthumbnail %}
-                {% endif %}
-                <h1>Lekcja syntetyczna</h1>
-            {% elif lesson_type == 'project' %}
-                <h1>Projekt</h1>
-            {% else %}
-                <h1>Pełny kurs</h1>
-            {% endif %}
-            {% if lesson_list %}
-            <ul class="section-lessons link-list">
-                {% for lesson in lesson_list %}
-                    <li class="section-lesson">
-                        {% if lesson.slug %}
-                            <a href="{{ lesson.get_absolute_url }}">{{ lesson }}{% if lesson_type == 'synthetic' %}
-                                <br/>(przegląd całego tematu w 45 minut)
-                            {% endif %}</a>
-                        {% else %}
-                            {{ lesson }} <em>(w&nbsp;przygotowaniu)</em>
-                        {% endif %}
-                    </li>
-                {% endfor %}
-            </ul>
-            {% else %}
-                <p>(W przygotowaniu)</p>
-            {% endif %}
-        </section>
-    {% endfor %}
-    </div>
-    {% endspaceless %}
-</section>
-{% endfor %}
diff --git a/catalogue/templates/catalogue/snippets/section_buttons.html b/catalogue/templates/catalogue/snippets/section_buttons.html
deleted file mode 100755 (executable)
index c7bb162..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<ul class="section-buttons">
-{% for object in object_list %}
-    {% url "catalogue_lessons" as lessons_url %}
-    <li class="box{{ object.order }}"><a href="{{ lessons_url }}#{{  object.slug }}"><span>{{ object }}</span></a></li>
-{% endfor %}
-</ul>
index a8d69e6..5166298 100755 (executable)
@@ -1,6 +1,8 @@
+from collections import defaultdict
 from django import template
 from django.utils.datastructures import SortedDict
 from ..models import Lesson, Section
+from curriculum.models import Level, CurriculumCourse
 from librarian.dcparser import WLURI, Person
 
 register = template.Library()
@@ -8,43 +10,58 @@ register = template.Library()
 
 @register.inclusion_tag("catalogue/snippets/carousel.html")
 def catalogue_carousel():
-    lessons_count = Lesson.objects.filter(type__in=('course', 'synthetic')).count()
-    if 1 < lessons_count % 10 < 5 and lessons_count / 10 % 10 != 1:
-        lessons_desc = u'kompletne lekcje'
-    else:
-        lessons_desc = u'kompletnych lekcji'
-    return locals()
-
-@register.inclusion_tag("catalogue/snippets/section_buttons.html")
-def catalogue_section_buttons():
     return {
         "object_list": Section.objects.all()
     }
 
-@register.inclusion_tag("catalogue/snippets/section_box.html")
-def section_box(section):
-    lessons = SortedDict()
+@register.inclusion_tag("catalogue/snippets/levels_main.html")
+def catalogue_levels_main():
+    object_list = Level.objects.exclude(lesson=None)
+    c = object_list.count()
+    return {
+        'object_list': object_list,
+        'section_width': (700 - 20 * (c - 1)) / c,
+    }
+
+
+@register.inclusion_tag("catalogue/snippets/level_box.html")
+def level_box(level):
+    lessons = dict(
+        synthetic = [],
+        course = SortedDict(),
+        project = [],
+    )
+    by_course = defaultdict(lambda: defaultdict(list))
+
     lesson_lists = [alist for alist in [
-        list(section.lesson_set.all()),
-        list(section.lessonstub_set.all())
+        list(level.lesson_set.exclude(type='appendix').order_by('section__order')),
+        list(level.lessonstub_set.all())
     ] if alist]
+
     while lesson_lists:
         min_index, min_list = min(enumerate(lesson_lists), key=lambda x: x[1][0].order)
         lesson = min_list.pop(0)
         if not min_list:
             lesson_lists.pop(min_index)
 
-        if lesson.level not in lessons:
-            newdict = SortedDict()
-            newdict['synthetic'] = []
-            newdict['course'] = []
-            lessons[lesson.level] = newdict
-        if lesson.type not in lessons[lesson.level]:
-            lessons[lesson.level][lesson.type] = []
-        lessons[lesson.level][lesson.type].append(lesson)
+        if lesson.type == 'course':
+            if lesson.section not in lessons['course']:
+                lessons['course'][lesson.section] = []
+            lessons['course'][lesson.section].append(lesson)
+        else:
+            lessons[lesson.type].append(lesson)
+
+        if hasattr(lesson, 'curriculum_courses'):
+            for course in lesson.curriculum_courses.all():
+                by_course[course][lesson.type].append(lesson)
+
+    courses = [(course, by_course[course]) for course in
+        CurriculumCourse.objects.filter(lesson__level=level).distinct()]
+
     return {
-        "section": section,
+        "level": level,
         "lessons": lessons,
+        "courses": courses,
     }
 
 @register.inclusion_tag("catalogue/snippets/lesson_nav.html")
@@ -52,17 +69,16 @@ def lesson_nav(lesson):
     if lesson.type == 'course':
         root = lesson.section
         siblings = Lesson.objects.filter(type='course', level=lesson.level, section=root)
-        mark_level = False
-        link_other_level = True
-    else:
+    elif lesson.type == 'appendix':
         root = None
         siblings = Lesson.objects.filter(type=lesson.type)
-        mark_level = link_other_level = lesson.type == 'course'
+    else:
+        root = None
+        siblings = Lesson.objects.filter(type=lesson.type, level=lesson.level)
     return {
         "lesson": lesson,
         "root": root,
         "siblings": siblings,
-        "mark_level": mark_level
     }
 
 @register.inclusion_tag("catalogue/snippets/lesson_link.html")
index 61e9e9a..3923f61 100755 (executable)
@@ -1,9 +1,9 @@
 from django.conf.urls import patterns, include, url
-from .views import SectionView, LessonView
+from .views import LessonListView, LessonView
 
 urlpatterns = patterns('',
     url(r'^$',
-        SectionView.as_view(),
+        LessonListView.as_view(),
         name="catalogue_lessons"),
     url(r'^(?P<slug>[^/]+)/$',
         LessonView.as_view(),
index 273bfa3..0ce7454 100644 (file)
@@ -2,16 +2,17 @@ import os.path
 from django.conf import settings
 from django.views.generic import DetailView, ListView
 from .models import Lesson, Section
+from curriculum.models import Level
+from publishers.models import Publisher
 
 
-class SectionView(ListView):
-    model = Section
+class LessonListView(ListView):
+    queryset = Level.objects.exclude(lesson=None)
+    template_name = "catalogue/lesson_list.html"
 
     def get_context_data(self, **kwargs):
-        context = super(SectionView, self).get_context_data(**kwargs)
+        context = super(LessonListView, self).get_context_data(**kwargs)
         context['appendix'] = Lesson.objects.filter(type='appendix')
-        context['package_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE)
-        context['package_student_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE_STUDENT)
         return context
 
 
@@ -23,4 +24,12 @@ class LessonView(DetailView):
             'catalogue/lesson/%s/lesson_detail.html' % self.object.type,
             'catalogue/lesson/lesson_detail.html',
         ]
-        
+
+    def get_context_data(self, **kwargs):
+        context = super(LessonView, self).get_context_data(**kwargs)
+        try:
+            context['publisher'] = Publisher.objects.get(
+                name=context['object'].dc.get('publisher', '').strip())
+        except:
+            pass
+        return context
index 8fa0149..b975da3 100644 (file)
@@ -1,7 +1,7 @@
 from django.contrib.sites.models import Site
 from django.core.files.uploadedfile import UploadedFile
 from django.core.mail import send_mail, mail_managers
-from django.core.validators import email_re
+from django.core.validators import validate_email
 from django import forms
 from django.template.loader import render_to_string
 from django.template import RequestContext
@@ -78,7 +78,7 @@ class ContactForm(forms.Form):
         mail_managers(mail_managers_subject, mail_managers_body, 
             fail_silently=True)
 
-        if email_re.match(contact.contact):
+        if validate_email(contact.contact):
             mail_subject = render_to_string([
                     'contact/%s/mail_subject.txt' % self.form_tag,
                     'contact/mail_subject.txt', 
diff --git a/curriculum/migrations/0010_auto__add_field_level_meta_name.py b/curriculum/migrations/0010_auto__add_field_level_meta_name.py
new file mode 100644 (file)
index 0000000..24fc996
--- /dev/null
@@ -0,0 +1,82 @@
+# -*- 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 'Level.meta_name'
+        db.add_column(u'curriculum_level', 'meta_name',
+                      self.gf('django.db.models.fields.CharField')(default=' ', max_length=255),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Level.meta_name'
+        db.delete_column(u'curriculum_level', 'meta_name')
+
+
+    models = {
+        u'curriculum.competence': {
+            'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        },
+        u'curriculum.competencelevel': {
+            'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'},
+            'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}),
+            'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"})
+        },
+        u'curriculum.curriculum': {
+            'Meta': {'object_name': 'Curriculum'},
+            'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.curriculumlevel': {
+            'Meta': {'object_name': 'CurriculumLevel'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'meta_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['curriculum']
\ No newline at end of file
diff --git a/curriculum/migrations/0011_meta_name.py b/curriculum/migrations/0011_meta_name.py
new file mode 100644 (file)
index 0000000..0539ae7
--- /dev/null
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        "Write your forwards methods here."
+        orm.Level.objects.all().update(meta_name=models.F('slug'))
+
+    def backwards(self, orm):
+        "Write your backwards methods here."
+
+    models = {
+        u'curriculum.competence': {
+            'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        },
+        u'curriculum.competencelevel': {
+            'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'},
+            'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}),
+            'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"})
+        },
+        u'curriculum.curriculum': {
+            'Meta': {'object_name': 'Curriculum'},
+            'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.curriculumlevel': {
+            'Meta': {'object_name': 'CurriculumLevel'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'meta_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['curriculum']
+    symmetrical = True
diff --git a/curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py b/curriculum/migrations/0012_auto__add_unique_level_meta_name__add_unique_level_slug.py
new file mode 100644 (file)
index 0000000..f9fa032
--- /dev/null
@@ -0,0 +1,86 @@
+# -*- 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 unique constraint on 'Level', fields ['meta_name']
+        db.create_unique(u'curriculum_level', ['meta_name'])
+
+        # Adding unique constraint on 'Level', fields ['slug']
+        db.create_unique(u'curriculum_level', ['slug'])
+
+
+    def backwards(self, orm):
+        # Removing unique constraint on 'Level', fields ['slug']
+        db.delete_unique(u'curriculum_level', ['slug'])
+
+        # Removing unique constraint on 'Level', fields ['meta_name']
+        db.delete_unique(u'curriculum_level', ['meta_name'])
+
+
+    models = {
+        u'curriculum.competence': {
+            'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        },
+        u'curriculum.competencelevel': {
+            'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'},
+            'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}),
+            'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"})
+        },
+        u'curriculum.curriculum': {
+            'Meta': {'object_name': 'Curriculum'},
+            'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.curriculumlevel': {
+            'Meta': {'object_name': 'CurriculumLevel'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'meta_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+        },
+        u'curriculum.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['curriculum']
\ No newline at end of file
diff --git a/curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py b/curriculum/migrations/0013_auto__add_field_level_package__add_field_level_student_package.py
new file mode 100644 (file)
index 0000000..4e0ee70
--- /dev/null
@@ -0,0 +1,92 @@
+# -*- 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 'Level.package'
+        db.add_column(u'curriculum_level', 'package',
+                      self.gf('django.db.models.fields.files.FileField')(max_length=255, null=True, blank=True),
+                      keep_default=False)
+
+        # Adding field 'Level.student_package'
+        db.add_column(u'curriculum_level', 'student_package',
+                      self.gf('django.db.models.fields.files.FileField')(max_length=255, null=True, blank=True),
+                      keep_default=False)
+
+
+    def backwards(self, orm):
+        # Deleting field 'Level.package'
+        db.delete_column(u'curriculum_level', 'package')
+
+        # Deleting field 'Level.student_package'
+        db.delete_column(u'curriculum_level', 'student_package')
+
+
+    models = {
+        u'curriculum.competence': {
+            'Meta': {'ordering': "['section', 'order']", 'object_name': 'Competence'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'section': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Section']"}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        },
+        u'curriculum.competencelevel': {
+            'Meta': {'ordering': "['competence', 'level']", 'object_name': 'CompetenceLevel'},
+            'competence': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Competence']"}),
+            'description_en': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            'description_pl': ('django.db.models.fields.TextField', [], {'default': "''"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.Level']"})
+        },
+        u'curriculum.curriculum': {
+            'Meta': {'object_name': 'Curriculum'},
+            'course': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumCourse']"}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['curriculum.CurriculumLevel']"}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+        },
+        u'curriculum.curriculumcourse': {
+            'Meta': {'ordering': "['slug']", 'object_name': 'CurriculumCourse'},
+            'accusative': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+        },
+        u'curriculum.curriculumlevel': {
+            'Meta': {'object_name': 'CurriculumLevel'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'})
+        },
+        u'curriculum.level': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Level'},
+            'group_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'group_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'meta_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'slug': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+            'student_package': ('django.db.models.fields.files.FileField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        u'curriculum.section': {
+            'Meta': {'ordering': "['order']", 'object_name': 'Section'},
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name_en': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'name_pl': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
+            'order': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
+        }
+    }
+
+    complete_apps = ['curriculum']
\ No newline at end of file
index b53d2ca..b4d8ac4 100644 (file)
@@ -22,7 +22,7 @@ class Section(models.Model):
 
     def url_for_level(self, level):
         return "%s?s=%d&level=%s&d=1" % (reverse("curriculum"), self.pk, level.slug)
-        
+
 add_translatable(Section, {
     'name': models.CharField(_('name'), max_length=255, default = '')
 })
@@ -66,8 +66,13 @@ add_translatable(Competence, {
 
 
 class Level(models.Model):
-    slug = models.CharField(_('slug'), max_length=255)
+    slug = models.CharField(_('slug'), max_length=255, unique=True)
+    meta_name = models.CharField(_('meta name'), max_length=255, unique=True)
     order = models.IntegerField(_('order'))
+    package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s.zip" % i.slug,
+        null=True, blank=True, max_length=255)
+    student_package = models.FileField(upload_to=lambda i, f: "curriculum/pack/edukacjamedialna_%s_uczen.zip" % i.slug,
+        null=True, blank=True, max_length=255)
 
     class Meta:
         ordering = ['order']
@@ -77,6 +82,48 @@ class Level(models.Model):
     def __unicode__(self):
         return self.name
 
+    def length_course(self):
+        return self.lesson_set.filter(type='course').count()
+
+    def length_synthetic(self):
+        return self.lesson_set.filter(type='synthetic').count()
+
+    def build_package(self, student):
+        from StringIO import StringIO
+        import zipfile
+        from django.core.files.base import ContentFile
+        from catalogue.templatetags.catalogue_tags import section_box
+        from catalogue.models import Lesson
+
+        buff = StringIO()
+        zipf = zipfile.ZipFile(buff, 'w', zipfile.ZIP_STORED)
+
+        lessons = section_box(self)['lessons']
+        for i, lesson in enumerate(lessons['synthetic']):
+            prefix = 'Skrocony kurs/%d %s/' % (i, lesson.slug)
+            lesson.add_to_zip(zipf, student, prefix)
+        for c, (section, clessons) in enumerate(lessons['course'].items()):
+            for i, lesson in enumerate(clessons):
+                prefix = 'Pelny kurs/%d %s/%d %s/' % (c, section.slug, i, lesson.slug)
+                lesson.add_to_zip(zipf, student, prefix)
+        for i, lesson in enumerate(lessons['project']):
+            prefix = 'Kurs skrocony/%d %s/' % (i, lesson.slug)
+            lesson.add_to_zip(zipf, student, prefix)
+        # Add all appendix lessons, from all levels.
+        for lesson in Lesson.objects.exclude(type__in=('synthetic', 'course', 'project')):
+            prefix = '%s/' % lesson.slug
+            lesson.add_to_zip(zipf, student, prefix)
+        zipf.close()
+
+        fieldname = "student_package" if student else "package"
+        getattr(self, fieldname).save(None, ContentFile(buff.getvalue()))
+
+    def build_packages(self):
+        self.build_package(False)
+        self.build_package(True)
+
+
+
 add_translatable(Level, {
     'name': models.CharField(_('name'), max_length=255, default = ''),
     'group': models.CharField(_('group'), max_length=255, default = '')
index db6d484..a2000b7 100755 (executable)
@@ -1,10 +1,14 @@
 {% url "catalogue_lessons" as lessons_url %}
-{% for course in object_list %}
-<li><a href="{{ lessons_url }}#{{ course.slug }}">
-    {% if accusative %}
-        {{ course.accusative }}
-    {% else %}
-        {{ course }}
-    {% endif %}
-</a></li>
+{% for level, course_list in object_list %}
+<section class="levelth" style="float: left;">{{ level }}:
+<ul class="link-list">
+        {% for course in course_list %}
+            <li><a href="{{ lessons_url }}#{{ level.slug }}_{{ course.slug }}">
+            {% if accusative %}
+                {{ course.accusative }}{% else %}
+                {{ course|lower }}{% endif %}</a>{% if not forloop.last %}, {% else %}.{% endif %}
+                </li>
+        {% endfor %}
+</ul>
+</section>
 {% endfor %}
index 986271c..4e02e04 100755 (executable)
@@ -1,6 +1,7 @@
 from django import template
 from django.utils.datastructures import SortedDict
 from ..models import Competence, Curriculum, CurriculumCourse
+from catalogue.models import Lesson
 
 register = template.Library()
 
@@ -19,7 +20,7 @@ def competence(texts, level):
 @register.inclusion_tag("curriculum/snippets/curriculum.html")
 def curriculum(identifiers):
     try:
-        currs = [Curriculum.objects.get(identifier=identifier)
+        currs = [Curriculum.objects.get(identifier__iexact=identifier.replace(' ', ''))
                     for identifier in identifiers]
     except Curriculum.DoesNotExist:
         return {'identifiers': identifiers}
@@ -70,7 +71,18 @@ def course_boxes():
 
 @register.inclusion_tag("curriculum/snippets/course_boxes_toc.html")
 def course_boxes_toc(accusative=False):
+    last = None, None
+    object_list = []
+    for l in Lesson.curriculum_courses.through.objects.all().order_by(
+            'lesson__level', 'curriculumcourse'):
+        level, course = l.lesson.level, l.curriculumcourse
+        if (level, course) == last:
+            continue
+        if level != last[0]:
+            object_list.append((level, []))
+        object_list[-1][1].append(course)
+        last = (level, course)
     return {
-        'object_list': CurriculumCourse.objects.all(),
+        'object_list': object_list,
         'accusative': accusative,
     }
index 7091ff1..ee80ab7 100644 (file)
@@ -3,12 +3,13 @@ INSTALLED_APPS = (
     'curriculum',
     'catalogue',
     'comment',
+    'publishers',
 
     'fnpdjango',
     'south',
     'pipeline',
     # Disable, if not using Piwik.
-    'piwik.django',
+    'piwik',
     # Disable, if not using CAS.
     'honeypot',
     'django_cas',
index 998b707..bb7401f 100644 (file)
@@ -15,8 +15,6 @@ MIDDLEWARE_CLASSES = tuple(x for x in (
             if "django_cas" in INSTALLED_APPS else None,
     'django.contrib.messages.middleware.MessageMiddleware'
             if "django.contrib.messages" in INSTALLED_APPS else None,
-    'piwik.django.middleware.PiwikMiddleware'
-            if "piwik.django" in INSTALLED_APPS else None,
     # Uncomment the next line for simple clickjacking protection:
     # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'pagination.middleware.PaginationMiddleware'
index 64770e8..e5b3dee 100644 (file)
@@ -11,3 +11,6 @@ PYBB_ENABLE_ANONYMOUS_POST = False
 PYBB_DEFAULT_TITLE = u'Forum'
 PYBB_DEFAULT_TIME_ZONE = 1
 PYBB_PERMISSION_HANDLER = 'edumed.forum.ForumPermissionHandler'
+
+THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine'
+THUMBNAIL_CONVERT = 'convert -density 300 -background white -flatten -alpha off'
index 43dbb7c..7cdd26c 100644 (file)
@@ -39,8 +39,10 @@ PIPELINE_JS = {
             'catalogue/js/jquery.cycle.all.js',
             'jquery/colorbox/jquery.colorbox-min.js',
             'jquery/colorbox/jquery.colorbox-pl.js',
+            'catalogue/js/carousel.js',
             'catalogue/js/edumed.js',
             'catalogue/js/lesson.js',
+            'catalogue/js/lesson-list.js',
             'sponsors/js/sponsors.js',
             'curriculum/curriculum.js',
             'js/formset.js',
index 758819b..869e6f4 100644 (file)
@@ -1,3 +1 @@
-CATALOGUE_PACKAGE = "catalogue/edukacjamedialna.zip"
-CATALOGUE_PACKAGE_STUDENT = "catalogue/edukacjamedialna_uczen.zip"
 CONTACT_FORMS_MODULE = 'edumed.contact_forms'
index 4fecbb1..ffb78d9 100644 (file)
@@ -1,10 +1,10 @@
 #main-promobox {
   float: right;
-  border-radius: 0.938em;
+  border-radius: 0.9375em;
   background: #16a487;
   padding: 1.5em 1.25em;
   width: 11.25em;
-  height: 11.688em; }
+  height: 11.6875em; }
   #main-promobox a {
     display: block; }
   #main-promobox h1 {
   width: 43.75em; }
   #main-sections h1 {
     font-size: .9em;
-    margin: 0 0 0 1.6em;
+    margin: 0 0 0 1.25em;
     text-transform: uppercase; }
   #main-sections ul {
-    margin: -0.188em 0 0 -1.25em;
+    margin: -0.1875em 0 0 -1.25em;
     padding: 0;
     list-style: none; }
     #main-sections ul li {
       margin-top: 1.25em;
       margin-left: 1.25em;
       float: left;
-      width: 10em;
       height: 5.625em;
-      border-radius: 0.938em; }
+      border-radius: 0.9375em; }
       #main-sections ul li a {
         color: white;
         text-transform: uppercase;
         display: block;
         height: 5em;
-        width: 9.375em;
         display: table;
-        padding: 0.313em; }
-        #main-sections ul li a span {
+        padding: 5px; }
+        #main-sections ul li a .in-box {
           font-size: .9em;
           height: 100%;
           width: 100%;
           border: 1px solid transparent;
           border-radius: 0.625em;
           padding-left: 1em; }
-      #main-sections ul li a:hover span {
+          #main-sections ul li a .in-box .name {
+            display: block;
+            font-size: 1.5em;
+            line-height: 1em;
+            margin-bottom: .2em; }
+      #main-sections ul li a:hover .in-box {
         border: 1px solid white; }
     #main-sections ul .box1 {
       background-color: #adaeaf; }
@@ -76,7 +79,7 @@
     #main-sections ul .box4 {
       background-color: #5e6165; }
     #main-sections ul .box5 {
-      background-color: #16a487; }
+      background-color: #f8b323; }
     #main-sections ul .box6 {
       background-color: #363a3e; }
     #main-sections ul .box7 {
     #main-sections ul .box8 {
       background-color: #ed7831; }
 
-#main-chosen {
+#main-howto {
   float: right;
   margin-top: 1.2em;
   width: 13.75em; }
-  #main-chosen h1 {
+  #main-howto h1 {
     font-size: .9em;
     margin: 0 0 0 1.4em;
     text-transform: uppercase; }
-  #main-chosen ul {
-    margin: 1.063em 0 0 1.4em; }
-    #main-chosen ul li {
+  #main-howto ul {
+    margin: 1.0625em 0 1.0625em 1.4em; }
+    #main-howto ul li {
       font-size: .9em;
       text-transform: uppercase;
       line-height: 1.25em; }
+    #main-howto ul a:before {
+      height: 1.25em; }
+    #main-howto ul .knowledge:before {
+      content: url(/static/img/icons/knowledge_dark.png); }
+    #main-howto ul .activity:before {
+      content: url(/static/img/icons/activity_dark.png); }
+    #main-howto ul .lesson-plan:before {
+      content: url(/static/img/icons/lesson-plan_dark.png); }
+    #main-howto ul .reference:before {
+      content: url(/static/img/icons/reference_dark.png); }
+    #main-howto ul .knowledge:hover:before {
+      content: url(/static/img/icons/knowledge_orange.png); }
+    #main-howto ul .activity:hover:before {
+      content: url(/static/img/icons/activity_orange.png); }
+    #main-howto ul .lesson-plan:hover:before {
+      content: url(/static/img/icons/lesson-plan_orange.png); }
+    #main-howto ul .reference:hover:before {
+      content: url(/static/img/icons/reference_orange.png); }
+  #main-howto p {
+    margin: 0 0 1.875em 1.4em; }
+
+#main-chosen {
+  clear: left;
+  float: left;
+  margin-top: 2em; }
+  #main-chosen h1 {
+    font-size: .9em;
+    margin: 0 0 1em 1.25em;
+    text-transform: uppercase; }
+  #main-chosen .levelth {
+    margin-left: 1.25em; }
 
 #main-tools {
   clear: both; }
index e956c81..54b2d35 100755 (executable)
@@ -48,7 +48,7 @@ $px: .0625em;
 
     h1 {
         font-size: .9em;
-        margin: 0 0 0 1.6em;
+        margin: 0 0 0 20*$px;
         text-transform: uppercase;
     }
 
@@ -61,7 +61,6 @@ $px: .0625em;
             margin-top: 20*$px;
             margin-left: 20*$px;
             float: left;
-            width: 160*$px;
             height: 90*$px;
             border-radius: 15*$px;
 
@@ -70,11 +69,10 @@ $px: .0625em;
                 text-transform: uppercase;
                 display: block;
                 height: 80*$px;
-                width: 150*$px;
                 display: table;
-                padding: 5*$px;
+                padding: 5px;
 
-                span {
+                .in-box {
                     font-size: .9em;
                     height: 100%;
                     width: 100%;
@@ -83,9 +81,16 @@ $px: .0625em;
                     border: 1px solid transparent;
                     border-radius: 10*$px;
                     padding-left: 16*$px;
+
+                    .name {
+                        display: block;
+                        font-size: 1.5em;
+                        line-height: 1em;
+                        margin-bottom: .2em;
+                    }
                 }
             }
-            a:hover span {
+            a:hover .in-box {
                 border: 1px solid white;
             }
         }
@@ -93,14 +98,15 @@ $px: .0625em;
         .box2 {background-color: #f8b323;}
         .box3 {background-color: #16a487;}
         .box4 {background-color: #5e6165;}
-        .box5 {background-color: #16a487;}
+        // .box5 {background-color: #16a487;}
+        .box5 {background-color: #f8b323;}
         .box6 {background-color: #363a3e;}
         .box7 {background-color: #adaeaf;}
         .box8 {background-color: #ed7831;}
     }
 }
 
-#main-chosen {
+#main-howto {
     float: right;
     margin-top: 1.2em;
     width: 220*$px;
@@ -112,13 +118,45 @@ $px: .0625em;
     }
 
     ul {
-        margin: 17*$px 0 0 1.4em;;
+        margin: 17*$px 0 17*$px 1.4em;
 
         li {
             font-size: .9em;
             text-transform: uppercase;
             line-height: 1.25em;
         }
+        a:before {
+            height: 20*$px;
+        }
+
+        .knowledge:before {content: url(/static/img/icons/knowledge_dark.png);}
+        .activity:before {content: url(/static/img/icons/activity_dark.png);}
+        .lesson-plan:before {content: url(/static/img/icons/lesson-plan_dark.png);}
+        .reference:before {content: url(/static/img/icons/reference_dark.png);}
+        .knowledge:hover:before {content: url(/static/img/icons/knowledge_orange.png);}
+        .activity:hover:before {content: url(/static/img/icons/activity_orange.png);}
+        .lesson-plan:hover:before {content: url(/static/img/icons/lesson-plan_orange.png);}
+        .reference:hover:before {content: url(/static/img/icons/reference_orange.png);}
+
+    }
+    p {
+        margin: 0 0 30*$px 1.4em;
+    }
+}
+
+#main-chosen {
+    clear: left;
+    float: left;
+    margin-top: 2em;
+
+    h1 {
+        font-size: .9em;
+        margin: 0 0 1em 20*$px;
+        text-transform: uppercase;
+    }
+
+    .levelth {
+        margin-left: 20*$px;
     }
 }
 
diff --git a/edumed/static/img/icons/internet_black.png b/edumed/static/img/icons/internet_black.png
new file mode 100644 (file)
index 0000000..538e60b
Binary files /dev/null and b/edumed/static/img/icons/internet_black.png differ
diff --git a/edumed/static/img/icons/nointernet_black.png b/edumed/static/img/icons/nointernet_black.png
new file mode 100644 (file)
index 0000000..9977783
Binary files /dev/null and b/edumed/static/img/icons/nointernet_black.png differ
index f4a3c27..9607254 100644 (file)
@@ -3,6 +3,7 @@
 {% load fnp_common fnp_share fnp_lang macros %}
 {% load compressed static %}
 {% load subdomainurls %}
+{% load piwik_tags %}
 
 {% macro title %}{% block title %}{% endblock %}{% endmacro %}
 {% macro site_name %}Edukacja medialna{% endmacro %}
@@ -98,6 +99,6 @@
     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
     {% compressed_js 'base' %}
     {% block extra_script %}{% endblock %}
-    {{ piwik_tag|safe }}
+    {% tracking_code %}
     </body>
 </html>
index 3a82a7b..ce81ed9 100755 (executable)
 
 <section id="main-sections">
 <h1>Lekcje:</h1>
-{% catalogue_section_buttons %}
+{% catalogue_levels_main %}
 </section>
 
-<section id="main-chosen">
-<h1>Wybrane tematy na:</h1>
+<section id="main-howto">
+<h1>Nasze lekcje to:</h1>
 <ul class="link-list">
-{% course_boxes_toc 1 %}
+    <li><a class="knowledge" href="/info/jak-korzystac/#wiedza-w-pigulce">wiedza w pigułce</a></li>
+    <li><a class="activity" href="/info/jak-korzystac/#zadania">zadania</a></li>
+    <li><a class="lesson-plan" href="/info/jak-korzystac/#scenariusze">scenariusze</a></li>
+    <li><a class="reference" href="/info/jak-korzystac/#slowniczek">słowniczek</a></li>
 </ul>
+<p>Zobacz, <a href="{% url 'info' 'dobre-praktyki' %}">jak przeprowadzili je inni.</a></p>
+
+{# <iframe width="220" height="124" src="//www.youtube.com/embed/______?controls=2&amp;rel=0&amp;showinfo=0&amp;theme=light" frameborder="0" allowfullscreen></iframe> #}
+</section>
+
+<section id="main-chosen">
+<h1>Według podstawy programowej:</h1>
+{% course_boxes_toc %}
 </section>
 
+
 <section id="main-tools">
 
 <section class="main-tools-box">
@@ -39,8 +51,6 @@
 <ul class="link-list">
     <li><a href="{% url 'contact_form' 'sugestie' %}">Zgłoś błąd lub sugestię</a></li>
     <li><a href="{% url 'info' 'jak-korzystac/' %}">Jak korzystać?</a></li>
-    <li><a href="{{ package_url }}">Pobierz wszystkie lekcje</a></li>
-    <li><a href="{{ package_student_url }}">Pobierz wszystkie lekcje w&nbsp;wersji dla ucznia</a></li>
     <li><a href="{% url 'catalogue_lesson' 'slowniczek' %}">Słowniczek</a></li>
     <li><a href="{% url 'catalogue_lesson' 'metody' %}">Metody edukacyjne</a></li>
     {% if request.user.is_authenticated %}<li><a href="{% url 'pybb:index' %}">Forum</a></li>{% endif %}
@@ -55,7 +65,3 @@
 
 {% endblock %}
 
-
-{% block footer_extra %}
-    <p>Wykorzystano zdjęcie autorstwa Katarzyny Włodarczyk, udostępnione na wolnej licencji CC BY-SA.</p>
-{% endblock %}
index 5ac002b..712570d 100755 (executable)
@@ -10,13 +10,6 @@ from .forms import AvatarlessEditProfileForm
 class HomeView(TemplateView):
     template_name="home.html"
 
-    def get_context_data(self, **kwargs):
-        context = super(HomeView, self).get_context_data(**kwargs)
-        context['package_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE)
-        context['package_student_url'] = os.path.join(settings.MEDIA_URL, settings.CATALOGUE_PACKAGE_STUDENT)
-        return context
-
-
 def mil_home_view(request):
     return flatpage(request, url = '/' if request.LANGUAGE_CODE == 'pl' else '/en/')
 
index 530e990..eea64b5 100644 (file)
@@ -1,10 +1,10 @@
 -i http://pypi.nowoczesnapolska.org.pl/simple
 
-Django>=1.5,<1.6
+Django>=1.6,<1.7
 South>=0.7.4
 django-pipeline>=1.2,<1.3
 python-memcached
-piwik
+django-piwik
 #pyScss
 #git+git://github.com/Kronuz/pyScss.git@d8f4da23a3c87696a75b3830ed4ab49b75550a93#egg=pyScss
 #TODO: pyScss support, for now just install sass