from catalogue import models
class BookAdmin(admin.ModelAdmin):
+ list_display = ['title', 'public', '_published', '_new_publishable', 'project']
+ list_filter = ['public', '_published', '_new_publishable', 'project']
prepopulated_fields = {'slug': ['title']}
search_fields = ['title']
+ admin.site.register(models.Project)
admin.site.register(models.Book, BookAdmin)
admin.site.register(models.Chunk)
-
admin.site.register(models.Chunk.tag_model)
+
+admin.site.register(models.Image)
+admin.site.register(models.Image.tag_model)
from django.utils.translation import ugettext_lazy as _
from catalogue.constants import MASTERS
-from catalogue.models import Book, Chunk
+from catalogue.models import Book, Chunk, Image
class DocumentCreateForm(forms.ModelForm):
"""
class Meta:
model = Book
- exclude = ['parent', 'parent_number']
+ exclude = ['parent', 'parent_number', 'project']
def __init__(self, *args, **kwargs):
super(DocumentCreateForm, self).__init__(*args, **kwargs)
"""
user = forms.ModelChoiceField(queryset=
User.objects.annotate(count=Count('chunk')).
- order_by('-count', 'last_name', 'first_name'), required=False,
+ order_by('last_name', 'first_name'), required=False,
label=_('Assigned to'))
class Meta:
class Meta:
model = Book
+ exclude = ['project']
def __init__(self, *args, **kwargs):
ret = super(BookForm, self).__init__(*args, **kwargs)
def __init__(self, *args, **kwargs):
ret = super(ReadonlyBookForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
- field.widget.attrs.update({"readonly": True})
+ field.widget.attrs.update({"disabled": "disabled"})
return ret
"""
master = forms.ChoiceField(choices=((m, m) for m in MASTERS))
+
+
+class ImageForm(forms.ModelForm):
+ """Form used for editing an Image."""
+ user = forms.ModelChoiceField(queryset=
+ User.objects.annotate(count=Count('chunk')).
+ order_by('-count', 'last_name', 'first_name'), required=False,
+ label=_('Assigned to'))
+
+ class Meta:
+ model = Image
+ fields = ['title', 'slug', 'user', 'stage']
+
+ def __init__(self, *args, **kwargs):
+ super(ImageForm, self).__init__(*args, **kwargs)
+ self.fields['slug'].widget.attrs={'class': 'autoslug'}
+ self.fields['title'].widget.attrs={'class': 'autoslug-source'}
+
+
+class ReadonlyImageForm(ImageForm):
+ """Form used for not editing a Book."""
+
+ def __init__(self, *args, **kwargs):
+ ret = super(ReadonlyImageForm, self).__init__(*args, **kwargs)
+ for field in self.fields.values():
+ field.widget.attrs.update({"disabled": "disabled"})
+ return ret
msgstr ""
"Project-Id-Version: Platforma Redakcyjna\n"
"Report-Msgid-Bugs-To: \n"
- "POT-Creation-Date: 2011-12-21 12:44+0100\n"
- "PO-Revision-Date: 2011-12-21 12:45+0100\n"
-"POT-Creation-Date: 2013-07-16 13:22+0200\n"
-"PO-Revision-Date: 2013-07-16 13:22+0100\n"
++"POT-Creation-Date: 2014-03-26 16:13+0100\n"
++"PO-Revision-Date: 2014-03-26 16:14+0100\n"
"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
- "Language-Team: Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org.pl>\n"
+ "Language-Team: Fundacja Nowoczesna Polska <fundacja@nowoczesnapolska.org."
+ "pl>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
- "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+ "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+ "|| n%100>=20) ? 1 : 2);\n"
+ "X-Generator: Poedit 1.5.4\n"
#: forms.py:39
msgid "Text file must be UTF-8 encoded."
msgid "Directories are documents in chunks"
msgstr "Katalogi zawierają dokumenty w częściach"
--#: forms.py:76
- #: forms.py:164
++#: forms.py:76 forms.py:165
msgid "Assigned to"
msgstr "Przypisane do"
- #: forms.py:97
- #: forms.py:111
+ #: forms.py:97 forms.py:111
msgid "Chunk with this slug already exists"
msgstr "Część z tym slugiem już istnieje"
msgid "Append to"
msgstr "Dołącz do"
- #: views.py:165
-#: views.py:160
++#: views.py:166
#, python-format
msgid "Slug already used for %s"
msgstr "Slug taki sam jak dla pliku %s"
- #: views.py:167
-#: views.py:162
++#: views.py:168
msgid "Slug already used in repository."
msgstr "Dokument o tym slugu już istnieje w repozytorium."
- #: views.py:173
-#: views.py:168
++#: views.py:174
msgid "File should be UTF-8 encoded."
msgstr "Plik powinien mieć kodowanie UTF-8."
- #: models/book.py:21
- #: models/chunk.py:23
- #: models/image.py:21
-#: views.py:498 models/book.py:56
++#: views.py:552 models/book.py:56
+ msgid "books"
+ msgstr "książki"
+
-#: views.py:500
++#: views.py:554
+ msgid "scan gallery"
+ msgstr "galeria skanów"
+
-#: models/book.py:28 models/chunk.py:23
++#: models/book.py:28 models/chunk.py:23 models/image.py:21
msgid "title"
msgstr "tytuł"
- #: models/book.py:22
- #: models/chunk.py:24
- #: models/image.py:22
-#: models/book.py:29 models/chunk.py:24
++#: models/book.py:29 models/chunk.py:24 models/image.py:22
msgid "slug"
msgstr "slug"
- #: models/book.py:23
- #: models/image.py:23
-#: models/book.py:30
++#: models/book.py:30 models/image.py:23
msgid "public"
msgstr "publiczna"
- #: models/book.py:24
+ #: models/book.py:31
msgid "scan gallery name"
msgstr "nazwa galerii skanów"
- #: models/book.py:27
+ #: models/book.py:35
msgid "parent"
msgstr "rodzic"
- #: models/book.py:28
+ #: models/book.py:36
msgid "parent number"
msgstr "numeracja rodzica"
- #: models/book.py:44
- #: models/chunk.py:21
- #: models/publish_log.py:17
+ #: models/book.py:55 models/chunk.py:21 models/publish_log.py:17
msgid "book"
msgstr "książka"
- #: models/book.py:45
- msgid "books"
- msgstr "książki"
-
- #: models/book.py:220
+ #: models/book.py:255
msgid "No chunks in the book."
msgstr "Książka nie ma części."
- #: models/book.py:224
+ #: models/book.py:259
msgid "Not all chunks have publishable revisions."
msgstr "Niektóre części nie są gotowe do publikacji."
- #: models/book.py:233
- #: models/image.py:80
-#: models/book.py:266
++#: models/book.py:266 models/image.py:80
msgid "Invalid XML"
msgstr "Nieprawidłowy XML"
- #: models/book.py:235
- #: models/image.py:82
-#: models/book.py:268
++#: models/book.py:268 models/image.py:82
msgid "No Dublin Core found."
msgstr "Brak sekcji Dublin Core."
- #: models/book.py:237
- #: models/image.py:84
-#: models/book.py:270
++#: models/book.py:270 models/image.py:84
msgid "Invalid Dublin Core"
msgstr "Nieprawidłowy Dublin Core"
- #: models/book.py:240
- #: models/image.py:88
-#: models/book.py:273
++#: models/book.py:273 models/image.py:88
msgid "rdf:about is not"
msgstr "rdf:about jest różny od"
msgid "chunks"
msgstr "części"
- #: models/image.py:20
- #: models/image.py:34
- #: models/publish_log.py:45
++#: models/image.py:20 models/image.py:34 models/publish_log.py:45
+msgid "image"
+msgstr "obraz"
+
+#: models/image.py:35
+msgid "images"
+msgstr "obrazy"
+
+#: models/image.py:73
+msgid "There is no publishable revision"
+msgstr "Żadna wersja nie została oznaczona do publikacji."
+
- #: models/publish_log.py:18
- #: models/publish_log.py:46
+ #: models/project.py:13
+ msgid "name"
+ msgstr "nazwa"
+
+ #: models/project.py:14
+ msgid "notes"
+ msgstr "notatki"
+
-#: models/project.py:19 templates/catalogue/book_list/book_list.html:62
++#: models/project.py:19 templates/catalogue/book_list/book_list.html:64
+ msgid "project"
+ msgstr "projekt"
+
+ #: models/project.py:20
+ msgid "projects"
+ msgstr "projekty"
+
-#: models/publish_log.py:18
++#: models/publish_log.py:18 models/publish_log.py:46
msgid "time"
msgstr "czas"
- #: models/publish_log.py:19
- #: models/publish_log.py:47
- #: templates/catalogue/wall.html:18
-#: models/publish_log.py:19 templates/catalogue/wall.html:18
++#: models/publish_log.py:19 models/publish_log.py:47
++#: templates/catalogue/wall.html:19
msgid "user"
msgstr "użytkownik"
- #: models/publish_log.py:24
- #: models/publish_log.py:33
+ #: models/publish_log.py:24 models/publish_log.py:33
msgid "book publish record"
msgstr "zapis publikacji książki"
msgid "book publish records"
msgstr "zapisy publikacji książek"
--#: models/publish_log.py:34
- #: models/publish_log.py:48
++#: models/publish_log.py:34 models/publish_log.py:48
msgid "change"
msgstr "zmiana"
msgid "chunk publish records"
msgstr "zapisy publikacji części"
-#: templates/catalogue/activity.html:9 templatetags/catalogue.py:29
+#: models/publish_log.py:53
+msgid "image publish record"
+msgstr "zapis publikacji obrazu"
+
+#: models/publish_log.py:54
+msgid "image publish records"
+msgstr "zapisy publikacji obrazów"
+
- #: templates/catalogue/activity.html:10
++#: templates/catalogue/activity.html:6 templates/catalogue/activity.html:12
+#: templatetags/catalogue.py:29
msgid "Activity"
msgstr "Aktywność"
msgid "Platforma Redakcyjna"
msgstr "Platforma Redakcyjna"
--#: templates/catalogue/book_append_to.html:9
++#: templates/catalogue/book_append_to.html:4
++#: templates/catalogue/book_append_to.html:11
msgid "Append book"
msgstr "Dołącz książkę"
--#: templates/catalogue/book_detail.html:14
- #: templates/catalogue/book_edit.html:9
- #: templates/catalogue/chunk_edit.html:13
- #: templates/catalogue/image_detail.html:14
-#: templates/catalogue/book_edit.html:9 templates/catalogue/chunk_edit.html:12
++#: templates/catalogue/book_detail.html:18
++#: templates/catalogue/book_edit.html:13
++#: templates/catalogue/chunk_edit.html:16
++#: templates/catalogue/image_detail.html:18
msgid "Save"
msgstr "Zapisz"
--#: templates/catalogue/book_detail.html:21
++#: templates/catalogue/book_detail.html:25
+ msgid "Edit gallery"
+ msgstr "Edytuj galerię"
+
-#: templates/catalogue/book_detail.html:24
++#: templates/catalogue/book_detail.html:28
msgid "Append to other book"
msgstr "Dołącz do innej książki"
- #: templates/catalogue/book_detail.html:27
-#: templates/catalogue/book_detail.html:30
++#: templates/catalogue/book_detail.html:34
msgid "Chunks"
msgstr "Części"
- #: templates/catalogue/book_detail.html:42
- #: templates/catalogue/image_detail.html:32
- #: templatetags/wall.py:78
-#: templates/catalogue/book_detail.html:45 templatetags/wall.py:78
++#: templates/catalogue/book_detail.html:49
++#: templates/catalogue/image_detail.html:36 templatetags/wall.py:78
msgid "Publication"
msgstr "Publikacja"
- #: templates/catalogue/book_detail.html:44
- #: templates/catalogue/image_detail.html:34
-#: templates/catalogue/book_detail.html:54
++#: templates/catalogue/book_detail.html:58
++#: templates/catalogue/image_detail.html:38
msgid "Last published"
msgstr "Ostatnio opublikowano"
- #: templates/catalogue/book_detail.html:54
-#: templates/catalogue/book_detail.html:64
++#: templates/catalogue/book_detail.html:68
msgid "Full XML"
msgstr "Pełny XML"
- #: templates/catalogue/book_detail.html:55
-#: templates/catalogue/book_detail.html:65
++#: templates/catalogue/book_detail.html:69
msgid "HTML version"
msgstr "Wersja HTML"
- #: templates/catalogue/book_detail.html:56
-#: templates/catalogue/book_detail.html:66
++#: templates/catalogue/book_detail.html:70
msgid "TXT version"
msgstr "Wersja TXT"
- #: templates/catalogue/book_detail.html:57
-#: templates/catalogue/book_detail.html:67
++#: templates/catalogue/book_detail.html:71
msgid "PDF version"
msgstr "Wersja PDF"
- #: templates/catalogue/book_detail.html:58
-#: templates/catalogue/book_detail.html:68
++#: templates/catalogue/book_detail.html:72
msgid "EPUB version"
msgstr "Wersja EPUB"
- #: templates/catalogue/book_detail.html:71
- #: templates/catalogue/image_detail.html:53
-#: templates/catalogue/book_detail.html:81
++#: templates/catalogue/book_detail.html:85
++#: templates/catalogue/image_detail.html:57
msgid "Publish"
msgstr "Opublikuj"
- #: templates/catalogue/book_detail.html:75
- #: templates/catalogue/image_detail.html:57
-#: templates/catalogue/book_detail.html:85
++#: templates/catalogue/book_detail.html:89
++#: templates/catalogue/image_detail.html:61
msgid "Log in to publish."
msgstr "Zaloguj się, aby opublikować."
- #: templates/catalogue/book_detail.html:78
- #: templates/catalogue/image_detail.html:60
-#: templates/catalogue/book_detail.html:88
++#: templates/catalogue/book_detail.html:92
++#: templates/catalogue/image_detail.html:64
msgid "This book can't be published yet, because:"
msgstr "Ta książka nie może jeszcze zostać opublikowana. Powód:"
- #: templates/catalogue/book_detail.html:87
- #: templates/catalogue/image_detail.html:68
-#: templates/catalogue/book_detail.html:98
++#: templates/catalogue/book_detail.html:102
++#: templates/catalogue/image_detail.html:72
msgid "Comments"
msgstr "Komentarze"
- #: templates/catalogue/book_html.html:13
-#: templates/catalogue/book_text.html:7
-msgid "Redakcja"
-msgstr ""
++#: templates/catalogue/book_edit.html:5
++msgid "Edit book"
++msgstr "Edytuj książkę"
+
-#: templates/catalogue/book_text.html:15
++#: templates/catalogue/book_html.html:13 templates/catalogue/book_text.html:15
msgid "Table of contents"
msgstr "Spis treści"
- #: templates/catalogue/book_html.html:14
-#: templates/catalogue/book_text.html:17
++#: templates/catalogue/book_html.html:14 templates/catalogue/book_text.html:17
msgid "Edit. note"
msgstr "Nota red."
-#: templates/catalogue/chunk_add.html:5 templates/catalogue/chunk_edit.html:18
+#: templates/catalogue/book_html.html:15
+msgid "Infobox"
+msgstr "Informacje"
+
- #: templates/catalogue/chunk_add.html:5
- #: templates/catalogue/chunk_edit.html:19
++#: templates/catalogue/book_text.html:7
++msgid "Redakcja"
++msgstr ""
++
++#: templates/catalogue/chunk_add.html:5 templates/catalogue/chunk_add.html:9
++#: templates/catalogue/chunk_edit.html:22
msgid "Split chunk"
msgstr "Podziel część"
--#: templates/catalogue/chunk_add.html:10
++#: templates/catalogue/chunk_add.html:14
msgid "Insert empty chunk after"
msgstr "Wstaw pustą część po"
--#: templates/catalogue/chunk_add.html:13
++#: templates/catalogue/chunk_add.html:17
msgid "Add chunk"
msgstr "Dodaj część"
- #: templates/catalogue/chunk_edit.html:6
- #: templates/catalogue/book_list/book.html:7
- #: templates/catalogue/book_list/chunk.html:5
-#: templates/catalogue/chunk_edit.html:5
++#: templates/catalogue/chunk_edit.html:5 templates/catalogue/chunk_edit.html:9
+ #: templates/catalogue/book_list/book.html:8
+ #: templates/catalogue/book_list/chunk.html:6
msgid "Chunk settings"
msgstr "Ustawienia części"
- #: templates/catalogue/chunk_edit.html:11
-#: templates/catalogue/chunk_edit.html:10
++#: templates/catalogue/chunk_edit.html:14
msgid "Book"
msgstr "Książka"
#: templates/catalogue/document_create_missing.html:5
++#: templates/catalogue/document_create_missing.html:9
msgid "Create a new book"
msgstr "Utwórz nową książkę"
--#: templates/catalogue/document_create_missing.html:11
++#: templates/catalogue/document_create_missing.html:15
msgid "Create book"
msgstr "Utwórz książkę"
--#: templates/catalogue/document_upload.html:8
--msgid "Bulk documents upload"
++#: templates/catalogue/document_list.html:7
++msgid "Book list"
++msgstr "Lista książek"
++
++#: templates/catalogue/document_upload.html:5
++msgid "Bulk document upload"
msgstr "Hurtowe dodawanie dokumentów"
#: templates/catalogue/document_upload.html:11
- msgid "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with <code>.xml</code> will be ignored."
- msgstr "Proszę wskazać archiwum ZIP z plikami XML w kodowaniu UTF-8. Pliki nie kończące się na <code>.xml</code> zostaną zignorowane."
++msgid "Bulk documents upload"
++msgstr "Hurtowe dodawanie dokumentów"
++
++#: templates/catalogue/document_upload.html:14
+ msgid ""
+ "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with "
+ "<code>.xml</code> will be ignored."
+ msgstr ""
+ "Proszę wskazać archiwum ZIP z plikami XML w kodowaniu UTF-8. Pliki nie "
+ "kończące się na <code>.xml</code> zostaną zignorowane."
- #: templates/catalogue/document_upload.html:17
- #: templates/catalogue/upload_pdf.html:13
- #: templatetags/catalogue.py:36
-#: templates/catalogue/document_upload.html:17 templatetags/catalogue.py:35
++#: templates/catalogue/document_upload.html:20
++#: templates/catalogue/upload_pdf.html:16 templatetags/catalogue.py:36
msgid "Upload"
msgstr "Załaduj"
--#: templates/catalogue/document_upload.html:24
- msgid "There have been some errors. No files have been added to the repository."
++#: templates/catalogue/document_upload.html:27
+ msgid ""
+ "There have been some errors. No files have been added to the repository."
msgstr "Wystąpiły błędy. Żadne pliki nie zostały dodane do repozytorium."
--#: templates/catalogue/document_upload.html:25
++#: templates/catalogue/document_upload.html:28
msgid "Offending files"
msgstr "Błędne pliki"
--#: templates/catalogue/document_upload.html:33
++#: templates/catalogue/document_upload.html:36
msgid "Correct files"
msgstr "Poprawne pliki"
--#: templates/catalogue/document_upload.html:44
++#: templates/catalogue/document_upload.html:47
msgid "Files have been successfully uploaded to the repository."
msgstr "Pliki zostały dodane do repozytorium."
--#: templates/catalogue/document_upload.html:45
++#: templates/catalogue/document_upload.html:48
msgid "Uploaded files"
msgstr "Dodane pliki"
--#: templates/catalogue/document_upload.html:55
++#: templates/catalogue/document_upload.html:58
msgid "Skipped files"
msgstr "Pominięte pliki"
--#: templates/catalogue/document_upload.html:56
++#: templates/catalogue/document_upload.html:59
msgid "Files skipped due to no <code>.xml</code> extension"
msgstr "Pliki pominięte z powodu braku rozszerzenia <code>.xml</code>."
- #: templates/catalogue/image_detail.html:22
-#: templates/catalogue/my_page.html:21
-msgid "Your last edited documents"
-msgstr "Twoje ostatnie edycje"
++#: templates/catalogue/image_detail.html:26
+msgid "Editor"
+msgstr "Edytor"
- #: templates/catalogue/image_detail.html:24
-#: templates/catalogue/my_page.html:30 templates/catalogue/user_page.html:13
-msgid "Recent activity for"
-msgstr "Ostatnia aktywność dla:"
++#: templates/catalogue/image_detail.html:28
+msgid "Proceed to the editor."
+msgstr "Przejdź do edytora."
-#: templates/catalogue/user_list.html:7 templatetags/catalogue.py:31
-msgid "Users"
-msgstr "Użytkownicy"
-
-#: templates/catalogue/wall.html:28
-msgid "not logged in"
-msgstr "nie zalogowany"
++#: templates/catalogue/image_list.html:7
++msgid "Image list"
++msgstr "Lista obrazów"
+
-#: templates/catalogue/wall.html:33
-msgid "No activity recorded."
-msgstr "Nie zanotowano aktywności."
-
-#: templates/catalogue/book_list/book.html:7
-#: templates/catalogue/book_list/book.html:28
-msgid "Book settings"
-msgstr "Ustawienia książki"
-
-#: templates/catalogue/book_list/book_list.html:22
-msgid "Show hidden books"
-msgstr "Pokaż ukryte książki"
+#: templates/catalogue/image_short.html:4
+msgid "Image settings"
+msgstr "Ustawienia obrazu"
- #: templates/catalogue/book_list/book_list.html:24
+#: templates/catalogue/image_table.html:19
+ #: templates/catalogue/book_list/book_list.html:27
msgid "Search in book titles"
msgstr "Szukaj w tytułach książek"
- #: templates/catalogue/book_list/book_list.html:29
+#: templates/catalogue/image_table.html:24
+ #: templates/catalogue/book_list/book_list.html:32
msgid "stage"
msgstr "etap"
- #: templates/catalogue/book_list/book_list.html:31
- #: templates/catalogue/book_list/book_list.html:42
+#: templates/catalogue/image_table.html:26
+#: templates/catalogue/image_table.html:37
-#: templates/catalogue/book_list/book_list.html:64
+ #: templates/catalogue/book_list/book_list.html:34
+ #: templates/catalogue/book_list/book_list.html:45
++#: templates/catalogue/book_list/book_list.html:66
msgid "none"
msgstr "brak"
- #: templates/catalogue/book_list/book_list.html:40
+#: templates/catalogue/image_table.html:35
+ #: templates/catalogue/book_list/book_list.html:43
msgid "editor"
msgstr "redaktor"
-#: templates/catalogue/book_list/book_list.html:54
+#: templates/catalogue/image_table.html:46
- #: templates/catalogue/book_list/book_list.html:51
++#: templates/catalogue/book_list/book_list.html:56
msgid "status"
msgstr "status"
-#: templates/catalogue/book_list/book_list.html:88
+#: templates/catalogue/image_table.html:63
+#, python-format
+msgid "%(c)s image"
+msgid_plural "%(c)s images"
+msgstr[0] "%(c)s obraz"
+msgstr[1] "%(c)s obrazy"
+msgstr[2] "%(c)s obrazów"
+
+#: templates/catalogue/image_table.html:68
+msgid "No images found."
+msgstr "Nie znaleziono obrazów."
+
- #: templates/catalogue/my_page.html:13
++#: templates/catalogue/my_page.html:15 templatetags/catalogue.py:27
++msgid "My page"
++msgstr "Moja strona"
++
++#: templates/catalogue/my_page.html:24
+msgid "Your last edited documents"
+msgstr "Twoje ostatnie edycje"
+
- #: templates/catalogue/my_page.html:22
- #: templates/catalogue/user_page.html:13
++#: templates/catalogue/my_page.html:33 templates/catalogue/user_page.html:16
+msgid "Recent activity for"
+msgstr "Ostatnia aktywność dla:"
+
- #: templates/catalogue/upload_pdf.html:8
++#: templates/catalogue/upload_pdf.html:5
++#: templates/catalogue/upload_pdf.html:11
+msgid "PDF file upload"
- msgstr ""
++msgstr "Ładowanie pliku PDF"
+
- #: templates/catalogue/user_list.html:7
++#: templates/catalogue/user_list.html:6 templates/catalogue/user_list.html:11
+#: templatetags/catalogue.py:32
+msgid "Users"
+msgstr "Użytkownicy"
+
- #: templates/catalogue/wall.html:28
++#: templates/catalogue/wall.html:29
+msgid "not logged in"
+msgstr "nie zalogowany"
+
- #: templates/catalogue/wall.html:33
++#: templates/catalogue/wall.html:34
+msgid "No activity recorded."
+msgstr "Nie zanotowano aktywności."
+
- #: templates/catalogue/book_list/book.html:6
- #: templates/catalogue/book_list/book.html:25
++#: templates/catalogue/book_list/book.html:7
++#: templates/catalogue/book_list/book.html:28
+msgid "Book settings"
+msgstr "Ustawienia książki"
+
- #: templates/catalogue/book_list/book_list.html:19
++#: templates/catalogue/book_list/book_list.html:22
+msgid "Show hidden books"
+msgstr "Pokaż ukryte książki"
+
- #: templates/catalogue/book_list/book_list.html:75
++#: templates/catalogue/book_list/book_list.html:90
#, python-format
msgid "%(c)s book"
msgid_plural "%(c)s books"
msgstr[1] "%(c)s książki"
msgstr[2] "%(c)s książek"
- #: templates/catalogue/book_list/book_list.html:80
-#: templates/catalogue/book_list/book_list.html:93
++#: templates/catalogue/book_list/book_list.html:95
msgid "No books found."
msgstr "Nie znaleziono książek."
- #: templatetags/book_list.py:84
- #: templatetags/book_list.py:145
-#: templates/catalogue/book_list/book_list.html:99
++#: templates/catalogue/book_list/book_list.html:101
+ msgid "Set stage"
+ msgstr "Ustaw etap"
+
-#: templates/catalogue/book_list/book_list.html:100
++#: templates/catalogue/book_list/book_list.html:102
+ msgid "Set user"
+ msgstr "Przypisz redaktora"
+
-#: templates/catalogue/book_list/book_list.html:102
++#: templates/catalogue/book_list/book_list.html:104
+ msgid "Project"
+ msgstr "Projekt"
+
-#: templates/catalogue/book_list/book_list.html:103
++#: templates/catalogue/book_list/book_list.html:105
+ msgid "Mark publishable"
+ msgstr "Oznacz do publikacji"
+
-#: templates/catalogue/book_list/book_list.html:104
++#: templates/catalogue/book_list/book_list.html:106
+ msgid "Mark not publishable"
+ msgstr "Odznacz do publikacji"
+
-#: templates/catalogue/book_list/book_list.html:105
++#: templates/catalogue/book_list/book_list.html:107
+ msgid "Other user"
+ msgstr "Inny użytkownik"
+
-#: templatetags/book_list.py:84
++#: templatetags/book_list.py:84 templatetags/book_list.py:152
msgid "publishable"
msgstr "do publikacji"
--#: templatetags/book_list.py:85
- #: templatetags/book_list.py:146
++#: templatetags/book_list.py:85 templatetags/book_list.py:153
msgid "changed"
msgstr "zmienione"
--#: templatetags/book_list.py:86
- #: templatetags/book_list.py:147
++#: templatetags/book_list.py:86 templatetags/book_list.py:154
msgid "published"
msgstr "opublikowane"
--#: templatetags/book_list.py:87
- #: templatetags/book_list.py:148
++#: templatetags/book_list.py:87 templatetags/book_list.py:155
msgid "unpublished"
msgstr "nie opublikowane"
--#: templatetags/book_list.py:88
- #: templatetags/book_list.py:149
++#: templatetags/book_list.py:88 templatetags/book_list.py:156
msgid "empty"
msgstr "puste"
--#: templatetags/catalogue.py:27
--msgid "My page"
--msgstr "Moja strona"
--
#: templatetags/catalogue.py:30
msgid "All"
msgstr "Wszystkie"
-#: templatetags/catalogue.py:34
+#: templatetags/catalogue.py:31
+msgid "Images"
+msgstr "Obrazy"
+
+#: templatetags/catalogue.py:35
msgid "Add"
msgstr "Dodaj"
-#: templatetags/catalogue.py:37
++#: templatetags/catalogue.py:38
+ msgid "Covers"
+ msgstr "Okładki"
+
#: templatetags/wall.py:49
msgid "Related edit"
msgstr "Powiązana zmiana"
msgid "Comment"
msgstr "Komentarz"
-#~ msgid "Infobox"
-#~ msgstr "Informacje"
-
#~ msgid "Admin"
#~ msgstr "Administracja"
#~ msgid "Describe the reason for reverting."
#~ msgstr "Opisz powód przywrócenia."
- #~ msgid "name"
- #~ msgstr "nazwa"
-
#~ msgid "theme"
#~ msgstr "motyw"
#~ msgid "Last edited by"
#~ msgstr "Ostatnio edytowane przez"
- #~ msgid "Link to gallery"
- #~ msgstr "Link do galerii"
-
#~ msgid "Summary"
#~ msgstr "Podsumowanie"
--- /dev/null
--- /dev/null
++# -*- 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 model 'ImagePublishRecord'
++ db.create_table(u'catalogue_imagepublishrecord', (
++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
++ ('image', self.gf('django.db.models.fields.related.ForeignKey')(related_name='publish_log', to=orm['catalogue.Image'])),
++ ('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
++ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
++ ('change', self.gf('django.db.models.fields.related.ForeignKey')(related_name='publish_log', to=orm['catalogue.ImageChange'])),
++ ))
++ db.send_create_signal('catalogue', ['ImagePublishRecord'])
++
++ # Adding model 'ImageChange'
++ db.create_table(u'catalogue_imagechange', (
++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
++ ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
++ ('author_name', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)),
++ ('author_email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)),
++ ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)),
++ ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['catalogue.ImageChange'])),
++ ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['catalogue.ImageChange'])),
++ ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
++ ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)),
++ ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)),
++ ('tree', self.gf('django.db.models.fields.related.ForeignKey')(related_name='change_set', to=orm['catalogue.Image'])),
++ ('data', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
++ ))
++ db.send_create_signal('catalogue', ['ImageChange'])
++
++ # Adding M2M table for field tags on 'ImageChange'
++ db.create_table(u'catalogue_imagechange_tags', (
++ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
++ ('imagechange', models.ForeignKey(orm['catalogue.imagechange'], null=False)),
++ ('imagetag', models.ForeignKey(orm['catalogue.imagetag'], null=False))
++ ))
++ db.create_unique(u'catalogue_imagechange_tags', ['imagechange_id', 'imagetag_id'])
++
++ # Adding unique constraint on 'ImageChange', fields ['tree', 'revision']
++ db.create_unique(u'catalogue_imagechange', ['tree_id', 'revision'])
++
++ # Adding model 'ImageTag'
++ db.create_table(u'catalogue_imagetag', (
++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
++ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
++ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=64, unique=True, null=True, blank=True)),
++ ('ordering', self.gf('django.db.models.fields.IntegerField')()),
++ ))
++ db.send_create_signal('catalogue', ['ImageTag'])
++
++ # Adding model 'Image'
++ db.create_table(u'catalogue_image', (
++ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
++ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
++ ('image', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
++ ('title', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
++ ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)),
++ ('public', self.gf('django.db.models.fields.BooleanField')(default=True, db_index=True)),
++ ('_short_html', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
++ ('_new_publishable', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)),
++ ('_published', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)),
++ ('_changed', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)),
++ ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['catalogue.ImageTag'], null=True, blank=True)),
++ ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['catalogue.ImageChange'], null=True, blank=True)),
++ ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_image', null=True, to=orm['auth.User'])),
++ ))
++ db.send_create_signal('catalogue', ['Image'])
++
++
++ def backwards(self, orm):
++ # Removing unique constraint on 'ImageChange', fields ['tree', 'revision']
++ db.delete_unique(u'catalogue_imagechange', ['tree_id', 'revision'])
++
++ # Deleting model 'ImagePublishRecord'
++ db.delete_table(u'catalogue_imagepublishrecord')
++
++ # Deleting model 'ImageChange'
++ db.delete_table(u'catalogue_imagechange')
++
++ # Removing M2M table for field tags on 'ImageChange'
++ db.delete_table('catalogue_imagechange_tags')
++
++ # Deleting model 'ImageTag'
++ db.delete_table(u'catalogue_imagetag')
++
++ # Deleting model 'Image'
++ db.delete_table(u'catalogue_image')
++
++
++ models = {
++ u'auth.group': {
++ 'Meta': {'object_name': 'Group'},
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
++ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
++ },
++ u'auth.permission': {
++ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
++ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
++ },
++ u'auth.user': {
++ 'Meta': {'object_name': 'User'},
++ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
++ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
++ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
++ },
++ 'catalogue.book': {
++ 'Meta': {'ordering': "['title', 'slug']", 'object_name': 'Book'},
++ '_new_publishable': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_on_track': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ '_published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
++ '_single': ('django.db.models.fields.NullBooleanField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ 'dc_cover_image': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['cover.Image']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
++ 'dc_slug': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '128', 'null': 'True', 'blank': 'True'}),
++ 'gallery': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
++ 'parent_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Project']", 'null': 'True', 'blank': 'True'}),
++ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
++ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '128'}),
++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
++ },
++ 'catalogue.bookpublishrecord': {
++ 'Meta': {'ordering': "['-timestamp']", 'object_name': 'BookPublishRecord'},
++ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.Book']"}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
++ },
++ 'catalogue.chunk': {
++ 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk'},
++ '_changed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_hidden': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
++ 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.Book']"}),
++ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_chunk'", 'null': 'True', 'to': u"orm['auth.User']"}),
++ 'gallery_start': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
++ 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['catalogue.ChunkChange']", 'null': 'True', 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'number': ('django.db.models.fields.IntegerField', [], {}),
++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
++ 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.ChunkTag']", 'null': 'True', 'blank': 'True'}),
++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
++ },
++ 'catalogue.chunkchange': {
++ 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ChunkChange'},
++ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
++ 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
++ 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
++ 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}),
++ 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
++ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}),
++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ChunkChange']"}),
++ 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
++ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'change_set'", 'symmetrical': 'False', 'to': "orm['catalogue.ChunkTag']"}),
++ 'tree': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'change_set'", 'to': "orm['catalogue.Chunk']"})
++ },
++ 'catalogue.chunkpublishrecord': {
++ 'Meta': {'object_name': 'ChunkPublishRecord'},
++ 'book_record': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.BookPublishRecord']"}),
++ 'change': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.ChunkChange']"}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
++ },
++ 'catalogue.chunktag': {
++ 'Meta': {'ordering': "['ordering']", 'object_name': 'ChunkTag'},
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
++ 'ordering': ('django.db.models.fields.IntegerField', [], {}),
++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'})
++ },
++ 'catalogue.image': {
++ 'Meta': {'ordering': "['title']", 'object_name': 'Image'},
++ '_changed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_new_publishable': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
++ '_short_html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
++ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_image'", 'null': 'True', 'to': u"orm['auth.User']"}),
++ 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['catalogue.ImageChange']", 'null': 'True', 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'image': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
++ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
++ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}),
++ 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['catalogue.ImageTag']", 'null': 'True', 'blank': 'True'}),
++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
++ },
++ 'catalogue.imagechange': {
++ 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ImageChange'},
++ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
++ 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
++ 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
++ 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}),
++ 'data': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
++ 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ImageChange']"}),
++ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['catalogue.ImageChange']"}),
++ 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
++ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'change_set'", 'symmetrical': 'False', 'to': "orm['catalogue.ImageTag']"}),
++ 'tree': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'change_set'", 'to': "orm['catalogue.Image']"})
++ },
++ 'catalogue.imagepublishrecord': {
++ 'Meta': {'ordering': "['-timestamp']", 'object_name': 'ImagePublishRecord'},
++ 'change': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.ImageChange']"}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'image': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'publish_log'", 'to': "orm['catalogue.Image']"}),
++ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
++ },
++ 'catalogue.imagetag': {
++ 'Meta': {'ordering': "['ordering']", 'object_name': 'ImageTag'},
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
++ 'ordering': ('django.db.models.fields.IntegerField', [], {}),
++ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'})
++ },
++ 'catalogue.project': {
++ 'Meta': {'ordering': "['name']", 'object_name': 'Project'},
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
++ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
++ },
++ u'contenttypes.contenttype': {
++ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
++ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
++ },
++ u'cover.image': {
++ 'Meta': {'object_name': 'Image'},
++ 'author': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
++ 'download_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
++ 'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
++ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'license_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
++ 'license_url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'blank': 'True'}),
++ 'source_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
++ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ }
++ }
++
++ complete_apps = ['catalogue']
# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
+ from catalogue.models.project import Project
from catalogue.models.chunk import Chunk
-from catalogue.models.publish_log import BookPublishRecord, ChunkPublishRecord
+from catalogue.models.image import Image
+from catalogue.models.publish_log import (BookPublishRecord,
+ ChunkPublishRecord, ImagePublishRecord)
from catalogue.models.book import Book
from catalogue.models.listeners import *
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.conf import settings
+from django.contrib.sites.models import Site
+from django.db import models
+from django.template.loader import render_to_string
+from django.utils.translation import ugettext_lazy as _
+from catalogue.helpers import cached_in_field
+from catalogue.tasks import refresh_instance
+from dvcs import models as dvcs_models
+
+
+class Image(dvcs_models.Document):
+ """ An editable chunk of text. Every Book text is divided into chunks. """
+ REPO_PATH = settings.CATALOGUE_IMAGE_REPO_PATH
+
+ image = models.FileField(_('image'), upload_to='catalogue/images')
+ title = models.CharField(_('title'), max_length=255, blank=True)
+ slug = models.SlugField(_('slug'), unique=True)
+ public = models.BooleanField(_('public'), default=True, db_index=True)
+
+ # cache
+ _short_html = models.TextField(null=True, blank=True, editable=False)
+ _new_publishable = models.NullBooleanField(editable=False)
+ _published = models.NullBooleanField(editable=False)
+ _changed = models.NullBooleanField(editable=False)
+
+ class Meta:
+ app_label = 'catalogue'
+ ordering = ['title']
+ verbose_name = _('image')
+ verbose_name_plural = _('images')
+ permissions = [('can_pubmark_image', 'Can mark images for publishing')]
+
+ # Representing
+ # ============
+
+ def __unicode__(self):
+ return self.title
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ("catalogue_image", [self.slug])
+
+ def correct_about(self):
+ return "http://%s%s" % (
+ Site.objects.get_current().domain,
+ self.get_absolute_url()
+ )
+
+ # State & cache
+ # =============
+
+ def last_published(self):
+ try:
+ return self.publish_log.all()[0].timestamp
+ except IndexError:
+ return None
+
+ def assert_publishable(self):
+ from librarian.picture import WLPicture
+ from librarian import NoDublinCore, ParseError, ValidationError
+
+ class SelfImageStore(object):
+ def path(self_, slug, mime_type):
+ """Returns own file object. Ignores slug ad mime_type."""
+ return open(self.image.path)
+
+ publishable = self.publishable()
+ assert publishable, _("There is no publishable revision")
+ picture_xml = publishable.materialize()
+
+ try:
+ picture = WLPicture.from_string(picture_xml.encode('utf-8'),
+ image_store=SelfImageStore)
+ except ParseError, e:
+ raise AssertionError(_('Invalid XML') + ': ' + str(e))
+ except NoDublinCore:
+ raise AssertionError(_('No Dublin Core found.'))
+ except ValidationError, e:
+ raise AssertionError(_('Invalid Dublin Core') + ': ' + str(e))
+
+ valid_about = self.correct_about()
+ assert picture.picture_info.about == valid_about, \
+ _("rdf:about is not") + " " + valid_about
+
++ def publishable_error(self):
++ try:
++ return self.assert_publishable()
++ except AssertionError, e:
++ return e
++ else:
++ return None
++
+ def accessible(self, request):
+ return self.public or request.user.is_authenticated()
+
+ def is_new_publishable(self):
+ change = self.publishable()
+ if not change:
+ return False
+ return not change.publish_log.exists()
+ new_publishable = cached_in_field('_new_publishable')(is_new_publishable)
+
+ def is_published(self):
+ return self.publish_log.exists()
+ published = cached_in_field('_published')(is_published)
+
+ def is_changed(self):
+ if self.head is None:
+ return False
+ return not self.head.publishable
+ changed = cached_in_field('_changed')(is_changed)
+
+ @cached_in_field('_short_html')
+ def short_html(self):
+ return render_to_string(
+ 'catalogue/image_short.html', {'image': self})
+
+ def refresh(self):
+ """This should be done offline."""
+ self.short_html
+ self.single
+ self.new_publishable
+ self.published
+
+ def touch(self):
+ update = {
+ "_changed": self.is_changed(),
+ "_short_html": None,
+ "_new_publishable": self.is_new_publishable(),
+ "_published": self.is_published(),
+ }
+ Image.objects.filter(pk=self.pk).update(**update)
+ refresh_instance(self)
+
+ def refresh(self):
+ """This should be done offline."""
+ self.changed
+ self.short_html
+
+
+ # Publishing
+ # ==========
+
+ def publish(self, user):
+ """Publishes the picture on behalf of a (local) user."""
+ from base64 import b64encode
+ import apiclient
+ from catalogue.signals import post_publish
+
+ self.assert_publishable()
+ change = self.publishable()
+ picture_xml = change.materialize()
+ picture_data = open(self.image.path).read()
+ apiclient.api_call(user, "pictures/", {
+ "picture_xml": picture_xml,
+ "picture_image_data": b64encode(picture_data),
+ })
+ # record the publish
+ log = self.publish_log.create(user=user, change=change)
+ post_publish.send(sender=log)
{% extends "catalogue/base.html" %}
{% load i18n %}
- {% load url from future %}
{% load wall %}
+{% block titleextra %}{% trans "Activity" %}{% endblock %}
+
+
{% block content %}
<h1><a href='{% url "catalogue_activity" prev_day.isoformat %}'><</a>
{% load catalogue %}
<!DOCTYPE html>
<html>
-<head>
+<head lang="{{ LANGUAGE_CODE }}">
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
{% compressed_css 'catalogue' %}
- <title>{% block title %}{% trans "Platforma Redakcyjna" %}{% endblock title %}</title>
+ <title>{% block title %}{% trans "Platforma Redakcyjna" %} ::
+ {% block titleextra %}{% endblock %}{% endblock title %}</title>
+ {% block add_css %}{% endblock %}
</head>
<body>
<div id="tabs-nav">
- <a href="{% url catalogue_document_list %}">
+ <a href="{% url 'catalogue_document_list' %}">
- <img id="logo" src="{{ STATIC_URL }}img/wl-orange.png" />
+ <img id="logo" src="{{ STATIC_URL }}img/wl-orange.png" alt="Platforma" />
</a>
<div id="tabs-nav-left">
</div>
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
{% compressed_js 'catalogue' %}
+ {% block add_js %}{% endblock %}
{% block extrabody %}
{% endblock %}
</body>
{% extends "catalogue/base.html" %}
{% load book_list comments i18n %}
+
+{% block titleextra %}{{ book.title }}{% endblock %}
+
+
{% block content %}
</tbody></table>
{% if editable %}</form>{% endif %}
-
{% if editable %}
- <p><a href="{% url catalogue_book_append book.slug %}">{% trans "Append to other book" %}</a></p>
+ {% if book.gallery %}
+ <p><a href="{% url 'catalogue_book_gallery' book.slug %}">{% trans "Edit gallery" %}</a></p>
+ {% endif %}
+
+ <p><a href="{% url 'catalogue_book_append' book.slug %}">{% trans "Append to other book" %}</a></p>
{% endif %}
<h2>{% trans "Publication" %}</h2>
+ <div class="cover-preview">
+ <img class="cover-preview" src="{% url 'cover_preview' book.slug %}" />
+ {% if book.dc_cover_image %}
+ <a href="{{ book.dc_cover_image.get_absolute_url }}">{{ book.dc_cover_image }}</a>
+ {% endif %}
+ </div>
+
<p>{% trans "Last published" %}:
{% if book.last_published %}
{{ book.last_published }}
{% if publishable %}
<p>
- <a href="{% url catalogue_book_xml book.slug %}">{% trans "Full XML" %}</a><br/>
- <a target="_blank" href="{% url catalogue_book_html book.slug %}">{% trans "HTML version" %}</a><br/>
- <a href="{% url catalogue_book_txt book.slug %}">{% trans "TXT version" %}</a><br/>
- <a href="{% url catalogue_book_pdf book.slug %}">{% trans "PDF version" %}</a><br/>
- <a href="{% url catalogue_book_epub book.slug %}">{% trans "EPUB version" %}</a><br/>
+ <a href="{% url 'catalogue_book_xml' book.slug %}" rel="nofollow">{% trans "Full XML" %}</a><br/>
+ <a target="_blank" href="{% url 'catalogue_book_html' book.slug %}" rel="nofollow">{% trans "HTML version" %}</a><br/>
+ <a href="{% url 'catalogue_book_txt' book.slug %}" rel="nofollow">{% trans "TXT version" %}</a><br/>
+ <a href="{% url 'catalogue_book_pdf' book.slug %}" rel="nofollow">{% trans "PDF version" %}</a><br/>
+ <a href="{% url 'catalogue_book_epub' book.slug %}" rel="nofollow">{% trans "EPUB version" %}</a><br/>
</p>
{% if user.is_authenticated %}
mira66 (http://www.flickr.com/photos/21804434@N02/) /
CC BY 2.0 (http://creativecommons.org/licenses/by/2.0/)
-->
- <form method="POST" action="{% url catalogue_publish book.slug %}">{% csrf_token %}
+ <form method="POST" action="{% url 'catalogue_publish' book.slug %}">{% csrf_token %}
<img src="{{ STATIC_URL }}img/angel-left.png" style="vertical-align: middle" />
<button id="publish-button" type="submit">
<span>{% trans "Publish" %}</span></button>
<img src="{{ STATIC_URL }}img/angel-right.png" style="vertical-align: middle" />
</form>
{% else %}
- <a href="{% url login %}">{% trans "Log in to publish." %}</a>
+ <a href="{% url 'login' %}">{% trans "Log in to publish." %}</a>
{% endif %}
{% else %}
<p>{% trans "This book can't be published yet, because:" %}</p>
<ul><li>{{ publishable_error }}</li></ul>
{% endif %}
+ <div style="clear: both;"></div>
</div>
{% load pagination_tags %}
-<form name='filter' action=''>
+<form name='filter' action='{{ request.path }}'>
<input type='hidden' name="title" value="{{ request.GET.title }}" />
<input type='hidden' name="stage" value="{{ request.GET.stage }}" />
{% if not viewed_user %}
{% endif %}
<input type='hidden' name="all" value="{{ request.GET.all }}" />
<input type='hidden' name="status" value="{{ request.GET.status }}" />
+ <input type='hidden' name="project" value="{{ request.GET.project }}" />
</form>
+
<table id="file-list"{% if viewed_user %} class="book-list-user"{% endif %}>
<thead><tr>
+ <th></th>
<th></th>
<th>
<input class='check-filter' type='checkbox' name='all' title='{% trans "Show hidden books" %}'
{% endif %}value="{{ user.username }}">{{ user.first_name }} {{ user.last_name }} ({{ user.count }})</option>
{% endfor %}
</select></th>
+ {% else %}
+ <th style='display: none'></th>
{% endif %}
<th><select name="status" class="filter">
{% endfor %}
</select></th>
+ <th><select name="project" class="filter">
+ <option value=''>- {% trans "project" %} -</option>
+ <option {% if request.GET.project == '-' %}selected="selected"
+ {% endif %}value="-">- {% trans "none" %} -</option>
+ {% for project in projects %}
+ <option {% if request.GET.project == project.pk|slugify %}selected="selected"
+ {% endif %}value='{{ project.pk }}'>{{ project.name }}</option>
+ {% endfor %}
+ </select></th>
+
</tr></thead>
{% with cnt=books|length %}
{% endif %}
{% endwith %}
{% endfor %}
- <tr><th class='paginator' colspan="5">
+ <tr><th class='paginator' colspan="6">
{% paginate %}
{% blocktrans count c=cnt %}{{c}} book{% plural %}{{c}} books{% endblocktrans %}</th></tr>
</tbody>
{% if not books %}
<p>{% trans "No books found." %}</p>
{% endif %}
+
+ <form id='chunk_mass_edit' action='{% url "catalogue_chunk_mass_edit" %}' style="display:none;">
+ {% csrf_token %}
+ <input type="hidden" name="ids" />
+ <label for="mass_edit_stage">{% trans "Set stage" %}</label><input type="hidden" name="stage" id="mass_edit_stage"/>
+ <label for="mass_edit_user">{% trans "Set user" %}</label><input type="hidden" name="user" id="mass_edit_stage" />
+ <input type="hidden" name="status" />
+ <label for="mass_edit_project">{% trans "Project" %}</label><input type="hidden" name="project" id="mass_edit_project" />
+ <label for="mass_edit_publish">{% trans "Mark publishable" %}</label>
+ <label for="mass_edit_unpublish">{% trans "Mark not publishable" %}</label>
+ <label for="mass_edit_other">{% trans "Other user" %}</label>
+ </form>
+
+ <select name="other-user" style="display:none;">
+ {% for user in other_users %}
+ <option {% if request.GET.user == user.username %}selected="selected"
+ {% endif %}value="{{ user.username }}">{{ user.first_name }} {{ user.last_name }} ({{ user.count }})</option>
+ {% endfor %}
+ </select>
{% extends "catalogue/base.html" %}
- {% load url from future %}
{% load i18n %}
+
+{% block titleextra %}{% trans "Chunk settings" %}{% endblock %}
+
+
{% block content %}
<h1>{% trans "Chunk settings" %}</h1>
{% load i18n %}
{% load catalogue book_list %}
+ {% load compressed %}
+{% block titleextra %}{% trans "Book list" %}{% endblock %}
+
+ {% block add_js %}
+ {% compressed_js 'book_list' %}
+ {% endblock %}
+
+ {% block add_css %}
+ {% compressed_css 'book_list' %}
+ {% endblock %}
+
{% block content %}
{% book_list %}
{% endblock content %}
{% load i18n %}
+{% block titleextra %}{% trans "Bulk document upload" %}{% endblock %}
+
+
{% block leftcolumn %}
{% trans "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with <code>.xml</code> will be ignored." %}
</p>
-<form enctype="multipart/form-data" method="POST" action="">
+<form enctype="multipart/form-data" method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ form.as_p }}
<p><button type="submit">{% trans "Upload" %}</button></p>
<h3>{% trans "Uploaded files" %}</h3>
<ul id='ok-list'>
{% for filename, slug, title in ok_list %}
- <li><a href='{% url wiki_editor slug %}'>{{ title }}</a> (<code>{{ filename }})</a></li>
+ <li><a href='{% url "wiki_editor" slug %}'>{{ title }}</a> (<code>{{ filename }})</a></li>
{% endfor %}
</ul>
{% endif %}
--- /dev/null
- <p><a href="{% url wiki_img_editor object.slug %}">{% trans "Proceed to the editor." %}</a></p>
+{% extends "catalogue/base.html" %}
+{% load book_list comments i18n %}
+
+
+{% block titleextra %}{{ object.title }}{% endblock %}
+
+
+{% block content %}
+
+
+<h1>{{ object.title }}</h1>
+
+
+{% if editable %}<form method='POST'>{% csrf_token %}{% endif %}
+<table class='editable'><tbody>
+ {{ form.as_table }}
+ {% if editable %}
+ <tr><td></td><td><button type="submit">{% trans "Save" %}</button></td></tr>
+ {% endif %}
+</tbody></table>
+{% if editable %}</form>{% endif %}
+
+
+
+<div class='section'>
+ <h2>{% trans "Editor" %}</h2>
+
- <form method="POST" action="{% url catalogue_publish_image object.slug %}">{% csrf_token %}
++ <p><a href="{% url 'wiki_img_editor' object.slug %}">{% trans "Proceed to the editor." %}</a></p>
+</div>
+
+
+
+<div class='section'>
+
+
+<h2>{% trans "Publication" %}</h2>
+
+<p>{% trans "Last published" %}:
+ {% if object.last_published %}
+ {{ object.last_published }}
+ {% else %}
+ —
+ {% endif %}
+</p>
+
+{% if publishable %}
+ {% if user.is_authenticated %}
+ <!--
+ Angel photos:
+ Angels in Ely Cathedral (http://www.flickr.com/photos/21804434@N02/4483220595/) /
+ mira66 (http://www.flickr.com/photos/21804434@N02/) /
+ CC BY 2.0 (http://creativecommons.org/licenses/by/2.0/)
+ -->
- <a href="{% url login %}">{% trans "Log in to publish." %}</a>
++ <form method="POST" action="{% url 'catalogue_publish_image' object.slug %}">{% csrf_token %}
+ <!--img src="{{ STATIC_URL }}img/angel-left.png" style="vertical-align: middle" /-->
+ <button id="publish-button" type="submit">
+ <span>{% trans "Publish" %}</span></button>
+ <!--img src="{{ STATIC_URL }}img/angel-right.png" style="vertical-align: middle" /-->
+ </form>
+ {% else %}
++ <a href="{% url 'login' %}">{% trans "Log in to publish." %}</a>
+ {% endif %}
+{% else %}
+ <p>{% trans "This book can't be published yet, because:" %}</p>
+ <ul><li>{{ publishable_error }}</li></ul>
+{% endif %}
+
+</div>
+
+
+<div class='section'>
+ <h2>{% trans "Comments" %}</h2>
+
+ {% render_comment_list for object %}
+ {% with object.get_absolute_url as next %}
+ {% render_comment_form for object %}
+ {% endwith %}
+</div>
+
+{% endblock content %}
--- /dev/null
- <td><a href="{% url catalogue_image image.slug %}" title='{% trans "Image settings" %}'>[B]</a></td>
+{% load i18n %}
+
+<tr>
- href="{% url wiki_img_editor image.slug %}">
++ <td><a href="{% url 'catalogue_image' image.slug %}" title='{% trans "Image settings" %}'>[B]</a></td>
+ <td><a target="_blank"
- <td class='user-column'>{% if image.user %}<a href="{% url catalogue_user image.user.username %}">{{ image.user.first_name }} {{ image.user.last_name }}</a>{% endif %}</td>
++ href="{% url 'wiki_img_editor' image.slug %}">
+ {{ image.title }}</a></td>
+ <td>{% if image.stage %}
+ {{ image.stage }}
+ {% else %}–
+ {% endif %}</td>
++ <td class='user-column'>{% if image.user %}<a href="{% url 'catalogue_user' image.user.username %}">{{ image.user.first_name }} {{ image.user.last_name }}</a>{% endif %}</td>
+ <td>
+ {% if image.published %}P{% endif %}
+ {% if image.new_publishable %}p{% endif %}
+ {% if image.changed %}+{% endif %}
+ </td>
+</tr>
{% load i18n %}
{% load catalogue book_list wall %}
+ {% load compressed %}
+ {% block add_js %}
+ {% compressed_js 'book_list' %}
+ {% endblock %}
+
+ {% block add_css %}
+ {% compressed_css 'book_list' %}
+ {% endblock %}
+{% block titleextra %}{% trans "My page" %}{% endblock %}
+
+
{% block leftcolumn %}
{% book_list request.user %}
{% endblock leftcolumn %}
<h2>{% trans "Your last edited documents" %}</h2>
<ol>
{% for slugs, item in last_books %}
- <li><a href="{% url wiki_editor slugs.0 slugs.1 %}"
+ <li><a href="{% url 'wiki_editor' slugs.0 slugs.1 %}"
target="_blank">{{ item.title }}</a><br/><span class="date">({{ item.time|date:"H:i:s, d/m/Y" }})</span></li>
{% endfor %}
</ol>
{% load i18n %}
+
+{% block titleextra %}{% trans "Users" %}{% endblock %}
+
+
{% block leftcolumn %}
<h1>{% trans "Users" %}</h1>
<ul>
{% for user in users %}
- <li><a href="{% url catalogue_user user.username %}">
+ <li><a href="{% url 'catalogue_user' user.username %}">
<span class="chunkno">{{ forloop.counter }}.</span>
{{ user.first_name }} {{ user.last_name }}</a>
({{ user.count }})</li>
<li class="{{ item.tag }}{% if not item.user %} anonymous{% endif %}">
<div class='gravatar'>
{% if item.get_email %}
- {% gravatar_img_for_email item.get_email 32 %}
+ <img src="{% gravatar_for_email item.get_email 32 %}"
+ height="32" width="32" alt='Avatar' />
<br/>
{% endif %}
</div>
<a target="_blank" href='{{ item.url }}'>{{ item.title }}</a>
<br/><strong>{% trans "user" %}:</strong>
{% if item.user %}
- <a href="{% url catalogue_user item.user.username %}">
+ <a href="{% url 'catalogue_user' item.user.username %}">
{{ item.user.first_name }} {{ item.user.last_name }}</a>
<{{ item.user.email|email_link }}>
{% else %}
from django import template
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
- from catalogue.models import Chunk, Image
-from catalogue.models import Chunk, Project
++from catalogue.models import Chunk, Image, Project
register = template.Library()
chunks = foreign_filter(chunks, arg_or_GET('user'), 'user', User, 'username')
chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model, 'slug')
chunks = search_filter(chunks, arg_or_GET('title'), ['book__title', 'title'])
+ chunks = foreign_filter(chunks, arg_or_GET('project'), 'book__project', Project, 'pk')
return chunks
new_context = {"viewed_user": user}
else:
filters = {}
- new_context = {"users": User.objects.annotate(
+ new_context = {
+ "users": User.objects.annotate(
count=Count('chunk')).filter(count__gt=0).order_by(
- '-count', 'last_name', 'first_name')}
+ '-count', 'last_name', 'first_name'),
+ "other_users": User.objects.annotate(
+ count=Count('chunk')).filter(count=0).order_by(
+ 'last_name', 'first_name'),
+ }
new_context.update({
"filters": True,
"books": ChunksList(document_list_filter(request, **filters)),
"stages": Chunk.tag_model.objects.all(),
"states": _states_options,
+ "projects": Project.objects.all(),
})
return new_context
+
+
+
+_image_states = [
+ ('publishable', _('publishable'), Q(_new_publishable=True)),
+ ('changed', _('changed'), Q(_changed=True)),
+ ('published', _('published'), Q(_published=True)),
+ ('unpublished', _('unpublished'), Q(_published=False)),
+ ('empty', _('empty'), Q(head=None)),
+ ]
+_image_states_options = [s[:2] for s in _image_states]
+_image_states_dict = dict([(s[0], s[2]) for s in _image_states])
+
+def image_list_filter(request, **kwargs):
+
+ def arg_or_GET(field):
+ return kwargs.get(field, request.GET.get(field))
+
+ images = Image.objects.all()
+
+ if not request.user.is_authenticated():
+ images = images.filter(public=True)
+
+ state = arg_or_GET('status')
+ if state in _image_states_dict:
+ images = images.filter(_image_states_dict[state])
+
+ images = foreign_filter(images, arg_or_GET('user'), 'user', User, 'username')
+ images = foreign_filter(images, arg_or_GET('stage'), 'stage', Image.tag_model, 'slug')
+ images = search_filter(images, arg_or_GET('title'), ['title', 'title'])
+ return images
+
+
+@register.inclusion_tag('catalogue/image_table.html', takes_context=True)
+def image_list(context, user=None):
+ request = context['request']
+
+ if user:
+ filters = {"user": user}
+ new_context = {"viewed_user": user}
+ else:
+ filters = {}
+ new_context = {"users": User.objects.annotate(
+ count=Count('image')).filter(count__gt=0).order_by(
+ '-count', 'last_name', 'first_name')}
+
+ new_context.update({
+ "filters": True,
+ "request": request,
+ "objects": image_list_filter(request, **filters),
+ "stages": Image.tag_model.objects.all(),
+ "states": _image_states_options,
+ })
+
+ return new_context
tabs.append(Tab('activity', _('Activity'), reverse("catalogue_activity")))
tabs.append(Tab('all', _('All'), reverse("catalogue_document_list")))
+ tabs.append(Tab('images', _('Images'), reverse("catalogue_image_list")))
tabs.append(Tab('users', _('Users'), reverse("catalogue_users")))
if user.has_perm('catalogue.add_book'):
tabs.append(Tab('create', _('Add'), reverse("catalogue_create_missing")))
tabs.append(Tab('upload', _('Upload'), reverse("catalogue_upload")))
+ tabs.append(Tab('cover', _('Covers'), reverse("cover_image_list")))
+
return {"tabs": tabs, "active_tab": active}
# -*- coding: utf-8
- from django.conf.urls.defaults import *
- from django.views.generic.simple import redirect_to
+ from django.conf.urls import patterns, url
+ from django.contrib.auth.decorators import permission_required
+ from django.views.generic import RedirectView
+ from catalogue.feeds import PublishTrackFeed
+ from catalogue.views import GalleryView
urlpatterns = patterns('catalogue.views',
- url(r'^$', redirect_to, {'url': 'catalogue/'}),
+ url(r'^$', RedirectView.as_view(url='catalogue/')),
+ url(r'^images/$', 'image_list', name='catalogue_image_list'),
+ url(r'^image/(?P<slug>[^/]+)/$', 'image', name="catalogue_image"),
+ url(r'^image/(?P<slug>[^/]+)/publish$', 'publish_image',
+ name="catalogue_publish_image"),
+
url(r'^catalogue/$', 'document_list', name='catalogue_document_list'),
url(r'^user/$', 'my', name='catalogue_user'),
url(r'^user/(?P<username>[^/]+)/$', 'user', name='catalogue_user'),
'create_missing', name='catalogue_create_missing'),
url(r'^book/(?P<slug>[^/]+)/publish$', 'publish', name="catalogue_publish"),
- #url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="catalogue_publish"),
url(r'^book/(?P<slug>[^/]+)/$', 'book', name="catalogue_book"),
+ url(r'^book/(?P<slug>[^/]+)/gallery/$',
+ permission_required('catalogue.change_book')(GalleryView.as_view()),
+ name="catalogue_book_gallery"),
url(r'^book/(?P<slug>[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"),
url(r'^book/(?P<slug>[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"),
url(r'^book/(?P<slug>[^/]+)/html$', 'book_html', name="catalogue_book_html"),
url(r'^book/(?P<slug>[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"),
url(r'^book/(?P<slug>[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"),
+
url(r'^chunk_add/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
'chunk_add', name="catalogue_chunk_add"),
url(r'^chunk_edit/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
'chunk_edit', name="catalogue_chunk_edit"),
url(r'^book_append/(?P<slug>[^/]+)/$',
'book_append', name="catalogue_book_append"),
+ url(r'^chunk_mass_edit',
+ 'chunk_mass_edit', name='catalogue_chunk_mass_edit'),
+ url(r'^track/(?P<slug>[^/]*)/$', PublishTrackFeed()),
)
from urllib import unquote
from urlparse import urlsplit, urlunsplit
+ from django.conf import settings
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required, permission_required
from django.core.urlresolvers import reverse
from django.db.models import Count, Q
+ from django.db import transaction
from django import http
from django.http import Http404, HttpResponse, HttpResponseForbidden
-from django.shortcuts import get_object_or_404, render, render_to_response
+from django.shortcuts import get_object_or_404, render
from django.utils.encoding import iri_to_uri
from django.utils.http import urlquote_plus
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import require_POST
- from django.views.generic.simple import direct_to_template
-from django.template import RequestContext
from apiclient import NotAuthorizedError
from catalogue import forms
from catalogue import helpers
from catalogue.helpers import active_tab
-from catalogue.models import Book, Chunk, BookPublishRecord, ChunkPublishRecord, Project
+from catalogue.models import (Book, Chunk, Image, BookPublishRecord,
- ChunkPublishRecord, ImagePublishRecord)
- from catalogue.tasks import publishable_error
++ ChunkPublishRecord, ImagePublishRecord, Project)
+ from fileupload.views import UploadView
#
# Quick hack around caching problems, TODO: use ETags
return render(request, 'catalogue/document_list.html')
+@active_tab('images')
+@never_cache
+def image_list(request, user=None):
+ return render(request, 'catalogue/image_list.html')
+
+
@never_cache
def user(request, username):
user = get_object_or_404(User, username=username)
@active_tab('users')
def users(request):
- return direct_to_template(request, 'catalogue/user_list.html', extra_context={
+ return render(request, 'catalogue/user_list.html', {
'users': User.objects.all().annotate(count=Count('chunk')).order_by(
'-count', 'last_name', 'first_name'),
})
"gallery": slug,
})
- return direct_to_template(request, "catalogue/document_create_missing.html", extra_context={
+ return render(request, "catalogue/document_create_missing.html", {
"slug": slug,
"form": form,
title=title,
)
- return direct_to_template(request, "catalogue/document_upload.html", extra_context={
+ return render(request, "catalogue/document_upload.html", {
"form": form,
"ok_list": ok_list,
"skipped_list": skipped_list,
else:
form = forms.DocumentsUploadForm()
- return direct_to_template(request, "catalogue/document_upload.html", extra_context={
+ return render(request, "catalogue/document_upload.html", {
"form": form,
"logout_to": '/',
book = get_object_or_404(Book, slug=slug)
if not book.accessible(request):
return HttpResponseForbidden("Not authorized.")
- xml = book.materialize()
- output = StringIO()
- # errors?
- import librarian.text
- librarian.text.transform(StringIO(xml), output)
- text = output.getvalue()
+ doc = book.wldocument()
+ text = doc.as_text().get_string()
response = http.HttpResponse(text, content_type='text/plain', mimetype='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s.txt' % slug
return response
book = get_object_or_404(Book, slug=slug)
if not book.accessible(request):
return HttpResponseForbidden("Not authorized.")
- xml = book.materialize()
- output = StringIO()
- # errors?
-
- import librarian.html
- librarian.html.transform(StringIO(xml), output, parse_dublincore=False,
- flags=['full-page'])
- html = output.getvalue()
- response = http.HttpResponse(html, content_type='text/html', mimetype='text/html')
- return response
+
+ doc = book.wldocument(parse_dublincore=False)
+ html = doc.as_html()
+
+ html = html.get_string() if html is not None else ''
+ # response = http.HttpResponse(html, content_type='text/html', mimetype='text/html')
+ # return response
+ # book_themes = {}
+ # for fragment in book.fragments.all().iterator():
+ # for theme in fragment.tags.filter(category='theme').iterator():
+ # book_themes.setdefault(theme, []).append(fragment)
+
+ # book_themes = book_themes.items()
+ # book_themes.sort(key=lambda s: s[0].sort_key)
- return render_to_response('catalogue/book_text.html', locals(),
- context_instance=RequestContext(request))
++ return render(request, 'catalogue/book_text.html', locals())
@never_cache
if not book.accessible(request):
return HttpResponseForbidden("Not authorized.")
- from tempfile import NamedTemporaryFile
- from os import unlink
- from librarian import pdf
- from catalogue.ebook_utils import RedakcjaDocProvider, serve_file
-
- xml = book.materialize()
- xml_file = NamedTemporaryFile()
- xml_file.write(xml.encode('utf-8'))
- xml_file.flush()
-
- try:
- pdf_file = NamedTemporaryFile(delete=False)
- pdf.transform(RedakcjaDocProvider(publishable=True),
- file_path=xml_file.name,
- output_file=pdf_file,
- )
- return serve_file(pdf_file.name, book.slug + '.pdf', 'application/pdf')
- finally:
- unlink(pdf_file.name)
+ # TODO: move to celery
+ doc = book.wldocument()
+ # TODO: error handling
+ pdf_file = doc.as_pdf()
+ from catalogue.ebook_utils import serve_file
+ return serve_file(pdf_file.get_filename(),
+ book.slug + '.pdf', 'application/pdf')
@never_cache
if not book.accessible(request):
return HttpResponseForbidden("Not authorized.")
- from StringIO import StringIO
- from tempfile import NamedTemporaryFile
- from librarian import epub
- from catalogue.ebook_utils import RedakcjaDocProvider
-
- xml = book.materialize()
- xml_file = NamedTemporaryFile()
- xml_file.write(xml.encode('utf-8'))
- xml_file.flush()
-
- epub_file = StringIO()
- epub.transform(RedakcjaDocProvider(publishable=True),
- file_path=xml_file.name,
- output_file=epub_file)
+ # TODO: move to celery
+ doc = book.wldocument()
+ # TODO: error handling
+ epub = doc.as_epub().get_string()
response = HttpResponse(mimetype='application/epub+zip')
response['Content-Disposition'] = 'attachment; filename=%s' % book.slug + '.epub'
- response.write(epub_file.getvalue())
+ response.write(epub)
return response
return http.HttpResponseRedirect(book.get_absolute_url())
else:
form = forms.BookForm(instance=book)
- editable = True
+ editable = True
else:
form = forms.ReadonlyBookForm(instance=book)
editable = False
- publish_error = publishable_error(book)
+ publish_error = book.publishable_error()
publishable = publish_error is None
- return direct_to_template(request, "catalogue/book_detail.html", extra_context={
+ return render(request, "catalogue/book_detail.html", {
"book": book,
"publishable": publishable,
"publishable_error": publish_error,
})
- publish_error = publishable_error(image)
+def image(request, slug):
+ image = get_object_or_404(Image, slug=slug)
+ if not image.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ if request.user.has_perm('catalogue.change_image'):
+ if request.method == "POST":
+ form = forms.ImageForm(request.POST, instance=image)
+ if form.is_valid():
+ form.save()
+ return http.HttpResponseRedirect(image.get_absolute_url())
+ else:
+ form = forms.ImageForm(instance=image)
+ editable = True
+ else:
+ form = forms.ReadonlyImageForm(instance=image)
+ editable = False
+
- return direct_to_template(request, "catalogue/image_detail.html", extra_context={
++ publish_error = image.publishable_error()
+ publishable = publish_error is None
+
++ return render(request, "catalogue/image_detail.html", {
+ "object": image,
+ "publishable": publishable,
+ "publishable_error": publish_error,
+ "form": form,
+ "editable": editable,
+ })
+
+
@permission_required('catalogue.add_chunk')
def chunk_add(request, slug, chunk):
try:
"title": "cz. %d" % (doc.number + 1, ),
})
- return direct_to_template(request, "catalogue/chunk_add.html", extra_context={
+ return render(request, "catalogue/chunk_add.html", {
"chunk": doc,
"form": form,
})
+ @login_required
def chunk_edit(request, slug, chunk):
try:
doc = Chunk.get(slug, chunk)
else:
go_next = ''
- return direct_to_template(request, "catalogue/chunk_edit.html", extra_context={
+ return render(request, "catalogue/chunk_edit.html", {
"chunk": doc,
"form": form,
"go_next": go_next,
})
+ @transaction.commit_on_success
+ @login_required
+ def chunk_mass_edit(request):
+ if request.method == 'POST':
+ ids = map(int, filter(lambda i: i.strip()!='', request.POST.get('ids').split(',')))
+ chunks = map(lambda i: Chunk.objects.get(id=i), ids)
+
+ stage = request.POST.get('stage')
+ if stage:
+ try:
+ stage = Chunk.tag_model.objects.get(slug=stage)
+ except Chunk.DoesNotExist, e:
+ stage = None
+
+ for c in chunks: c.stage = stage
+
+ username = request.POST.get('user')
+ logger.info("username: %s" % username)
+ logger.info(request.POST)
+ if username:
+ try:
+ user = User.objects.get(username=username)
+ except User.DoesNotExist, e:
+ user = None
+
+ for c in chunks: c.user = user
+
+ status = request.POST.get('status')
+ if status:
+ books_affected = set()
+ for c in chunks:
+ if status == 'publish':
+ c.head.publishable = True
+ c.head.save()
+ elif status == 'unpublish':
+ c.head.publishable = False
+ c.head.save()
+ c.touch() # cache
+ books_affected.add(c.book)
+ for b in books_affected:
+ b.touch() # cache
+
+ project_id = request.POST.get('project')
+ if project_id:
+ try:
+ project = Project.objects.get(pk=int(project_id))
+ except (Project.DoesNotExist, ValueError), e:
+ project = None
+ for c in chunks:
+ book = c.book
+ book.project = project
+ book.save()
+
+ for c in chunks: c.save()
+
+ return HttpResponse("", content_type="text/plain")
+ else:
+ raise Http404
+
+
@permission_required('catalogue.change_book')
def book_append(request, slug):
book = get_object_or_404(Book, slug=slug)
return http.HttpResponseRedirect(append_to.get_absolute_url())
else:
form = forms.BookAppendForm(book)
- return direct_to_template(request, "catalogue/book_append_to.html", extra_context={
+ return render(request, "catalogue/book_append_to.html", {
"book": book,
"form": form,
return http.HttpResponseRedirect(book.get_absolute_url())
+@require_POST
+@login_required
+def publish_image(request, slug):
+ image = get_object_or_404(Image, slug=slug)
+ if not image.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ try:
+ image.publish(request.user)
+ except NotAuthorizedError:
+ return http.HttpResponseRedirect(reverse('apiclient_oauth'))
+ except BaseException, e:
+ return http.HttpResponse(e)
+ else:
+ return http.HttpResponseRedirect(image.get_absolute_url())
++
++
+ class GalleryView(UploadView):
+ def get_object(self, request, slug):
+ book = get_object_or_404(Book, slug=slug)
+ if not book.gallery:
+ raise Http404
+ return book
+
+ def breadcrumbs(self):
+ return [
+ (_('books'), reverse('catalogue_document_list')),
+ (self.object.title, self.object.get_absolute_url()),
+ (_('scan gallery'),),
+ ]
+
+ def get_directory(self):
+ return "%s%s/" % (settings.IMAGE_DIR, self.object.gallery)
from django.core.files.storage import FileSystemStorage
from django.db import models, transaction
from django.db.models.base import ModelBase
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import string_concat, ugettext_lazy as _
- from mercurial import mdiff, simplemerge
+ from mercurial import simplemerge
from django.conf import settings
from dvcs.signals import post_commit, post_publishable
class Meta:
abstract = True
ordering = ['ordering']
- verbose_name = _("tag")
- verbose_name_plural = _("tags")
def __unicode__(self):
return self.name
def listener_changed(sender, instance, **kwargs):
sender._object_cache = {}
- def next(self):
+ def get_next(self):
"""
Returns the next tag - stage to work on.
Returns None for the last stage.
abstract = True
ordering = ('created_at',)
unique_together = ['tree', 'revision']
- verbose_name = _("change")
- verbose_name_plural = _("changes")
def __unicode__(self):
return u"Id: %r, Tree %r, Parent %r, Data: %s" % (self.id, self.tree_id, self.parent_id, self.data)
post_publishable.send(sender=self, publishable=publishable)
-
-
def create_tag_model(model):
name = model.__name__ + 'Tag'
class Meta(Tag.Meta):
app_label = model._meta.app_label
+ verbose_name = string_concat(_("tag"), " ", _("for:"), " ",
+ model._meta.verbose_name)
+ verbose_name_plural = string_concat(_("tags"), " ", _("for:"), " ",
+ model._meta.verbose_name)
attrs = {
'__module__': model.__module__,
class Meta(Change.Meta):
app_label = model._meta.app_label
+ verbose_name = string_concat(_("change"), " ", _("for:"), " ",
+ model._meta.verbose_name)
+ verbose_name_plural = string_concat(_("changes"), " ", _("for:"), " ",
+ model._meta.verbose_name)
attrs = {
'__module__': model.__module__,
tags = kwargs.get('tags', [])
if tags:
# set stage to next tag after the commited one
- self.stage = max(tags, key=lambda t: t.ordering).next()
+ self.stage = max(tags, key=lambda t: t.ordering).get_next()
change = self.change_set.create(author=author,
author_name=author_name,
{% extends "base.html" %}
{% load toolbar_tags i18n %}
-{% block title %}{{ book.title }} - {{ block.super }}{% endblock %}
+{% block titleextra %}{{ chunk.pretty_title }}{% endblock %}
{% block extrahead %}
{% load compressed %}
{% compressed_css 'detail' %}
{% endblock %}
{% block extrabody %}
-<script type="text/javascript" charset="utf-8">
+<script type="text/javascript">
var STATIC_URL = '{{STATIC_URL}}';
</script>
{% compressed_js 'detail' %}
</div>
<div id="header">
- <h1><a href="{% url catalogue_document_list %}"><img src="{{STATIC_URL}}icons/go-home.png" alt="Home" /></a><a href="{% url catalogue_document_list %}">Strona<br/>główna</a></h1>
- <h1><a href="{% url 'catalogue_document_list' %}"><img src="{{STATIC_URL}}icons/go-home.png"/><a href="{% url 'catalogue_document_list' %}">Strona<br>główna</a></h1>
++ <h1><a href="{% url 'catalogue_document_list' %}"><img src="{{STATIC_URL}}icons/go-home.png" alt="Home" /></a><a href="{% url 'catalogue_document_list' %}">Strona<br>główna</a></h1>
<div id="tools">
<a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">
{% trans "Help" %}</a>
<div id="side-gallery">
<!-- gallery toolbar -->
<div class="toolbar">
- <button class="previous-page">
- <img src="{{STATIC_URL}}icons/go-previous.png"
- alt="{% trans "Previous" %}" title="{% trans "Previous" %}"/>
+ <button class="start-page" alt="{% trans "Go to first image of this part" %}" title="{% trans "Go to first image of this part" %}">
+ <img src="{{STATIC_URL}}icons/revert.png"/>
+ </button>
+ <button class="previous-page" alt="{% trans "Previous" %}" title="{% trans "Previous" %}">
+ <img src="{{STATIC_URL}}icons/go-previous.png"/>
</button>
<input type="text" size="3" maxlength="3" value="0" class="page-number" />
- <span id="imagesCount" id="">/0</span>
+ <span id="imagesCount">/0</span>
- <button class="next-page">
+ <button class="next-page" alt="{% trans "Next" %}" title="{% trans "Next" %}">
- <img src="{{STATIC_URL}}icons/go-next.png"/>
+ <img src="{{STATIC_URL}}icons/go-next.png"
- alt="{% trans "Next" %}" title="{% trans "Next" %}"/>
++ alt="{% trans "Next" %}" title="{% trans "Next" %}"/>
</button>
<button class="zoom-in">{% trans "Zoom in" %}</button>
<button class="zoom-out">{% trans "Zoom out" %}</button>
<div class="error_message">
</div>
<div class="gallery-image">
- <img src="{{MEDIA_URL}}images/empty.png" />
+ <img src="{{MEDIA_URL}}images/empty.png" alt="no image" />
</div>
</div>
<!-- <div class="toolbar">
</div> -->
<div id="summary-view">
- <img class="book-cover" src="{{ STATIC_URL }}img/sample_cover.png" alt="Sample cover" />
+ <div class="summary-cover-area">
+ <p><img id="summary-cover" class="book-cover"
+ {% if revision %}
+ src="{% url 'cover_preview' chunk.book.slug chunk.slug revision %}"
+ {% else %}
+ src="{% url 'cover_preview' chunk.book.slug chunk.slug %}"
+ {% endif %}></p>
+ <p><button id="summary-cover-refresh">{% trans "Refresh from working copy" %}</button></p>
+ </div>
<h2>
- <label for="title">{% trans "Title" %}:</label>
+ <label>{% trans "Title" %}:</label>
<span data-ui-editable="true" data-edit-target="meta.displayTitle"
>{{ chunk.pretty_name }}</span>
</h2>
<p>
<label>{% trans "Current version" %}:</label>
{{ chunk.revision }} ({{ chunk.head.created_at }})
+ </p>
<p>
<label>{% trans "Last edited by" %}:</label>
{{ chunk.head.author }}
</p>
<p>
- <label for="gallery">{% trans "Link to gallery" %}:</label>
+ <label>{% trans "Link to gallery" %}:</label>
<span data-ui-editable="true" data-edit-target="meta.galleryLink"
>{{ chunk.book.gallery }}</span>
</p>
--- /dev/null
- <h1><a href="{% url catalogue_document_list %}"><img alt="Home" src="{{STATIC_URL}}icons/go-home.png"/></a><a href="{% url catalogue_document_list %}">Strona<br/>główna</a></h1>
+{% extends "base.html" %}
+{% load toolbar_tags i18n %}
+
+{% block title %}{{ document.title }} - {{ block.super }}{% endblock %}
+{% block extrahead %}
+{% load compressed %}
+{% compressed_css 'detail' %}
+{% endblock %}
+
+{% block extrabody %}
+<script type="text/javascript">
+ var STATIC_URL = '{{STATIC_URL}}';
+</script>
+{% compressed_js 'wiki_img' %}
+{% endblock %}
+
+{% block maincontent %}
+<div id="document-meta"
+ data-object-id="{{ document.pk }}" style="display:none">
+
+ <span data-key="revision">{{ revision }}</span>
+ <span data-key="diff">{{ request.GET.diff }}</span>
+
+ {% block meta-extra %} {% endblock %}
+</div>
+
+<div id="header">
++ <h1><a href="{% url 'catalogue_document_list' %}"><img alt="Home" src="{{STATIC_URL}}icons/go-home.png"/></a><a href="{% url 'catalogue_document_list' %}">Strona<br/>główna</a></h1>
+ <div id="tools">
+ <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">
+ {% trans "Help" %}</a>
+ | {% include "registration/head_login.html" %}
+ | {% trans "Version" %}: <span id="document-revision">{% trans "Unknown" %}</span>
+ {% if not readonly %}
+ | <button style="margin-left: 6px" id="save-button">{% trans "Save" %}</button>
+ <span id='save-attempt-info'>{% trans "Save attempt in progress" %}</span>
+ <span id='out-of-date-info'>{% trans "There is a newer version of this document!" %}</span>
+ {% endif %}
+ </div>
+ <ol id="tabs" class="tabs">
+ {% block tabs-menu %} {% endblock %}
+ </ol>
+</div>
+<div id="splitter">
+ <div id="editor" class="{% block editor-class %} {% endblock %}">
+ {% block tabs-content %} {% endblock %}
+ </div>
+</div>
+
+{% block dialogs %} {% endblock %}
+
+{% endblock %}
--- /dev/null
- data-basehref="{% url wiki_img_editor_readonly document.slug %}">{% trans "View version" %}</button>
+{% load i18n %}
+<div id="history-view-editor" class="editor" style="display: none">
+ <div class="toolbar">
+ <button type="button" id="make-diff-button"
+ data-enabled-when="2" disabled="disabled">{% trans "Compare versions" %}</button>
+ {% if can_pubmark %}
+ <button type="button" id="pubmark-changeset-button"
+ data-enabled-when="1" disabled="disabled">{% trans "Mark for publishing" %}</button>
+ {% endif %}
+ <button type="button" id="doc-revert-button"
+ data-enabled-when="1" disabled="disabled">{% trans "Revert document" %}</button>
+ <button id="open-preview-button" disabled="disabled"
+ data-enabled-when="1"
++ data-basehref="{% url 'wiki_img_editor_readonly' document.slug %}">{% trans "View version" %}</button>
+
+ </div>
+ <div id="history-view">
+ <p class="message-box" style="display:none;"></p>
+
+ <table id="changes-list-container">
+ <tbody id="changes-list">
+ </tbody>
+ <tbody style="display: none;">
+ <tr class="entry row-stub">
+ <td data-stub-value="version"></td>
+ <td>
+ <span data-stub-value="date"></span>
+ <br/><span data-stub-value="author"></span>
+ <br />
+ <span data-stub-value="description"></span>
+ </td>
+ <td>
+ <div data-stub-value="publishable"></div>
+ <div data-stub-value="tag"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
--- /dev/null
- from django.conf.urls.defaults import *
+# -*- coding: utf-8
++from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns('wiki_img.views',
+ url(r'^edit/(?P<slug>[^/]+)/$',
+ 'editor', name="wiki_img_editor"),
+
+ url(r'^readonly/(?P<slug>[^/]+)/$',
+ 'editor_readonly', name="wiki_img_editor_readonly"),
+
+ url(r'^text/(?P<image_id>\d+)/$',
+ 'text', name="wiki_img_text"),
+
+ url(r'^history/(?P<object_id>\d+)/$',
+ 'history', name="wiki_img_history"),
+
+ url(r'^revert/(?P<object_id>\d+)/$',
+ 'revert', name='wiki_img_revert'),
+
+ url(r'^diff/(?P<object_id>\d+)/$', 'diff', name="wiki_img_diff"),
+ url(r'^pubmark/(?P<object_id>\d+)/$', 'pubmark', name="wiki_img_pubmark"),
+
+)
--- /dev/null
- from django.views.generic.simple import direct_to_template
+import os
+import functools
+import logging
+logger = logging.getLogger("fnp.wiki_img")
+
- from django.shortcuts import get_object_or_404
+from django.core.urlresolvers import reverse
+from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
+ ajax_require_permission)
+
+from django import http
- return direct_to_template(request, template_name, extra_context={
++from django.shortcuts import get_object_or_404, render
+from django.views.decorators.http import require_GET, require_POST
+from django.conf import settings
+from django.utils.formats import localize
+from django.utils.translation import ugettext as _
+
+from catalogue.models import Image
+from wiki import forms
+from wiki import nice_diff
+from wiki_img.forms import ImageSaveForm
+
+#
+# Quick hack around caching problems, TODO: use ETags
+#
+from django.views.decorators.cache import never_cache
+
+
+@never_cache
+def editor(request, slug, template_name='wiki_img/document_details.html'):
+ doc = get_object_or_404(Image, slug=slug)
+
- return direct_to_template(request, template_name, extra_context={
++ return render(request, template_name, {
+ 'document': doc,
+ 'forms': {
+ "text_save": ImageSaveForm(user=request.user, prefix="textsave"),
+ "text_revert": forms.DocumentTextRevertForm(prefix="textrevert"),
+ "pubmark": forms.DocumentPubmarkForm(prefix="pubmark"),
+ },
+ 'can_pubmark': request.user.has_perm('catalogue.can_pubmark_image'),
+ 'REDMINE_URL': settings.REDMINE_URL,
+ })
+
+
+@require_GET
+def editor_readonly(request, slug, template_name='wiki_img/document_details_readonly.html'):
+ doc = get_object_or_404(Image, slug=slug)
+ try:
+ revision = request.GET['revision']
+ except (KeyError):
+ raise Http404
+
++ return render(request, template_name, {
+ 'document': doc,
+ 'revision': revision,
+ 'readonly': True,
+ 'REDMINE_URL': settings.REDMINE_URL,
+ })
+
+
+@never_cache
+def text(request, image_id):
+ doc = get_object_or_404(Image, pk=image_id)
+ if request.method == 'POST':
+ form = ImageSaveForm(request.POST, user=request.user, prefix="textsave")
+ if form.is_valid():
+ if request.user.is_authenticated():
+ author = request.user
+ else:
+ author = None
+ text = form.cleaned_data['text']
+ parent_revision = form.cleaned_data['parent_revision']
+ if parent_revision is not None:
+ parent = doc.at_revision(parent_revision)
+ else:
+ parent = None
+ stage = form.cleaned_data['stage_completed']
+ tags = [stage] if stage else []
+ publishable = (form.cleaned_data['publishable'] and
+ request.user.has_perm('catalogue.can_pubmark_image'))
+ doc.commit(author=author,
+ text=text,
+ parent=parent,
+ description=form.cleaned_data['comment'],
+ tags=tags,
+ author_name=form.cleaned_data['author_name'],
+ author_email=form.cleaned_data['author_email'],
+ publishable=publishable,
+ )
+ revision = doc.revision()
+ return JSONResponse({
+ 'text': doc.materialize() if parent_revision != revision else None,
+ 'meta': {},
+ 'revision': revision,
+ })
+ else:
+ return JSONFormInvalid(form)
+ else:
+ revision = request.GET.get("revision", None)
+
+ try:
+ revision = int(revision)
+ except (ValueError, TypeError):
+ revision = doc.revision()
+
+ if revision is not None:
+ text = doc.at_revision(revision).materialize()
+ else:
+ text = ''
+
+ return JSONResponse({
+ 'text': text,
+ 'meta': {},
+ 'revision': revision,
+ })
+
+
+@never_cache
+def history(request, object_id):
+ # TODO: pagination
+ doc = get_object_or_404(Image, pk=object_id)
+ if not doc.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ changes = []
+ for change in doc.history().reverse():
+ changes.append({
+ "version": change.revision,
+ "description": change.description,
+ "author": change.author_str(),
+ "date": localize(change.created_at),
+ "publishable": _("Publishable") + "\n" if change.publishable else "",
+ "tag": ',\n'.join(unicode(tag) for tag in change.tags.all()),
+ })
+ return JSONResponse(changes)
+
+
+@never_cache
+@require_POST
+def revert(request, object_id):
+ form = forms.DocumentTextRevertForm(request.POST, prefix="textrevert")
+ if form.is_valid():
+ doc = get_object_or_404(Image, pk=object_id)
+ if not doc.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ revision = form.cleaned_data['revision']
+
+ comment = form.cleaned_data['comment']
+ comment += "\n#revert to %s" % revision
+
+ if request.user.is_authenticated():
+ author = request.user
+ else:
+ author = None
+
+ before = doc.revision()
+ logger.info("Reverting %s to %s", object_id, revision)
+ doc.at_revision(revision).revert(author=author, description=comment)
+
+ return JSONResponse({
+ 'text': doc.materialize() if before != doc.revision() else None,
+ 'meta': {},
+ 'revision': doc.revision(),
+ })
+ else:
+ return JSONFormInvalid(form)
+
+
+@never_cache
+def diff(request, object_id):
+ revA = int(request.GET.get('from', 0))
+ revB = int(request.GET.get('to', 0))
+
+ if revA > revB:
+ revA, revB = revB, revA
+
+ if revB == 0:
+ revB = None
+
+ doc = get_object_or_404(Image, pk=object_id)
+ if not doc.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ # allow diff from the beginning
+ if revA:
+ docA = doc.at_revision(revA).materialize()
+ else:
+ docA = ""
+ docB = doc.at_revision(revB).materialize()
+
+ return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(),
+ docB.splitlines(), context=3))
+
+
+@require_POST
+@ajax_require_permission('catalogue.can_pubmark_image')
+def pubmark(request, object_id):
+ form = forms.DocumentPubmarkForm(request.POST, prefix="pubmark")
+ if form.is_valid():
+ doc = get_object_or_404(Image, pk=object_id)
+ if not doc.accessible(request):
+ return HttpResponseForbidden("Not authorized.")
+
+ revision = form.cleaned_data['revision']
+ publishable = form.cleaned_data['publishable']
+ change = doc.at_revision(revision)
+ if publishable != change.publishable:
+ change.set_publishable(publishable)
+ return JSONResponse({"message": _("Revision marked")})
+ else:
+ return JSONResponse({"message": _("Nothing changed")})
+ else:
+ return JSONFormInvalid(form)
- Subproject commit 859b209f96275dce7205f7c8011784d409a48de8
-Subproject commit 6351b433475b8119c8cd0cf7a8c72c623308c5d3
++Subproject commit 75a1b6f79da05e694d2528769cad5e964d761f34
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = PROJECT_ROOT + '/media/dynamic'
- STATIC_ROOT = PROJECT_ROOT + '/static/'
+ STATIC_ROOT = PROJECT_ROOT + '/../static/'
+
+ STATICFILES_DIRS = [
+ PROJECT_ROOT + '/static/'
+ ]
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
MEDIA_URL = '/media/dynamic/'
STATIC_URL = '/media/static/'
- # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
- # trailing slash.
- # Examples: "http://foo.com/media/", "/media/".
- ADMIN_MEDIA_PREFIX = '/media/admin-media/'
-
- # Make this unique, and don't share it with anybody.
- SECRET_KEY = 'ife@x^_lak+x84=lxtr!-ur$5g$+s6xt85gbbm@e_fk6q3r8=+'
SESSION_COOKIE_NAME = "redakcja_sessionid"
# List of callables that know how to import templates from various sources.
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_cas.middleware.CASMiddleware',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
'django.contrib.sites',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.comments',
- 'compress',
'south',
'sorl.thumbnail',
- 'filebrowser',
'pagination',
'gravatar',
'djcelery',
'djkombu',
+ 'fileupload',
+ 'pipeline',
'catalogue',
+ 'cover',
'dvcs',
'wiki',
+ 'wiki_img',
'toolbar',
'apiclient',
'email_mangler',
CAS_USER_ATTRS_MAP = {
'email': 'email', 'firstname': 'first_name', 'lastname': 'last_name'}
-
- FILEBROWSER_URL_FILEBROWSER_MEDIA = STATIC_URL + 'filebrowser/'
- FILEBROWSER_DIRECTORY = 'images/'
- FILEBROWSER_ADMIN_VERSIONS = []
- FILEBROWSER_VERSIONS_BASEDIR = 'thumbnails/'
- FILEBROWSER_DEFAULT_ORDER = "path_relative"
-
# REPOSITORY_PATH = '/Users/zuber/Projekty/platforma/files/books'
- IMAGE_DIR = 'images'
+
+ IMAGE_DIR = 'images/'
import djcelery
+ STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+ # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+ )
+
+
+ STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
+ PIPELINE_CSS_COMPRESSOR = None
+ PIPELINE_JS_COMPRESSOR = None
+ PIPELINE_STORAGE = 'pipeline.storage.PipelineFinderStorage'
+
+
# CSS and JS files to compress
- COMPRESS_CSS = {
+ PIPELINE_CSS = {
'detail': {
'source_filenames': (
'css/master.css',
'css/summary.css',
'css/html.css',
'css/jquery.autocomplete.css',
+ 'css/imgareaselect-default.css', #img!
'css/dialogs.css',
),
- 'output_filename': 'compressed/detail_styles_?.css',
+ 'output_filename': 'compressed/detail_styles.css',
},
'catalogue': {
'source_filenames': (
'css/filelist.css',
),
- 'output_filename': 'compressed/catalogue_styles_?.css',
- }
+ 'output_filename': 'compressed/catalogue_styles.css',
+ },
+ 'book': {
+ 'source_filenames': (
+ 'css/book.css',
+ ),
+ 'output_filename': 'compressed/book.css',
+ },
+ 'book_list': {
+ 'source_filenames': (
+ 'contextmenu/jquery.contextMenu.css',
+ 'css/book_list.css',
+ ),
+ 'output_filename': 'compressed/book_list.css',
+ },
}
- COMPRESS_JS = {
+ PIPELINE_JS = {
# everything except codemirror
'detail': {
'source_filenames': (
'js/wiki/view_search.js',
'js/wiki/view_column_diff.js',
),
- 'output_filename': 'compressed/detail_scripts_?.js',
+ 'output_filename': 'compressed/detail_scripts.js',
},
- 'output_filename': 'compressed/detail_img_scripts_?.js',
+ 'wiki_img': {
+ 'source_filenames': (
+ # libraries
+ 'js/lib/jquery-1.4.2.min.js',
+ 'js/lib/jquery/jquery.autocomplete.js',
+ 'js/lib/jquery/jquery.blockui.js',
+ 'js/lib/jquery/jquery.elastic.js',
+ 'js/lib/jquery/jquery.imgareaselect.js',
+ 'js/button_scripts.js',
+ 'js/slugify.js',
+
+ # wiki scripts
+ 'js/wiki_img/wikiapi.js',
+
+ # base UI
+ 'js/wiki_img/base.js',
+ 'js/wiki/toolbar.js',
+
+ # dialogs
+ 'js/wiki/dialog_save.js',
+ 'js/wiki/dialog_revert.js',
+ 'js/wiki/dialog_pubmark.js',
+
+ # views
+ 'js/wiki_img/view_editor_objects.js',
+ 'js/wiki_img/view_editor_motifs.js',
+ 'js/wiki/view_editor_source.js',
+ 'js/wiki/view_history.js',
+ 'js/wiki/view_column_diff.js',
+ ),
++ 'output_filename': 'compressed/detail_img_scripts.js',
+ },
'catalogue': {
'source_filenames': (
'js/catalogue/catalogue.js',
'js/slugify.js',
'email_mangler/email_mangler.js',
),
- 'output_filename': 'compressed/catalogue_scripts_?.js',
- }
+ 'output_filename': 'compressed/catalogue_scripts.js',
+ },
+ 'book': {
+ 'source_filenames': (
+ 'js/book_text/jquery.eventdelegation.js',
+ 'js/book_text/jquery.scrollto.js',
+ 'js/book_text/jquery.highlightfade.js',
+ 'js/book_text/book.js',
+ ),
+ 'output_filename': 'compressed/book.js',
+ },
+ 'book_list': {
+ 'source_filenames': (
+ 'contextmenu/jquery.ui.position.js',
+ 'contextmenu/jquery.contextMenu.js',
+ 'js/catalogue/book_list.js',
+ ),
+ 'output_filename': 'compressed/book_list.js',
+ }
}
-
- COMPRESS = True
- COMPRESS_CSS_FILTERS = None
- COMPRESS_JS_FILTERS = None
- COMPRESS_AUTO = True
- COMPRESS_VERSION = True
- COMPRESS_VERSIONING = 'compress.versioning.hash.MD5Versioning'
margin-bottom: -1px;
border-width: 1px;
border-style: solid;
- border-color: rgba(0,0,0,0);
+ border-color: transparent;
}
#tabs-nav-left .active {
#last-edited-list .date {
font-size: 70%;
- color: grey;
+ color: #808080;
}
a, a:visited, a:active {
- color: #bf6000;
+ color: #a05000;
text-decoration: none;
}
.wall .publish {
background-color: #fdc;
- }
+ }
+
+ div.cover-preview {
+ width: 216px;
+ min-height: 300px;
+ float: left;
+ margin-right: 2em;
+ }
+
+ img.cover-preview {
+ width: 216px;
+ height: 300px;
+ }
border-right: 2px solid #999;
cursor: pointer;
background: #C1C1C1;
+ z-index:100;
+ cursor: col-resize;
}
.vsplitbar:hover {
background-color: #E6E6E6;
}
-
.vsplitbar p {
font: 12px Helvetica,Verdana,sans-serif;
margin: 250px auto;
}
+ #drag-layer {
+ position:absolute;
+ top:0;
+ bottom:0;
+ left:0;
+ right:0;
+ z-index:1000;
+ display: none;
+ cursor: col-resize;
+ }
+
.editor {
position: absolute;
top: 0px;
overflow: hidden;
}
+.sideless .editor {
+ right: 0;
+}
+.image-object {
+ padding-left: 1em;
+ font: 12px Sans, Helvetica, Verdana, sans-serif;
+}
+.image-object:hover {
+ cursor: pointer;
+}
+#objects-list .delete {
+ padding-left: 3px;
+ font: 10px Sans, Helvetica, Verdana, sans-serif;
+}
+#objects-list .delete:hover {
+ cursor: pointer;
+}
+
+#objects-list .active {
+ color: #800;
+}
+
+
#editor.readonly .editor {
right: 0px;
}
font: 11px Helvetica, Verdana, sans-serif;
font-weight: bold;
+
+ z-index: 100;
}
float: left;
}
+.tabs a {
+ color: black;
+}
+
#tabs-right {
float: right;
padding-right: 1em;
.saveNotify {
position:absolute;
- top:22px;
+ bottom:22px;
right:7px;
z-index:800;
background-color: #FFFF69;
.saveNotify span {
font-weight: bold;
}
+
+
+
+.scrolled {
+ position: absolute;
+ top: 29px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: auto;
+}
--- /dev/null
- * version 0.9.3
+/*
+ * imgAreaSelect jQuery plugin
- * Copyright (c) 2008-2010 Michal Wojciechowski (odyniec.net)
++ * version 0.9.10
+ *
- resizeMargin = 10,
-
++ * Copyright (c) 2008-2013 Michal Wojciechowski (odyniec.net)
+ *
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://odyniec.net/projects/imgareaselect/
+ *
+ */
+
+(function($) {
+
+var abs = Math.abs,
+ max = Math.max,
+ min = Math.min,
+ round = Math.round;
+
+function div() {
+ return $('<div/>');
+}
+
+$.imgAreaSelect = function (img, options) {
+ var
+
+ $img = $(img),
+
+ imgLoaded,
+
+ $box = div(),
+ $area = div(),
+ $border = div().add(div()).add(div()).add(div()),
+ $outer = div().add(div()).add(div()).add(div()),
+ $handles = $([]),
+
+ $areaOpera,
+
+ left, top,
+
+ imgOfs = { left: 0, top: 0 },
+
+ imgWidth, imgHeight,
+
+ $parent,
+
+ parOfs = { left: 0, top: 0 },
+
+ zIndex = 0,
+
+ position = 'absolute',
+
+ startX, startY,
+
+ scaleX, scaleY,
+
- x1: round(x1 / sx),
- y1: round(y1 / sy),
- x2: round(x2 / sx),
- y2: round(y2 / sy)
+ resize,
+
+ minWidth, minHeight, maxWidth, maxHeight,
+
+ aspectRatio,
+
+ shown,
+
+ x1, y1, x2, y2,
+
+ selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 },
+
+ docElem = document.documentElement,
+
++ ua = navigator.userAgent,
++
+ $p, d, i, o, w, h, adjusted;
+
+ function viewX(x) {
+ return x + imgOfs.left - parOfs.left;
+ }
+
+ function viewY(y) {
+ return y + imgOfs.top - parOfs.top;
+ }
+
+ function selX(x) {
+ return x - imgOfs.left + parOfs.left;
+ }
+
+ function selY(y) {
+ return y - imgOfs.top + parOfs.top;
+ }
+
+ function evX(event) {
+ return event.pageX - parOfs.left;
+ }
+
+ function evY(event) {
+ return event.pageY - parOfs.top;
+ }
+
+ function getSelection(noScale) {
+ var sx = noScale || scaleX, sy = noScale || scaleY;
+
+ return { x1: round(selection.x1 * sx),
+ y1: round(selection.y1 * sy),
+ x2: round(selection.x2 * sx),
+ y2: round(selection.y2 * sy),
+ width: round(selection.x2 * sx) - round(selection.x1 * sx),
+ height: round(selection.y2 * sy) - round(selection.y1 * sy) };
+ }
+
+ function setSelection(x1, y1, x2, y2, noScale) {
+ var sx = noScale || scaleX, sy = noScale || scaleY;
+
+ selection = {
- if (!$img.width())
++ x1: round(x1 / sx || 0),
++ y1: round(y1 / sy || 0),
++ x2: round(x2 / sx || 0),
++ y2: round(y2 / sy || 0)
+ };
+
+ selection.width = selection.x2 - selection.x1;
+ selection.height = selection.y2 - selection.y1;
+ }
+
+ function adjust() {
- imgWidth = $img.width();
- imgHeight = $img.height();
++ if (!imgLoaded || !$img.width())
+ return;
+
+ imgOfs = { left: round($img.offset().left), top: round($img.offset().top) };
+
- minWidth = options.minWidth || 0;
- minHeight = options.minHeight || 0;
- maxWidth = min(options.maxWidth || 1<<24, imgWidth);
- maxHeight = min(options.maxHeight || 1<<24, imgHeight);
++ imgWidth = $img.innerWidth();
++ imgHeight = $img.innerHeight();
++
++ imgOfs.top += ($img.outerHeight() - imgHeight) >> 1;
++ imgOfs.left += ($img.outerWidth() - imgWidth) >> 1;
+
- parOfs = $.inArray($parent.css('position'), ['absolute', 'relative']) + 1 ?
++ minWidth = round(options.minWidth / scaleX) || 0;
++ minHeight = round(options.minHeight / scaleY) || 0;
++ maxWidth = round(min(options.maxWidth / scaleX || 1<<24, imgWidth));
++ maxHeight = round(min(options.maxHeight / scaleY || 1<<24, imgHeight));
+
+ if ($().jquery == '1.3.2' && position == 'fixed' &&
+ !docElem['getBoundingClientRect'])
+ {
+ imgOfs.top += max(document.body.scrollTop, docElem.scrollTop);
+ imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft);
+ }
+
- $($handles[4]).css({ left: w / 2 });
- $($handles[5]).css({ left: w, top: h / 2 });
- $($handles[6]).css({ left: w / 2, top: h });
- $($handles[7]).css({ top: h / 2 });
++ parOfs = /absolute|relative/.test($parent.css('position')) ?
+ { left: round($parent.offset().left) - $parent.scrollLeft(),
+ top: round($parent.offset().top) - $parent.scrollTop() } :
+ position == 'fixed' ?
+ { left: $(document).scrollLeft(), top: $(document).scrollTop() } :
+ { left: 0, top: 0 };
+
+ left = viewX(0);
+ top = viewY(0);
+
+ if (selection.x2 > imgWidth || selection.y2 > imgHeight)
+ doResize();
+ }
+
+ function update(resetKeyPress) {
+ if (!shown) return;
+
+ $box.css({ left: viewX(selection.x1), top: viewY(selection.y1) })
+ .add($area).width(w = selection.width).height(h = selection.height);
+
+ $area.add($border).add($handles).css({ left: 0, top: 0 });
+
+ $border
+ .width(max(w - $border.outerWidth() + $border.innerWidth(), 0))
+ .height(max(h - $border.outerHeight() + $border.innerHeight(), 0));
+
+ $($outer[0]).css({ left: left, top: top,
+ width: selection.x1, height: imgHeight });
+ $($outer[1]).css({ left: left + selection.x1, top: top,
+ width: w, height: selection.y1 });
+ $($outer[2]).css({ left: left + selection.x2, top: top,
+ width: imgWidth - selection.x2, height: imgHeight });
+ $($outer[3]).css({ left: left + selection.x1, top: top + selection.y2,
+ width: w, height: imgHeight - selection.y2 });
+
+ w -= $handles.outerWidth();
+ h -= $handles.outerHeight();
+
+ switch ($handles.length) {
+ case 8:
- if ($.imgAreaSelect.keyPress != docKeyPress)
++ $($handles[4]).css({ left: w >> 1 });
++ $($handles[5]).css({ left: w, top: h >> 1 });
++ $($handles[6]).css({ left: w >> 1, top: h });
++ $($handles[7]).css({ top: h >> 1 });
+ case 4:
+ $handles.slice(1,3).css({ left: w });
+ $handles.slice(2,4).css({ top: h });
+ }
+
+ if (resetKeyPress !== false) {
- if ($.browser.msie && $border.outerWidth() - $border.innerWidth() == 2) {
++ if ($.imgAreaSelect.onKeyPress != docKeyPress)
+ $(document).unbind($.imgAreaSelect.keyPress,
+ $.imgAreaSelect.onKeyPress);
+
+ if (options.keys)
+ $(document)[$.imgAreaSelect.keyPress](
+ $.imgAreaSelect.onKeyPress = docKeyPress);
+ }
+
- if (y <= resizeMargin)
++ if (msie && $border.outerWidth() - $border.innerWidth() == 2) {
+ $border.css('margin', 0);
+ setTimeout(function () { $border.css('margin', 'auto'); }, 0);
+ }
+ }
+
+ function doUpdate(resetKeyPress) {
+ adjust();
+ update(resetKeyPress);
+ x1 = viewX(selection.x1); y1 = viewY(selection.y1);
+ x2 = viewX(selection.x2); y2 = viewY(selection.y2);
+ }
+
+ function hide($elem, fn) {
+ options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide();
+
+ }
+
+ function areaMouseMove(event) {
+ var x = selX(evX(event)) - selection.x1,
+ y = selY(evY(event)) - selection.y1;
+
+ if (!adjusted) {
+ adjust();
+ adjusted = true;
+
+ $box.one('mouseout', function () { adjusted = false; });
+ }
+
+ resize = '';
+
+ if (options.resizable) {
- else if (y >= selection.height - resizeMargin)
++ if (y <= options.resizeMargin)
+ resize = 'n';
- if (x <= resizeMargin)
++ else if (y >= selection.height - options.resizeMargin)
+ resize = 's';
- else if (x >= selection.width - resizeMargin)
++ if (x <= options.resizeMargin)
+ resize += 'w';
-
++ else if (x >= selection.width - options.resizeMargin)
+ resize += 'e';
+ }
+
+ $box.css('cursor', resize ? resize + '-resize' :
+ options.movable ? 'move' : '');
+ if ($areaOpera)
+ $areaOpera.toggle();
+ }
+
+ function docMouseUp(event) {
+ $('body').css('cursor', '');
- options.onSelectEnd(img, getSelection());
-
+ if (options.autoHide || selection.width * selection.height == 0)
+ hide($box.add($outer), function () { $(this).hide(); });
+
- x2 = resize == '' || /w|e/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
- y2 = resize == '' || /n|s/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
+ $(document).unbind('mousemove', selectingMouseMove);
+ $box.mousemove(areaMouseMove);
++
++ options.onSelectEnd(img, getSelection());
+ }
+
+ function areaMouseDown(event) {
+ if (event.which != 1) return false;
+
+ adjust();
+
+ if (resize) {
+ $('body').css('cursor', resize + '-resize');
+
+ x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']);
+ y1 = viewY(selection[/n/.test(resize) ? 'y2' : 'y1']);
+
+ $(document).mousemove(selectingMouseMove)
+ .one('mouseup', docMouseUp);
+ $box.unbind('mousemove', areaMouseMove);
+ }
+ else if (options.movable) {
+ startX = left + selection.x1 - evX(event);
+ startY = top + selection.y1 - evY(event);
+
+ $box.unbind('mousemove', areaMouseMove);
+
+ $(document).mousemove(movingMouseMove)
+ .one('mouseup', function () {
+ options.onSelectEnd(img, getSelection());
+
+ $(document).unbind('mousemove', movingMouseMove);
+ $box.mousemove(areaMouseMove);
+ });
+ }
+ else
+ $img.mousedown(event);
+
+ return false;
+ }
+
+ function fixAspectRatio(xFirst) {
+ if (aspectRatio)
+ if (xFirst) {
+ x2 = max(left, min(left + imgWidth,
+ x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)));
+
+ y2 = round(max(top, min(top + imgHeight,
+ y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))));
+ x2 = round(x2);
+ }
+ else {
+ y2 = max(top, min(top + imgHeight,
+ y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1)));
+ x2 = round(max(left, min(left + imgWidth,
+ x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1))));
+ y2 = round(y2);
+ }
+ }
+
+ function doResize() {
+ x1 = min(x1, left + imgWidth);
+ y1 = min(y1, top + imgHeight);
+
+ if (abs(x2 - x1) < minWidth) {
+ x2 = x1 - minWidth * (x2 < x1 || -1);
+
+ if (x2 < left)
+ x1 = left + minWidth;
+ else if (x2 > left + imgWidth)
+ x1 = left + imgWidth - minWidth;
+ }
+
+ if (abs(y2 - y1) < minHeight) {
+ y2 = y1 - minHeight * (y2 < y1 || -1);
+
+ if (y2 < top)
+ y1 = top + minHeight;
+ else if (y2 > top + imgHeight)
+ y1 = top + imgHeight - minHeight;
+ }
+
+ x2 = max(left, min(x2, left + imgWidth));
+ y2 = max(top, min(y2, top + imgHeight));
+
+ fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio);
+
+ if (abs(x2 - x1) > maxWidth) {
+ x2 = x1 - maxWidth * (x2 < x1 || -1);
+ fixAspectRatio();
+ }
+
+ if (abs(y2 - y1) > maxHeight) {
+ y2 = y1 - maxHeight * (y2 < y1 || -1);
+ fixAspectRatio(true);
+ }
+
+ selection = { x1: selX(min(x1, x2)), x2: selX(max(x1, x2)),
+ y1: selY(min(y1, y2)), y2: selY(max(y1, y2)),
+ width: abs(x2 - x1), height: abs(y2 - y1) };
+
+ update();
+
+ options.onSelectChange(img, getSelection());
+ }
+
+ function selectingMouseMove(event) {
- if ($outer.is(':not(:visible)'))
++ x2 = /w|e|^$/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
++ y2 = /n|s|^$/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
+
+ doResize();
+
+ return false;
+
+ }
+
+ function doMove(newX1, newY1) {
+ x2 = (x1 = newX1) + selection.width;
+ y2 = (y1 = newY1) + selection.height;
+
+ $.extend(selection, { x1: selX(x1), y1: selY(y1), x2: selX(x2),
+ y2: selY(y2) });
+
+ update();
+
+ options.onSelectChange(img, getSelection());
+ }
+
+ function movingMouseMove(event) {
+ x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width));
+ y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height));
+
+ doMove(x1, y1);
+
+ event.preventDefault();
+
+ return false;
+ }
+
+ function startSelection() {
++ $(document).unbind('mousemove', startSelection);
+ adjust();
+
+ x2 = x1;
+ y2 = y1;
+
+ doResize();
+
+ resize = '';
+
- $(document).unbind('mousemove', startSelection);
++ if (!$outer.is(':visible'))
+ $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
+
+ shown = true;
+
+ $(document).unbind('mouseup', cancelSelection)
+ .mousemove(selectingMouseMove).one('mouseup', docMouseUp);
+ $box.unbind('mousemove', areaMouseMove);
+
+ options.onSelectStart(img, getSelection());
+ }
+
+ function cancelSelection() {
- selection = { x1: selX(x1), y1: selY(y1), x2: selX(x1), y2: selY(y1),
- width: 0, height: 0 };
++ $(document).unbind('mousemove', startSelection)
++ .unbind('mouseup', cancelSelection);
+ hide($box.add($outer));
+
- options.onSelectChange(img, getSelection());
- options.onSelectEnd(img, getSelection());
++ setSelection(selX(x1), selY(y1), selX(x1), selY(y1));
+
- $(document).one('mousemove', startSelection)
- .one('mouseup', cancelSelection);
++ if (!(this instanceof $.imgAreaSelect)) {
++ options.onSelectChange(img, getSelection());
++ options.onSelectEnd(img, getSelection());
++ }
+ }
+
+ function imgMouseDown(event) {
+ if (event.which != 1 || $outer.is(':animated')) return false;
+
+ adjust();
+ startX = x1 = evX(event);
+ startY = y1 = evY(event);
+
- resizable: true,
++ $(document).mousemove(startSelection).mouseup(cancelSelection);
+
+ return false;
+ }
+
+ function windowResize() {
+ doUpdate(false);
+ }
+
+ function imgLoad() {
+ imgLoaded = true;
+
+ setOptions(options = $.extend({
+ classPrefix: 'imgareaselect',
+ movable: true,
- for (option in props)
+ parent: 'body',
++ resizable: true,
++ resizeMargin: 10,
+ onInit: function () {},
+ onSelectStart: function () {},
+ onSelectChange: function () {},
+ onSelectEnd: function () {}
+ }, options));
+
+ $box.add($outer).css({ visibility: '' });
+
+ if (options.show) {
+ shown = true;
+ adjust();
+ update();
+ $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
+ }
+
+ setTimeout(function () { options.onInit(img, getSelection()); }, 0);
+ }
+
+ var docKeyPress = function(event) {
+ var k = options.keys, d, t, key = event.keyCode;
+
+ d = !isNaN(k.alt) && (event.altKey || event.originalEvent.altKey) ? k.alt :
+ !isNaN(k.ctrl) && event.ctrlKey ? k.ctrl :
+ !isNaN(k.shift) && event.shiftKey ? k.shift :
+ !isNaN(k.arrows) ? k.arrows : 10;
+
+ if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) ||
+ (k.ctrl == 'resize' && event.ctrlKey) ||
+ (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey)))
+ {
+ switch (key) {
+ case 37:
+ d = -d;
+ case 39:
+ t = max(x1, x2);
+ x1 = min(x1, x2);
+ x2 = max(t + d, x1);
+ fixAspectRatio();
+ break;
+ case 38:
+ d = -d;
+ case 40:
+ t = max(y1, y2);
+ y1 = min(y1, y2);
+ y2 = max(t + d, y1);
+ fixAspectRatio(true);
+ break;
+ default:
+ return;
+ }
+
+ doResize();
+ }
+ else {
+ x1 = min(x1, x2);
+ y1 = min(y1, y2);
+
+ switch (key) {
+ case 37:
+ doMove(max(x1 - d, left), y1);
+ break;
+ case 38:
+ doMove(x1, max(y1 - d, top));
+ break;
+ case 39:
+ doMove(x1 + min(d, imgWidth - selX(x2)), y1);
+ break;
+ case 40:
+ doMove(x1, y1 + min(d, imgHeight - selY(y2)));
+ break;
+ default:
+ return;
+ }
+ }
+
+ return false;
+ };
+
+ function styleOptions($elem, props) {
- $box.append($area.add($border).add($handles).add($areaOpera));
++ for (var option in props)
+ if (options[option] !== undefined)
+ $elem.css(props[option], options[option]);
+ }
+
+ function setOptions(newOptions) {
+ if (newOptions.parent)
+ ($parent = $(newOptions.parent)).append($box.add($outer));
+
+ $.extend(options, newOptions);
+
+ adjust();
+
+ if (newOptions.handles != null) {
+ $handles.remove();
+ $handles = $([]);
+
+ i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0;
+
+ while (i--)
+ $handles = $handles.add(div());
+
+ $handles.addClass(options.classPrefix + '-handle').css({
+ position: 'absolute',
+ fontSize: 0,
+ zIndex: zIndex + 1 || 1
+ });
+
+ if (!parseInt($handles.css('width')) >= 0)
+ $handles.width(5).height(5);
+
+ if (o = options.borderWidth)
+ $handles.css({ borderWidth: o, borderStyle: 'solid' });
+
+ styleOptions($handles, { borderColor1: 'border-color',
+ borderColor2: 'background-color',
+ borderOpacity: 'opacity' });
+ }
+
+ scaleX = options.imageWidth / imgWidth || 1;
+ scaleY = options.imageHeight / imgHeight || 1;
+
+ if (newOptions.x1 != null) {
+ setSelection(newOptions.x1, newOptions.y1, newOptions.x2,
+ newOptions.y2);
+ newOptions.show = !newOptions.hide;
+ }
+
+ if (newOptions.keys)
+ options.keys = $.extend({ shift: 1, ctrl: 'resize' },
+ newOptions.keys);
+
+ $outer.addClass(options.classPrefix + '-outer');
+ $area.addClass(options.classPrefix + '-selection');
+ for (i = 0; i++ < 4;)
+ $($border[i-1]).addClass(options.classPrefix + '-border' + i);
+
+ styleOptions($area, { selectionColor: 'background-color',
+ selectionOpacity: 'opacity' });
+ styleOptions($border, { borderOpacity: 'opacity',
+ borderWidth: 'border-width' });
+ styleOptions($outer, { outerColor: 'background-color',
+ outerOpacity: 'opacity' });
+ if (o = options.borderColor1)
+ $($border[0]).css({ borderStyle: 'solid', borderColor: o });
+ if (o = options.borderColor2)
+ $($border[1]).css({ borderStyle: 'dashed', borderColor: o });
+
- if ($.browser.msie) {
- if (o = $outer.css('filter').match(/opacity=([0-9]+)/))
++ $box.append($area.add($border).add($areaOpera)).append($handles);
+
- if (o = $border.css('filter').match(/opacity=([0-9]+)/))
++ if (msie) {
++ if (o = ($outer.css('filter')||'').match(/opacity=(\d+)/))
+ $outer.css('opacity', o[1]/100);
- $img.unbind('mousedown', imgMouseDown);
++ if (o = ($border.css('filter')||'').match(/opacity=(\d+)/))
+ $border.css('opacity', o[1]/100);
+ }
+
+ if (newOptions.hide)
+ hide($box.add($outer));
+ else if (newOptions.show && imgLoaded) {
+ shown = true;
+ $box.add($outer).fadeIn(options.fadeSpeed||0);
+ doUpdate();
+ }
+
+ aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1];
+
+ $img.add($outer).unbind('mousedown', imgMouseDown);
+
+ if (options.disable || options.enable === false) {
+ $box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
+ $(window).unbind('resize', windowResize);
+ }
+ else {
+ if (options.enable || options.disable === false) {
+ if (options.resizable || options.movable)
+ $box.mousemove(areaMouseMove).mousedown(areaMouseDown);
+
+ $(window).resize(windowResize);
+ }
+
+ if (!options.persistent)
+ $img.add($outer).mousedown(imgMouseDown);
+ }
+
+ options.enable = options.disable = undefined;
+ }
+
+ this.remove = function () {
- if ($.browser.msie)
++ setOptions({ disable: true });
+ $box.add($outer).remove();
+ };
+
+ this.getOptions = function () { return options; };
+
+ this.setOptions = setOptions;
+
+ this.getSelection = getSelection;
+
+ this.setSelection = setSelection;
+
++ this.cancelSelection = cancelSelection;
++
+ this.update = doUpdate;
+
++ var msie = (/msie ([\w.]+)/i.exec(ua)||[])[1],
++ opera = /opera/i.test(ua),
++ safari = /webkit/i.test(ua) && !/chrome/i.test(ua);
++
+ $p = $img;
+
+ while ($p.length) {
+ zIndex = max(zIndex,
+ !isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex);
+ if ($p.css('position') == 'fixed')
+ position = 'fixed';
+
+ $p = $p.parent(':not(body)');
+ }
+
+ zIndex = options.zIndex || zIndex;
+
- $.imgAreaSelect.keyPress = $.browser.msie ||
- $.browser.safari ? 'keydown' : 'keypress';
++ if (msie)
+ $img.attr('unselectable', 'on');
+
- if ($.browser.opera)
++ $.imgAreaSelect.keyPress = msie || safari ? 'keydown' : 'keypress';
++
++ if (opera)
+
+ $areaOpera = div().css({ width: '100%', height: '100%',
+ position: 'absolute', zIndex: zIndex + 2 || 2 });
+
+ $box.add($outer).css({ visibility: 'hidden', position: position,
+ overflow: 'hidden', zIndex: zIndex || '0' });
+ $box.css({ zIndex: zIndex + 2 || 2 });
+ $area.add($border).css({ position: 'absolute', fontSize: 0 });
+
+ img.complete || img.readyState == 'complete' || !$img.is('img') ?
+ imgLoad() : $img.one('load', imgLoad);
++
++ if (!imgLoaded && msie && msie >= 7)
++ img.src = img.src;
+};
+
+$.fn.imgAreaSelect = function (options) {
+ options = options || {};
+
+ this.each(function () {
+ if ($(this).data('imgAreaSelect')) {
+ if (options.remove) {
+ $(this).data('imgAreaSelect').remove();
+ $(this).removeData('imgAreaSelect');
+ }
+ else
+ $(this).data('imgAreaSelect').setOptions(options);
+ }
+ else if (!options.remove) {
+ if (options.enable === undefined && options.disable === undefined)
+ options.enable = true;
+
+ $(this).data('imgAreaSelect', new $.imgAreaSelect(this, options));
+ }
+ });
+
+ if (options.instance)
+ return $(this).data('imgAreaSelect');
+
+ return this;
+};
+
+})(jQuery);
function initialize()
{
+ var splitter = $('#splitter'),
+ editors = $('#editor .editor'),
+ vsplitbar = $('.vsplitbar'),
+ sidebar = $('#sidebar'),
+ dragLayer = $('#drag-layer'),
+ vsplitbarWidth = vsplitbar.outerWidth(),
+ isHolding = false;
+
+ // Moves panes so that left border of the vsplitbar lands x pixels from the left border of the splitter
+ function setSplitbarAt(x) {
+ var right = splitterWidth - x;
+ editors.each(function() {
+ this.style.right = right + 'px';
+ });
+ vsplitbar[0].style.right = sidebar[0].style.width = (right - vsplitbarWidth) + 'px';
+ };
+
$(document).keydown(function(event) {
console.log("Received key:", event);
});
* TABS
*/
$('.tabs li').live('click', function(event, callback) {
+ event.preventDefault();
$.wiki.switchToTab(this);
});
$(window).resize(function(){
$('iframe').height($(window).height() - $('#tabs').outerHeight() - $('#source-editor .toolbar').outerHeight());
+ splitterWidth = splitter.width();
});
$(window).resize();
- $('.vsplitbar').toggle(
+ vsplitbar.toggle(
function() {
$.wiki.state.perspectives.ScanGalleryPerspective.show = true;
- $('#sidebar').show();
- $('.vsplitbar').css('right', 480).addClass('active');
- $('#editor .editor').css('right', 510);
+ setSplitbarAt(splitterWidth - (480 + vsplitbarWidth));
+ $('.vsplitbar').addClass('active');
$(window).resize();
$.wiki.perspectiveForTab('#tabs-right .active').onEnter();
},
function() {
var active_right = $.wiki.perspectiveForTab('#tabs-right .active');
$.wiki.state.perspectives.ScanGalleryPerspective.show = false;
- $('#sidebar').hide();
- $('.vsplitbar').css('right', 0).removeClass('active');
$(".vsplitbar-title").html("↑ " + active_right.vsplitbar + " ↑");
- $('#editor .editor').css('right', 30);
+ setSplitbarAt(splitterWidth - vsplitbarWidth);
+ $('.vsplitbar').removeClass('active');
$(window).resize();
active_right.onExit();
}
);
+
+ /* Splitbar dragging support */
+ vsplitbar
+ .mousedown(function(e) {
+ e.preventDefault();
+ isHolding = true;
+ })
+ .mousemove(function(e) {
+ if(isHolding) {
+ dragLayer.show(); // We don't show it up until now so that we don't lose single click events on vsplitbar
+ }
+ });
+ dragLayer.mousemove(function(e) {
+ setSplitbarAt(e.clientX - vsplitbarWidth/2);
+ });
+ $('body').mouseup(function(e) {
+ dragLayer.hide();
+ isHolding = false;
+ });
+
+
if($.wiki.state.perspectives.ScanGalleryPerspective.show){
$('.vsplitbar').trigger('click');
$(".vsplitbar-title").html("↓ GALERIA ↓");
# -*- coding: utf-8 -*-
- from django.conf.urls.defaults import *
+ from django.conf.urls import include, patterns, url
from django.contrib import admin
from django.conf import settings
+ from django.conf.urls.static import static
+ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+ from django.views.generic import RedirectView
admin.autodiscover()
urlpatterns = patterns('',
# Auth
- #url(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
- #url(r'^accounts/logout/$', 'catalogue.views.logout_then_redirect', name='logout'),
-
url(r'^accounts/login/$', 'django_cas.views.login', name='login'),
url(r'^accounts/logout/$', 'django_cas.views.logout', name='logout'),
+ url(r'^admin/login/$', 'django_cas.views.login', name='login'),
+ url(r'^admin/logout/$', 'django_cas.views.logout', name='logout'),
# Admin panel
- (r'^admin/filebrowser/', include('filebrowser.urls')),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^admin/', include(admin.site.urls)),
(r'^comments/', include('django.contrib.comments.urls')),
- url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/documents/'}),
+ url(r'^$', RedirectView.as_view(url= '/documents/')),
url(r'^documents/', include('catalogue.urls')),
url(r'^apiclient/', include('apiclient.urls')),
url(r'^editor/', include('wiki.urls')),
-
- # Static files (should be served by Apache)
- url(r'^%s(?P<path>.+)$' % settings.MEDIA_URL[1:], 'django.views.static.serve',
- {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
- url(r'^%s(?P<path>.+)$' % settings.ADMIN_MEDIA_PREFIX[1:], 'django.views.static.serve',
- {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
- url(r'^%s(?P<path>.+)$' % settings.STATIC_URL[1:], 'django.views.static.serve',
- {'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
-
- url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/documents/'}),
-
+ url(r'^images/', include('wiki_img.urls')),
+ url(r'^cover/', include('cover.urls')),
)
+
+ if settings.DEBUG:
+ urlpatterns += staticfiles_urlpatterns()
+ urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)