Show More
@@ -0,0 +1,92 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | from south.utils import datetime_utils as datetime | |||
|
3 | from south.db import db | |||
|
4 | from south.v2 import SchemaMigration | |||
|
5 | from django.db import models | |||
|
6 | ||||
|
7 | ||||
|
8 | class Migration(SchemaMigration): | |||
|
9 | ||||
|
10 | def forwards(self, orm): | |||
|
11 | # Adding field 'Post.image_pre_width' | |||
|
12 | db.add_column(u'boards_post', 'image_pre_width', | |||
|
13 | self.gf('django.db.models.fields.IntegerField')(default=0), | |||
|
14 | keep_default=False) | |||
|
15 | ||||
|
16 | # Adding field 'Post.image_pre_height' | |||
|
17 | db.add_column(u'boards_post', 'image_pre_height', | |||
|
18 | self.gf('django.db.models.fields.IntegerField')(default=0), | |||
|
19 | keep_default=False) | |||
|
20 | ||||
|
21 | ||||
|
22 | def backwards(self, orm): | |||
|
23 | # Deleting field 'Post.image_pre_width' | |||
|
24 | db.delete_column(u'boards_post', 'image_pre_width') | |||
|
25 | ||||
|
26 | # Deleting field 'Post.image_pre_height' | |||
|
27 | db.delete_column(u'boards_post', 'image_pre_height') | |||
|
28 | ||||
|
29 | ||||
|
30 | models = { | |||
|
31 | 'boards.ban': { | |||
|
32 | 'Meta': {'object_name': 'Ban'}, | |||
|
33 | 'can_read': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), | |||
|
34 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
35 | 'ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), | |||
|
36 | 'reason': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '200'}) | |||
|
37 | }, | |||
|
38 | 'boards.post': { | |||
|
39 | 'Meta': {'object_name': 'Post'}, | |||
|
40 | '_text_rendered': ('django.db.models.fields.TextField', [], {}), | |||
|
41 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
42 | 'image': ('boards.thumbs.ImageWithThumbsField', [], {'max_length': '100', 'blank': 'True'}), | |||
|
43 | 'image_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |||
|
44 | 'image_pre_height': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |||
|
45 | 'image_pre_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |||
|
46 | 'image_width': ('django.db.models.fields.IntegerField', [], {'default': '0'}), | |||
|
47 | 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), | |||
|
48 | 'poster_ip': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}), | |||
|
49 | 'poster_user_agent': ('django.db.models.fields.TextField', [], {}), | |||
|
50 | 'pub_time': ('django.db.models.fields.DateTimeField', [], {}), | |||
|
51 | 'referenced_posts': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rfp+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), | |||
|
52 | 'text': ('markupfield.fields.MarkupField', [], {'rendered_field': 'True'}), | |||
|
53 | 'text_markup_type': ('django.db.models.fields.CharField', [], {'default': "'markdown'", 'max_length': '30'}), | |||
|
54 | 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Post']", 'null': 'True'}), | |||
|
55 | 'thread_new': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.Thread']", 'null': 'True'}), | |||
|
56 | 'title': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | |||
|
57 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['boards.User']", 'null': 'True'}) | |||
|
58 | }, | |||
|
59 | 'boards.setting': { | |||
|
60 | 'Meta': {'object_name': 'Setting'}, | |||
|
61 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
62 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), | |||
|
63 | 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.User']"}), | |||
|
64 | 'value': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | |||
|
65 | }, | |||
|
66 | 'boards.tag': { | |||
|
67 | 'Meta': {'object_name': 'Tag'}, | |||
|
68 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
69 | 'linked': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), | |||
|
70 | 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), | |||
|
71 | 'threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tag+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Thread']"}) | |||
|
72 | }, | |||
|
73 | 'boards.thread': { | |||
|
74 | 'Meta': {'object_name': 'Thread'}, | |||
|
75 | 'bump_time': ('django.db.models.fields.DateTimeField', [], {}), | |||
|
76 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
77 | 'last_edit_time': ('django.db.models.fields.DateTimeField', [], {}), | |||
|
78 | 'replies': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'tre+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), | |||
|
79 | 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['boards.Tag']", 'symmetrical': 'False'}) | |||
|
80 | }, | |||
|
81 | 'boards.user': { | |||
|
82 | 'Meta': {'object_name': 'User'}, | |||
|
83 | 'fav_tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['boards.Tag']", 'null': 'True', 'blank': 'True'}), | |||
|
84 | 'fav_threads': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['boards.Post']"}), | |||
|
85 | u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | |||
|
86 | 'rank': ('django.db.models.fields.IntegerField', [], {}), | |||
|
87 | 'registration_time': ('django.db.models.fields.DateTimeField', [], {}), | |||
|
88 | 'user_id': ('django.db.models.fields.CharField', [], {'max_length': '50'}) | |||
|
89 | } | |||
|
90 | } | |||
|
91 | ||||
|
92 | complete_apps = ['boards'] No newline at end of file |
@@ -0,0 +1,66 b'' | |||||
|
1 | {% extends "boards/base.html" %} | |||
|
2 | ||||
|
3 | {% load i18n %} | |||
|
4 | {% load cache %} | |||
|
5 | {% load static from staticfiles %} | |||
|
6 | {% load board %} | |||
|
7 | ||||
|
8 | {% block head %} | |||
|
9 | <title>Neboard - {{ thread.get_opening_post.get_title }}</title> | |||
|
10 | {% endblock %} | |||
|
11 | ||||
|
12 | {% block content %} | |||
|
13 | {% spaceless %} | |||
|
14 | {% get_current_language as LANGUAGE_CODE %} | |||
|
15 | ||||
|
16 | <script src="{% static 'js/thread.js' %}"></script> | |||
|
17 | ||||
|
18 | {% cache 600 thread_gallery_view thread.id thread.last_edit_time LANGUAGE_CODE %} | |||
|
19 | <div class="image-mode-tab"> | |||
|
20 | <a href="{% url 'thread' thread.get_opening_post.id %}">{% trans 'Normal mode' %}</a>, | |||
|
21 | <a class="current_mode" href="{% url 'thread_mode' thread.get_opening_post.id 'gallery' %}">{% trans 'Gallery mode' %}</a> | |||
|
22 | </div> | |||
|
23 | ||||
|
24 | <div id="posts-table"> | |||
|
25 | {% for post in thread.get_replies %} | |||
|
26 | {% if post.image %} | |||
|
27 | <div class="gallery_image"> | |||
|
28 | <div> | |||
|
29 | <a | |||
|
30 | class="thumb" | |||
|
31 | href="{{ post.image.url }}"><img | |||
|
32 | src="{{ post.image.url_200x150 }}" | |||
|
33 | alt="{{ post.id }}" | |||
|
34 | width="{{ post.image_pre_width }}" | |||
|
35 | height="{{ post.image_pre_height }}" | |||
|
36 | data-width="{{ post.image_width }}" | |||
|
37 | data-height="{{ post.image_height }}"/> | |||
|
38 | </a> | |||
|
39 | </div> | |||
|
40 | <div class="gallery_image_metadata"> | |||
|
41 | {{ post.image_width }}x{{ post.image_height }} | |||
|
42 | {% image_actions post.image.url request.get_host %} | |||
|
43 | </div> | |||
|
44 | </div> | |||
|
45 | {% endif %} | |||
|
46 | {% endfor %} | |||
|
47 | </div> | |||
|
48 | {% endcache %} | |||
|
49 | ||||
|
50 | {% endspaceless %} | |||
|
51 | {% endblock %} | |||
|
52 | ||||
|
53 | {% block metapanel %} | |||
|
54 | ||||
|
55 | {% get_current_language as LANGUAGE_CODE %} | |||
|
56 | ||||
|
57 | <span class="metapanel" data-last-update="{{ last_update }}"> | |||
|
58 | {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %} | |||
|
59 | <span id="reply-count">{{ thread.get_reply_count }}</span> {% trans 'replies' %}, | |||
|
60 | <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}. | |||
|
61 | {% trans 'Last update: ' %}{{ thread.last_edit_time }} | |||
|
62 | [<a href="rss/">RSS</a>] | |||
|
63 | {% endcache %} | |||
|
64 | </span> | |||
|
65 | ||||
|
66 | {% endblock %} |
@@ -0,0 +1,7 b'' | |||||
|
1 | # 1.5 Aker # | |||
|
2 | * Saving image previews size. No space will be shown below images in some | |||
|
3 | styles. | |||
|
4 | * Showing notification in page title when new posts are loaded into the open | |||
|
5 | thread. | |||
|
6 | * Thread moderation fixes | |||
|
7 | * Added new gallery with search links and image metadata No newline at end of file |
1 | NO CONTENT: modified file, binary diff hidden |
|
NO CONTENT: modified file, binary diff hidden |
@@ -7,7 +7,7 b' msgid ""' | |||||
7 | msgstr "" |
|
7 | msgstr "" | |
8 | "Project-Id-Version: PACKAGE VERSION\n" |
|
8 | "Project-Id-Version: PACKAGE VERSION\n" | |
9 | "Report-Msgid-Bugs-To: \n" |
|
9 | "Report-Msgid-Bugs-To: \n" | |
10 |
"POT-Creation-Date: 2013-1 |
|
10 | "POT-Creation-Date: 2013-12-24 20:39+0200\n" | |
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
|
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
|
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
13 | "Language-Team: LANGUAGE <LL@li.org>\n" |
|
13 | "Language-Team: LANGUAGE <LL@li.org>\n" | |
@@ -34,77 +34,72 b' msgstr "\xd1\x80\xd0\xb0\xd0\xb7\xd1\x80\xd0\xb0\xd0\xb1\xd0\xbe\xd1\x82\xd1\x87\xd0\xb8\xd0\xba javascript"' | |||||
34 | msgid "designer" |
|
34 | msgid "designer" | |
35 | msgstr "дизайнер" |
|
35 | msgstr "дизайнер" | |
36 |
|
36 | |||
37 | #: forms.py:48 templates/boards/posting_general.html:209 |
|
37 | #: forms.py:72 | |
38 | #: templates/boards/thread.html:101 |
|
|||
39 | msgid "Title" |
|
38 | msgid "Title" | |
40 | msgstr "Заголовок" |
|
39 | msgstr "Заголовок" | |
41 |
|
40 | |||
42 | #: forms.py:50 templates/boards/posting_general.html:224 |
|
41 | #: forms.py:74 | |
43 | #: templates/boards/thread.html:116 |
|
|||
44 | msgid "Text" |
|
42 | msgid "Text" | |
45 | msgstr "Текст" |
|
43 | msgstr "Текст" | |
46 |
|
44 | |||
47 | #: forms.py:51 templates/boards/posting_general.html:229 |
|
45 | #: forms.py:75 | |
48 | #: templates/boards/thread.html:121 |
|
|||
49 | msgid "Image" |
|
46 | msgid "Image" | |
50 | msgstr "Изображение" |
|
47 | msgstr "Изображение" | |
51 |
|
48 | |||
52 | #: forms.py:54 templates/boards/posting_general.html:239 |
|
49 | #: forms.py:78 | |
53 | #: templates/boards/thread.html:126 |
|
|||
54 | msgid "e-mail" |
|
50 | msgid "e-mail" | |
55 | msgstr "" |
|
51 | msgstr "" | |
56 |
|
52 | |||
57 |
#: forms.py: |
|
53 | #: forms.py:89 | |
58 | #, python-format |
|
54 | #, python-format | |
59 | msgid "Title must have less than %s characters" |
|
55 | msgid "Title must have less than %s characters" | |
60 | msgstr "Заголовок должен иметь меньше %s символов" |
|
56 | msgstr "Заголовок должен иметь меньше %s символов" | |
61 |
|
57 | |||
62 |
#: forms.py: |
|
58 | #: forms.py:98 | |
63 | #, python-format |
|
59 | #, python-format | |
64 | msgid "Text must have less than %s characters" |
|
60 | msgid "Text must have less than %s characters" | |
65 | msgstr "Текст должен быть короче %s символов" |
|
61 | msgstr "Текст должен быть короче %s символов" | |
66 |
|
62 | |||
67 |
#: forms.py: |
|
63 | #: forms.py:109 | |
68 | #, python-format |
|
64 | #, python-format | |
69 | msgid "Image must be less than %s bytes" |
|
65 | msgid "Image must be less than %s bytes" | |
70 | msgstr "Изображение должно быть менее %s байт" |
|
66 | msgstr "Изображение должно быть менее %s байт" | |
71 |
|
67 | |||
72 |
#: forms.py:1 |
|
68 | #: forms.py:136 | |
73 | msgid "Either text or image must be entered." |
|
69 | msgid "Either text or image must be entered." | |
74 | msgstr "Текст или картинка должны быть введены." |
|
70 | msgstr "Текст или картинка должны быть введены." | |
75 |
|
71 | |||
76 |
#: forms.py:1 |
|
72 | #: forms.py:149 | |
77 | #, python-format |
|
73 | #, python-format | |
78 | msgid "Wait %s seconds after last posting" |
|
74 | msgid "Wait %s seconds after last posting" | |
79 | msgstr "Подождите %s секунд после последнего постинга" |
|
75 | msgstr "Подождите %s секунд после последнего постинга" | |
80 |
|
76 | |||
81 |
#: forms.py:13 |
|
77 | #: forms.py:163 templates/boards/post.html:61 templates/boards/tags.html:6 | |
82 | #: templates/boards/posting_general.html:234 templates/boards/tags.html:6 |
|
|||
83 | #: templates/boards/rss/post.html:10 |
|
78 | #: templates/boards/rss/post.html:10 | |
84 | msgid "Tags" |
|
79 | msgid "Tags" | |
85 | msgstr "Теги" |
|
80 | msgstr "Теги" | |
86 |
|
81 | |||
87 |
#: forms.py:1 |
|
82 | #: forms.py:171 | |
88 | msgid "Inappropriate characters in tags." |
|
83 | msgid "Inappropriate characters in tags." | |
89 | msgstr "Недопустимые символы в тегах." |
|
84 | msgstr "Недопустимые символы в тегах." | |
90 |
|
85 | |||
91 |
#: forms.py:1 |
|
86 | #: forms.py:199 forms.py:220 | |
92 | msgid "Captcha validation failed" |
|
87 | msgid "Captcha validation failed" | |
93 | msgstr "Проверка капчи провалена" |
|
88 | msgstr "Проверка капчи провалена" | |
94 |
|
89 | |||
95 |
#: forms.py:2 |
|
90 | #: forms.py:226 | |
96 | msgid "Theme" |
|
91 | msgid "Theme" | |
97 | msgstr "Тема" |
|
92 | msgstr "Тема" | |
98 |
|
93 | |||
99 |
#: forms.py:2 |
|
94 | #: forms.py:231 | |
100 | msgid "Enable moderation panel" |
|
95 | msgid "Enable moderation panel" | |
101 | msgstr "Включить панель модерации" |
|
96 | msgstr "Включить панель модерации" | |
102 |
|
97 | |||
103 |
#: forms.py:2 |
|
98 | #: forms.py:246 | |
104 | msgid "No such user found" |
|
99 | msgid "No such user found" | |
105 | msgstr "Данный пользователь не найден" |
|
100 | msgstr "Данный пользователь не найден" | |
106 |
|
101 | |||
107 |
#: forms.py:2 |
|
102 | #: forms.py:260 | |
108 | #, python-format |
|
103 | #, python-format | |
109 | msgid "Wait %s minutes after last login" |
|
104 | msgid "Wait %s minutes after last login" | |
110 | msgstr "Подождите %s минут после последнего входа" |
|
105 | msgstr "Подождите %s минут после последнего входа" | |
@@ -137,15 +132,15 b' msgstr "\xd0\xa0\xd0\xb5\xd0\xbf\xd0\xbe\xd0\xb7\xd0\xb8\xd1\x82\xd0\xbe\xd1\x80\xd0\xb8\xd0\xb9"' | |||||
137 | msgid "Feed" |
|
132 | msgid "Feed" | |
138 | msgstr "Лента" |
|
133 | msgstr "Лента" | |
139 |
|
134 | |||
140 |
#: templates/boards/base.html:3 |
|
135 | #: templates/boards/base.html:31 | |
141 | msgid "All threads" |
|
136 | msgid "All threads" | |
142 | msgstr "Все темы" |
|
137 | msgstr "Все темы" | |
143 |
|
138 | |||
144 |
#: templates/boards/base.html: |
|
139 | #: templates/boards/base.html:36 | |
145 | msgid "Tag management" |
|
140 | msgid "Tag management" | |
146 | msgstr "Управление тегами" |
|
141 | msgstr "Управление тегами" | |
147 |
|
142 | |||
148 |
#: templates/boards/base.html: |
|
143 | #: templates/boards/base.html:38 | |
149 | msgid "Settings" |
|
144 | msgid "Settings" | |
150 | msgstr "Настройки" |
|
145 | msgstr "Настройки" | |
151 |
|
146 | |||
@@ -171,92 +166,65 b' msgstr "ID \xd0\xbf\xd0\xbe\xd0\xbb\xd1\x8c\xd0\xb7\xd0\xbe\xd0\xb2\xd0\xb0\xd1\x82\xd0\xb5\xd0\xbb\xd1\x8f"' | |||||
171 | msgid "Insert your user id above" |
|
166 | msgid "Insert your user id above" | |
172 | msgstr "Вставьте свой ID пользователя выше" |
|
167 | msgstr "Вставьте свой ID пользователя выше" | |
173 |
|
168 | |||
174 |
#: templates/boards/post.html:3 |
|
169 | #: templates/boards/post.html:35 templates/boards/posting_general.html:103 | |
175 |
#: templates/boards/thread.html: |
|
170 | #: templates/boards/thread.html:68 | |
176 | msgid "Delete" |
|
171 | msgid "Delete" | |
177 | msgstr "Удалить" |
|
172 | msgstr "Удалить" | |
178 |
|
173 | |||
179 |
#: templates/boards/post.html:3 |
|
174 | #: templates/boards/post.html:38 templates/boards/posting_general.html:107 | |
180 |
#: templates/boards/thread.html: |
|
175 | #: templates/boards/thread.html:71 | |
181 | msgid "Ban IP" |
|
176 | msgid "Ban IP" | |
182 | msgstr "Заблокировать IP" |
|
177 | msgstr "Заблокировать IP" | |
183 |
|
178 | |||
184 |
#: templates/boards/post.html:5 |
|
179 | #: templates/boards/post.html:51 templates/boards/posting_general.html:116 | |
185 |
#: templates/boards/posting_general.html:1 |
|
180 | #: templates/boards/posting_general.html:180 templates/boards/thread.html:80 | |
186 | msgid "Replies" |
|
181 | msgid "Replies" | |
187 | msgstr "Ответы" |
|
182 | msgstr "Ответы" | |
188 |
|
183 | |||
189 |
#: templates/boards/posting_general.html:6 |
|
184 | #: templates/boards/posting_general.html:64 | |
190 | msgid "Previous page" |
|
185 | msgid "Previous page" | |
191 | msgstr "Предыдущая страница" |
|
186 | msgstr "Предыдущая страница" | |
192 |
|
187 | |||
193 |
#: templates/boards/posting_general.html:9 |
|
188 | #: templates/boards/posting_general.html:97 | |
194 | msgid "Reply" |
|
189 | msgid "Reply" | |
195 | msgstr "Ответ" |
|
190 | msgstr "Ответ" | |
196 |
|
191 | |||
197 |
#: templates/boards/posting_general.html:12 |
|
192 | #: templates/boards/posting_general.html:125 templates/boards/thread.html:130 | |
198 | msgid "replies" |
|
193 | #: templates/boards/thread_gallery.html:52 | |
199 | msgstr "ответов" |
|
|||
200 |
|
||||
201 | #: templates/boards/posting_general.html:123 templates/boards/thread.html:155 |
|
|||
202 | msgid "images" |
|
194 | msgid "images" | |
203 | msgstr "изображений" |
|
195 | msgstr "изображений" | |
204 |
|
196 | |||
205 |
#: templates/boards/posting_general.html:1 |
|
197 | #: templates/boards/posting_general.html:142 | |
206 | #, python-format |
|
198 | #, python-format | |
207 | msgid "Skipped %(count)s replies. Open thread to see all replies." |
|
199 | msgid "Skipped %(count)s replies. Open thread to see all replies." | |
208 | msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы." |
|
200 | msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы." | |
209 |
|
201 | |||
210 |
#: templates/boards/posting_general.html: |
|
202 | #: templates/boards/posting_general.html:203 | |
211 | msgid "Next page" |
|
203 | msgid "Next page" | |
212 | msgstr "Следующая страница" |
|
204 | msgstr "Следующая страница" | |
213 |
|
205 | |||
214 |
#: templates/boards/posting_general.html:20 |
|
206 | #: templates/boards/posting_general.html:208 | |
215 | msgid "No threads exist. Create the first one!" |
|
207 | msgid "No threads exist. Create the first one!" | |
216 | msgstr "Нет тем. Создайте первую!" |
|
208 | msgstr "Нет тем. Создайте первую!" | |
217 |
|
209 | |||
218 |
#: templates/boards/posting_general.html:2 |
|
210 | #: templates/boards/posting_general.html:214 | |
219 | msgid "Create new thread" |
|
211 | msgid "Create new thread" | |
220 | msgstr "Создать новую тему" |
|
212 | msgstr "Создать новую тему" | |
221 |
|
213 | |||
222 |
#: templates/boards/posting_general.html:21 |
|
214 | #: templates/boards/posting_general.html:218 templates/boards/thread.html:112 | |
223 | msgid "Formatting" |
|
|||
224 | msgstr "Форматирование" |
|
|||
225 |
|
||||
226 | #: templates/boards/posting_general.html:216 templates/boards/thread.html:108 |
|
|||
227 | msgid "quote" |
|
|||
228 | msgstr "цитата" |
|
|||
229 |
|
||||
230 | #: templates/boards/posting_general.html:217 templates/boards/thread.html:109 |
|
|||
231 | msgid "italic" |
|
|||
232 | msgstr "курсив" |
|
|||
233 |
|
||||
234 | #: templates/boards/posting_general.html:218 templates/boards/thread.html:110 |
|
|||
235 | msgid "bold" |
|
|||
236 | msgstr "полужирный" |
|
|||
237 |
|
||||
238 | #: templates/boards/posting_general.html:219 templates/boards/thread.html:111 |
|
|||
239 | msgid "spoiler" |
|
|||
240 | msgstr "спойлер" |
|
|||
241 |
|
||||
242 | #: templates/boards/posting_general.html:220 templates/boards/thread.html:112 |
|
|||
243 | msgid "comment" |
|
|||
244 | msgstr "комментарий" |
|
|||
245 |
|
||||
246 | #: templates/boards/posting_general.html:252 templates/boards/thread.html:140 |
|
|||
247 | msgid "Post" |
|
215 | msgid "Post" | |
248 | msgstr "Отправить" |
|
216 | msgstr "Отправить" | |
249 |
|
217 | |||
250 |
#: templates/boards/posting_general.html:2 |
|
218 | #: templates/boards/posting_general.html:222 | |
251 | msgid "Tags must be delimited by spaces. Text or image is required." |
|
219 | msgid "Tags must be delimited by spaces. Text or image is required." | |
252 | msgstr "" |
|
220 | msgstr "" | |
253 | "Теги должны быть разделены пробелами. Текст или изображение обязательны." |
|
221 | "Теги должны быть разделены пробелами. Текст или изображение обязательны." | |
254 |
|
222 | |||
255 |
#: templates/boards/posting_general.html:25 |
|
223 | #: templates/boards/posting_general.html:225 templates/boards/thread.html:116 | |
256 | msgid "Text syntax" |
|
224 | msgid "Text syntax" | |
257 | msgstr "Синтаксис текста" |
|
225 | msgstr "Синтаксис текста" | |
258 |
|
226 | |||
259 |
#: templates/boards/posting_general.html:2 |
|
227 | #: templates/boards/posting_general.html:235 | |
260 | msgid "Pages:" |
|
228 | msgid "Pages:" | |
261 | msgstr "Страницы: " |
|
229 | msgstr "Страницы: " | |
262 |
|
230 | |||
@@ -292,15 +260,27 b' msgstr "\xd1\x82\xd0\xb5\xd0\xbc"' | |||||
292 | msgid "No tags found." |
|
260 | msgid "No tags found." | |
293 | msgstr "Теги не найдены." |
|
261 | msgstr "Теги не найдены." | |
294 |
|
262 | |||
295 |
#: templates/boards/thread.html:2 |
|
263 | #: templates/boards/thread.html:22 templates/boards/thread_gallery.html:20 | |
|
264 | msgid "Normal mode" | |||
|
265 | msgstr "Нормальный режим" | |||
|
266 | ||||
|
267 | #: templates/boards/thread.html:23 templates/boards/thread_gallery.html:21 | |||
|
268 | msgid "Gallery mode" | |||
|
269 | msgstr "Режим галереи" | |||
|
270 | ||||
|
271 | #: templates/boards/thread.html:31 | |||
296 | msgid "posts to bumplimit" |
|
272 | msgid "posts to bumplimit" | |
297 | msgstr "сообщений до бамплимита" |
|
273 | msgstr "сообщений до бамплимита" | |
298 |
|
274 | |||
299 |
#: templates/boards/thread.html: |
|
275 | #: templates/boards/thread.html:106 | |
300 | msgid "Reply to thread" |
|
276 | msgid "Reply to thread" | |
301 | msgstr "Ответить в тему" |
|
277 | msgstr "Ответить в тему" | |
302 |
|
278 | |||
303 |
#: templates/boards/thread.html:1 |
|
279 | #: templates/boards/thread.html:129 templates/boards/thread_gallery.html:51 | |
|
280 | msgid "replies" | |||
|
281 | msgstr "ответов" | |||
|
282 | ||||
|
283 | #: templates/boards/thread.html:131 templates/boards/thread_gallery.html:53 | |||
304 | msgid "Last update: " |
|
284 | msgid "Last update: " | |
305 | msgstr "Последнее обновление: " |
|
285 | msgstr "Последнее обновление: " | |
306 |
|
286 | |||
@@ -353,6 +333,24 b' msgstr "\xd0\xa1\xd1\x81\xd1\x8b\xd0\xbb\xd0\xba\xd0\xb0 \xd0\xbd\xd0\xb0 \xd1\x81\xd0\xbe\xd0\xbe\xd0\xb1\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5"' | |||||
353 | msgid "Strikethrough text" |
|
333 | msgid "Strikethrough text" | |
354 | msgstr "Зачеркнутый текст" |
|
334 | msgstr "Зачеркнутый текст" | |
355 |
|
335 | |||
|
336 | #~ msgid "Formatting" | |||
|
337 | #~ msgstr "Форматирование" | |||
|
338 | ||||
|
339 | #~ msgid "quote" | |||
|
340 | #~ msgstr "цитата" | |||
|
341 | ||||
|
342 | #~ msgid "italic" | |||
|
343 | #~ msgstr "курсив" | |||
|
344 | ||||
|
345 | #~ msgid "bold" | |||
|
346 | #~ msgstr "полужирный" | |||
|
347 | ||||
|
348 | #~ msgid "spoiler" | |||
|
349 | #~ msgstr "спойлер" | |||
|
350 | ||||
|
351 | #~ msgid "comment" | |||
|
352 | #~ msgstr "комментарий" | |||
|
353 | ||||
356 | #~ msgid "Tag: " |
|
354 | #~ msgid "Tag: " | |
357 | #~ msgstr "Тег: " |
|
355 | #~ msgstr "Тег: " | |
358 |
|
356 |
1 | NO CONTENT: modified file, binary diff hidden |
|
NO CONTENT: modified file, binary diff hidden |
@@ -8,7 +8,7 b' msgid ""' | |||||
8 | msgstr "" |
|
8 | msgstr "" | |
9 | "Project-Id-Version: PACKAGE VERSION\n" |
|
9 | "Project-Id-Version: PACKAGE VERSION\n" | |
10 | "Report-Msgid-Bugs-To: \n" |
|
10 | "Report-Msgid-Bugs-To: \n" | |
11 |
"POT-Creation-Date: 2013-1 |
|
11 | "POT-Creation-Date: 2013-12-21 21:45+0200\n" | |
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
|
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
13 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
|
13 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
14 | "Language-Team: LANGUAGE <LL@li.org>\n" |
|
14 | "Language-Team: LANGUAGE <LL@li.org>\n" | |
@@ -19,11 +19,11 b' msgstr ""' | |||||
19 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" |
|
19 | "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" | |
20 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" |
|
20 | "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" | |
21 |
|
21 | |||
22 |
#: static/js/refpopup.js: |
|
22 | #: static/js/refpopup.js:57 | |
23 | msgid "Loading..." |
|
23 | msgid "Loading..." | |
24 | msgstr "Загрузка..." |
|
24 | msgstr "Загрузка..." | |
25 |
|
25 | |||
26 |
#: static/js/refpopup.js: |
|
26 | #: static/js/refpopup.js:76 | |
27 | msgid "Post not found" |
|
27 | msgid "Post not found" | |
28 | msgstr "Сообщение не найдено" |
|
28 | msgstr "Сообщение не найдено" | |
29 |
|
29 | |||
@@ -35,5 +35,9 b' msgstr "\xd0\x9d\xd0\xbe\xd1\x80\xd0\xbc\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd1\x8b\xd0\xb9"' | |||||
35 | msgid "Gallery" |
|
35 | msgid "Gallery" | |
36 | msgstr "Галерея" |
|
36 | msgstr "Галерея" | |
37 |
|
37 | |||
|
38 | #: static/js/thread_update.js:177 | |||
|
39 | msgid "[new posts]" | |||
|
40 | msgstr "[новые посты]" | |||
|
41 | ||||
38 | #~ msgid "Replies" |
|
42 | #~ msgid "Replies" | |
39 | #~ msgstr "Ответы" |
|
43 | #~ msgstr "Ответы" |
@@ -34,7 +34,8 b' class MinifyHTMLMiddleware(object):' | |||||
34 | except AttributeError: |
|
34 | except AttributeError: | |
35 | compress_html = False |
|
35 | compress_html = False | |
36 |
|
36 | |||
37 |
if |
|
37 | if RESPONSE_CONTENT_TYPE in response\ | |
|
38 | and TYPE_HTML in response[RESPONSE_CONTENT_TYPE] and compress_html: | |||
38 | response.content = strip_spaces_between_tags( |
|
39 | response.content = strip_spaces_between_tags( | |
39 | response.content.strip()) |
|
40 | response.content.strip()) | |
40 | return response No newline at end of file |
|
41 | return response |
@@ -86,12 +86,18 b' class PostManager(models.Manager):' | |||||
86 |
|
86 | |||
87 | def delete_post(self, post): |
|
87 | def delete_post(self, post): | |
88 | """ |
|
88 | """ | |
89 | Delete post and update its thread |
|
89 | Delete post and update or delete its thread | |
90 | """ |
|
90 | """ | |
|
91 | ||||
|
92 | thread = post.thread_new | |||
91 |
|
93 | |||
92 | thread = post.thread_new |
|
94 | if thread.get_opening_post() == self: | |
93 | thread.last_edit_time = timezone.now() |
|
95 | thread.replies.delete() | |
94 | thread.save() |
|
96 | ||
|
97 | thread.delete() | |||
|
98 | else: | |||
|
99 | thread.last_edit_time = timezone.now() | |||
|
100 | thread.save() | |||
95 |
|
101 | |||
96 | post.delete() |
|
102 | post.delete() | |
97 |
|
103 | |||
@@ -235,10 +241,15 b' class Post(models.Model):' | |||||
235 | image_width = models.IntegerField(default=0) |
|
241 | image_width = models.IntegerField(default=0) | |
236 | image_height = models.IntegerField(default=0) |
|
242 | image_height = models.IntegerField(default=0) | |
237 |
|
243 | |||
|
244 | image_pre_width = models.IntegerField(default=0) | |||
|
245 | image_pre_height = models.IntegerField(default=0) | |||
|
246 | ||||
238 | image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename, |
|
247 | image = thumbs.ImageWithThumbsField(upload_to=_update_image_filename, | |
239 | blank=True, sizes=(IMAGE_THUMB_SIZE,), |
|
248 | blank=True, sizes=(IMAGE_THUMB_SIZE,), | |
240 | width_field='image_width', |
|
249 | width_field='image_width', | |
241 |
height_field='image_height' |
|
250 | height_field='image_height', | |
|
251 | preview_width_field='image_pre_width', | |||
|
252 | preview_height_field='image_pre_height') | |||
242 |
|
253 | |||
243 | poster_ip = models.GenericIPAddressField() |
|
254 | poster_ip = models.GenericIPAddressField() | |
244 | poster_user_agent = models.TextField() |
|
255 | poster_user_agent = models.TextField() |
@@ -27,3 +27,7 b'' | |||||
27 | z-index: 300; |
|
27 | z-index: 300; | |
28 | position:absolute; |
|
28 | position:absolute; | |
29 | } |
|
29 | } | |
|
30 | ||||
|
31 | .gallery_image { | |||
|
32 | display: inline-block; | |||
|
33 | } No newline at end of file |
@@ -173,8 +173,6 b' blockquote {' | |||||
173 | min-width: 1px; |
|
173 | min-width: 1px; | |
174 | text-align: center; |
|
174 | text-align: center; | |
175 | display: table-row; |
|
175 | display: table-row; | |
176 |
|
||||
177 | height: 150px; |
|
|||
178 | } |
|
176 | } | |
179 |
|
177 | |||
180 | .post > .metadata { |
|
178 | .post > .metadata { | |
@@ -356,3 +354,15 b' li {' | |||||
356 | .skipped_replies { |
|
354 | .skipped_replies { | |
357 | margin: 5px; |
|
355 | margin: 5px; | |
358 | } |
|
356 | } | |
|
357 | ||||
|
358 | .current_page, .current_mode { | |||
|
359 | border: solid 1px #afdcec; | |||
|
360 | padding: 2px; | |||
|
361 | } | |||
|
362 | ||||
|
363 | .gallery_image { | |||
|
364 | border: solid 1px; | |||
|
365 | padding: 0.5ex; | |||
|
366 | margin: 0.5ex; | |||
|
367 | text-align: center; | |||
|
368 | } No newline at end of file |
@@ -171,8 +171,6 b' blockquote {' | |||||
171 | min-width: 1px; |
|
171 | min-width: 1px; | |
172 | text-align: center; |
|
172 | text-align: center; | |
173 | display: table-row; |
|
173 | display: table-row; | |
174 |
|
||||
175 | height: 150px; |
|
|||
176 | } |
|
174 | } | |
177 |
|
175 | |||
178 | .post > .metadata { |
|
176 | .post > .metadata { | |
@@ -342,3 +340,8 b' input[type="submit"]:hover {' | |||||
342 | .skipped_replies { |
|
340 | .skipped_replies { | |
343 | margin: 5px; |
|
341 | margin: 5px; | |
344 | } |
|
342 | } | |
|
343 | ||||
|
344 | .current_page, .current_mode { | |||
|
345 | border: solid 1px #000; | |||
|
346 | padding: 2px; | |||
|
347 | } No newline at end of file |
@@ -330,4 +330,28 b' li {' | |||||
330 |
|
330 | |||
331 | .mark_btn:last-child { |
|
331 | .mark_btn:last-child { | |
332 | border-right: 1px solid #182F6F; |
|
332 | border-right: 1px solid #182F6F; | |
|
333 | } | |||
|
334 | ||||
|
335 | .current_page { | |||
|
336 | border-bottom: 1px solid #FFF; | |||
|
337 | padding: 0px 0.5ex; | |||
|
338 | } | |||
|
339 | ||||
|
340 | .image-mode-tab a { | |||
|
341 | text-decoration: none; | |||
|
342 | } | |||
|
343 | .image-mode-tab .current_mode::before { | |||
|
344 | content: "✓ "; | |||
|
345 | padding: 0 0 0 .5ex; | |||
|
346 | color: #182F6F; | |||
|
347 | background: #FFF; | |||
|
348 | } | |||
|
349 | .image-mode-tab .current_mode { | |||
|
350 | padding: 0 .5ex 0 0; | |||
|
351 | color: #182F6F; | |||
|
352 | background: #FFF; | |||
|
353 | } | |||
|
354 | ||||
|
355 | .gallery_image_metadata { | |||
|
356 | margin-bottom: 1em; | |||
333 | } No newline at end of file |
|
357 | } |
@@ -23,33 +23,6 b'' | |||||
23 | for the JavaScript code in this page. |
|
23 | for the JavaScript code in this page. | |
24 | */ |
|
24 | */ | |
25 |
|
25 | |||
26 | function addGalleryPanel() { |
|
|||
27 | var gallery = $('a[class="thumb"]').clone(true), |
|
|||
28 | normal = $('.post').clone(true); |
|
|||
29 |
|
||||
30 | $('.navigation_panel').filter(':first').after( |
|
|||
31 | '<div class="image-mode-tab" role="radiogroup" aria-label="Image mode2">' + |
|
|||
32 | '<label><input type="radio" class="image-mode-normal" name="image-mode" value="0" checked="checked"/>'+ gettext('Normal') +'</label>' + |
|
|||
33 | '<label><input type="radio" class="image-mode-table" name="image-mode" value="1"/>'+ gettext('Gallery') +'</label>' + |
|
|||
34 | '</div>' |
|
|||
35 | ); |
|
|||
36 |
|
||||
37 | $('input[name="image-mode"]').change(function() { |
|
|||
38 | //gallery mode |
|
|||
39 | if($(this).val() === '1') { |
|
|||
40 | $('.thread').replaceWith( |
|
|||
41 | $('<div id="posts-table"></div>').append(gallery) |
|
|||
42 | ); |
|
|||
43 | } |
|
|||
44 | //normal mode |
|
|||
45 | else { |
|
|||
46 | $('#posts-table').replaceWith( |
|
|||
47 | $('<div class="thread"></div>').append(normal) |
|
|||
48 | ); |
|
|||
49 | } |
|
|||
50 | }); |
|
|||
51 | } |
|
|||
52 |
|
||||
53 | function moveCaretToEnd(el) { |
|
26 | function moveCaretToEnd(el) { | |
54 | if (typeof el.selectionStart == "number") { |
|
27 | if (typeof el.selectionStart == "number") { | |
55 | el.selectionStart = el.selectionEnd = el.value.length; |
|
28 | el.selectionStart = el.selectionEnd = el.value.length; | |
@@ -72,10 +45,3 b' function addQuickReply(postId) {' | |||||
72 |
|
45 | |||
73 | $("html, body").animate({ scrollTop: $(textAreaId).offset().top }, "slow"); |
|
46 | $("html, body").animate({ scrollTop: $(textAreaId).offset().top }, "slow"); | |
74 | } |
|
47 | } | |
75 |
|
||||
76 |
|
||||
77 |
|
||||
78 | $(document).ready(function(){ |
|
|||
79 | addGalleryPanel(); |
|
|||
80 | initAutoupdate(); |
|
|||
81 | }); |
|
@@ -97,6 +97,10 b' function updateThread() {' | |||||
97 |
|
97 | |||
98 | updateBumplimitProgress(data.added.length); |
|
98 | updateBumplimitProgress(data.added.length); | |
99 | updatePostBumpableStatus(); |
|
99 | updatePostBumpableStatus(); | |
|
100 | ||||
|
101 | if (data.added.length + data.updated.length > 0) { | |||
|
102 | showNewPostsTitle(); | |||
|
103 | } | |||
100 | }) |
|
104 | }) | |
101 | .error(function(data) { |
|
105 | .error(function(data) { | |
102 | // TODO Show error message that server is unavailable? |
|
106 | // TODO Show error message that server is unavailable? | |
@@ -162,3 +166,27 b' function updatePostBumpableStatus() {' | |||||
162 | $('.thread').find('.post').addClass('dead_post'); |
|
166 | $('.thread').find('.post').addClass('dead_post'); | |
163 | } |
|
167 | } | |
164 | } |
|
168 | } | |
|
169 | ||||
|
170 | var documentOriginalTitle = ''; | |||
|
171 | /** | |||
|
172 | * Show 'new posts' text in the title if the document is not visible to a user | |||
|
173 | */ | |||
|
174 | function showNewPostsTitle() { | |||
|
175 | if (document.hidden) { | |||
|
176 | documentOriginalTitle = document.title; | |||
|
177 | document.title = gettext('[new posts]') + ' ' + document.title; | |||
|
178 | ||||
|
179 | document.addEventListener('visibilitychange', function() { | |||
|
180 | if (documentOriginalTitle !== '') { | |||
|
181 | document.title = documentOriginalTitle; | |||
|
182 | documentOriginalTitle = ''; | |||
|
183 | } | |||
|
184 | ||||
|
185 | document.removeEventListener('visibilitychange', null); | |||
|
186 | }); | |||
|
187 | } | |||
|
188 | } | |||
|
189 | ||||
|
190 | $(document).ready(function(){ | |||
|
191 | initAutoupdate(); | |||
|
192 | }); |
@@ -79,6 +79,8 b'' | |||||
79 | href="{{ thread.op.image.url }}"><img |
|
79 | href="{{ thread.op.image.url }}"><img | |
80 | src="{{ thread.op.image.url_200x150 }}" |
|
80 | src="{{ thread.op.image.url_200x150 }}" | |
81 | alt="{{ thread.op.id }}" |
|
81 | alt="{{ thread.op.id }}" | |
|
82 | width="{{ thread.op.image_pre_width }}" | |||
|
83 | height="{{ thread.op.image_pre_height }}" | |||
82 | data-width="{{ thread.op.image_width }}" |
|
84 | data-width="{{ thread.op.image_width }}" | |
83 | data-height="{{ thread.op.image_height }}"/> |
|
85 | data-height="{{ thread.op.image_height }}"/> | |
84 | </a> |
|
86 | </a> | |
@@ -99,7 +101,7 b'' | |||||
99 | [<a href=" |
|
101 | [<a href=" | |
100 | {% url 'delete' post_id=thread.op.id %}?next={{ request.path }}" |
|
102 | {% url 'delete' post_id=thread.op.id %}?next={{ request.path }}" | |
101 | >{% trans 'Delete' %}</a>] |
|
103 | >{% trans 'Delete' %}</a>] | |
102 |
({{ thread. |
|
104 | ({{ thread.op.poster_ip }}) | |
103 | [<a href=" |
|
105 | [<a href=" | |
104 | {% url 'ban' post_id=thread.op.id %}?next={{ request.path }}" |
|
106 | {% url 'ban' post_id=thread.op.id %}?next={{ request.path }}" | |
105 | >{% trans 'Ban IP' %}</a>] |
|
107 | >{% trans 'Ban IP' %}</a>] | |
@@ -154,6 +156,8 b'' | |||||
154 | href="{{ post.image.url }}"><img |
|
156 | href="{{ post.image.url }}"><img | |
155 | src=" {{ post.image.url_200x150 }}" |
|
157 | src=" {{ post.image.url_200x150 }}" | |
156 | alt="{{ post.id }}" |
|
158 | alt="{{ post.id }}" | |
|
159 | width="{{ post.image_pre_width }}" | |||
|
160 | height="{{ post.image_pre_height }}" | |||
157 | data-width="{{ post.image_width }}" |
|
161 | data-width="{{ post.image_width }}" | |
158 | data-height="{{ post.image_height }}"/> |
|
162 | data-height="{{ post.image_height }}"/> | |
159 | </a> |
|
163 | </a> | |
@@ -227,17 +231,23 b'' | |||||
227 | {% block metapanel %} |
|
231 | {% block metapanel %} | |
228 |
|
232 | |||
229 | <span class="metapanel"> |
|
233 | <span class="metapanel"> | |
230 |
<b><a href="{% url "authors" %}">Neboard</a> 1. |
|
234 | <b><a href="{% url "authors" %}">Neboard</a> 1.5 Aker</b> | |
231 | {% trans "Pages:" %} |
|
235 | {% trans "Pages:" %}[ | |
232 | {% for page in pages %} |
|
236 | {% for page in pages %} | |
233 |
|
|
237 | <a | |
|
238 | {% ifequal page current_page %} | |||
|
239 | class="current_page" | |||
|
240 | {% endifequal %} | |||
|
241 | href=" | |||
234 | {% if tag %} |
|
242 | {% if tag %} | |
235 | {% url "tag" tag_name=tag page=page %} |
|
243 | {% url "tag" tag_name=tag page=page %} | |
236 | {% else %} |
|
244 | {% else %} | |
237 | {% url "index" page=page %} |
|
245 | {% url "index" page=page %} | |
238 | {% endif %} |
|
246 | {% endif %} | |
239 |
">{{ page }}</a> |
|
247 | ">{{ page }}</a> | |
|
248 | {% if not forloop.last %},{% endif %} | |||
240 | {% endfor %} |
|
249 | {% endfor %} | |
|
250 | ] | |||
241 | [<a href="rss/">RSS</a>] |
|
251 | [<a href="rss/">RSS</a>] | |
242 | </span> |
|
252 | </span> | |
243 |
|
253 |
@@ -6,7 +6,7 b'' | |||||
6 | {% load board %} |
|
6 | {% load board %} | |
7 |
|
7 | |||
8 | {% block head %} |
|
8 | {% block head %} | |
9 |
<title>Neboard - {{ thread.get_ |
|
9 | <title>Neboard - {{ thread.get_opening_post.get_title }}</title> | |
10 | {% endblock %} |
|
10 | {% endblock %} | |
11 |
|
11 | |||
12 | {% block content %} |
|
12 | {% block content %} | |
@@ -17,6 +17,12 b'' | |||||
17 | <script src="{% static 'js/thread.js' %}"></script> |
|
17 | <script src="{% static 'js/thread.js' %}"></script> | |
18 |
|
18 | |||
19 | {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %} |
|
19 | {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %} | |
|
20 | ||||
|
21 | <div class="image-mode-tab"> | |||
|
22 | <a class="current_mode" href="{% url 'thread' thread.get_opening_post.id %}">{% trans 'Normal mode' %}</a>, | |||
|
23 | <a href="{% url 'thread_mode' thread.get_opening_post.id 'gallery' %}">{% trans 'Gallery mode' %}</a> | |||
|
24 | </div> | |||
|
25 | ||||
20 | {% if bumpable %} |
|
26 | {% if bumpable %} | |
21 | <div class="bar-bg"> |
|
27 | <div class="bar-bg"> | |
22 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> |
|
28 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> | |
@@ -40,6 +46,8 b'' | |||||
40 | href="{{ post.image.url }}"><img |
|
46 | href="{{ post.image.url }}"><img | |
41 | src="{{ post.image.url_200x150 }}" |
|
47 | src="{{ post.image.url_200x150 }}" | |
42 | alt="{{ post.id }}" |
|
48 | alt="{{ post.id }}" | |
|
49 | width="{{ post.image_pre_width }}" | |||
|
50 | height="{{ post.image_pre_height }}" | |||
43 | data-width="{{ post.image_width }}" |
|
51 | data-width="{{ post.image_width }}" | |
44 | data-height="{{ post.image_height }}"/> |
|
52 | data-height="{{ post.image_height }}"/> | |
45 | </a> |
|
53 | </a> |
@@ -6,6 +6,17 b' from django import template' | |||||
6 |
|
6 | |||
7 | register = template.Library() |
|
7 | register = template.Library() | |
8 |
|
8 | |||
|
9 | actions = [ | |||
|
10 | { | |||
|
11 | 'name': 'google', | |||
|
12 | 'link': 'http://google.com/searchbyimage?image_url=%s', | |||
|
13 | }, | |||
|
14 | { | |||
|
15 | 'name': 'iqdb', | |||
|
16 | 'link': 'http://iqdb.org/?url=%s', | |||
|
17 | }, | |||
|
18 | ] | |||
|
19 | ||||
9 |
|
20 | |||
10 | @register.simple_tag(name='post_url') |
|
21 | @register.simple_tag(name='post_url') | |
11 | def post_url(*args, **kwargs): |
|
22 | def post_url(*args, **kwargs): | |
@@ -21,3 +32,18 b' def post_url(*args, **kwargs):' | |||||
21 | link = reverse(thread, kwargs={'post_id': post_id}) |
|
32 | link = reverse(thread, kwargs={'post_id': post_id}) | |
22 |
|
33 | |||
23 | return link |
|
34 | return link | |
|
35 | ||||
|
36 | ||||
|
37 | @register.simple_tag(name='image_actions') | |||
|
38 | def image_actions(*args, **kwargs): | |||
|
39 | image_link = args[0] | |||
|
40 | if len(args) > 1: | |||
|
41 | image_link = 'http://' + args[1] + image_link # TODO https? | |||
|
42 | ||||
|
43 | result = '' | |||
|
44 | ||||
|
45 | for action in actions: | |||
|
46 | result += '[<a href="' + action['link'] % image_link + '">' + \ | |||
|
47 | action['name'] + '</a>]' | |||
|
48 | ||||
|
49 | return result |
@@ -3,6 +3,7 b'' | |||||
3 | django-thumbs by Antonio Melé |
|
3 | django-thumbs by Antonio Melé | |
4 | http://django.es |
|
4 | http://django.es | |
5 | """ |
|
5 | """ | |
|
6 | from django.core.files.images import ImageFile | |||
6 | from django.db.models import ImageField |
|
7 | from django.db.models import ImageField | |
7 | from django.db.models.fields.files import ImageFieldFile |
|
8 | from django.db.models.fields.files import ImageFieldFile | |
8 | from PIL import Image |
|
9 | from PIL import Image | |
@@ -13,13 +14,13 b' import cStringIO' | |||||
13 | def generate_thumb(img, thumb_size, format): |
|
14 | def generate_thumb(img, thumb_size, format): | |
14 | """ |
|
15 | """ | |
15 | Generates a thumbnail image and returns a ContentFile object with the thumbnail |
|
16 | Generates a thumbnail image and returns a ContentFile object with the thumbnail | |
16 |
|
17 | |||
17 | Parameters: |
|
18 | Parameters: | |
18 | =========== |
|
19 | =========== | |
19 | img File object |
|
20 | img File object | |
20 |
|
21 | |||
21 | thumb_size desired thumbnail size, ie: (200,120) |
|
22 | thumb_size desired thumbnail size, ie: (200,120) | |
22 |
|
23 | |||
23 | format format of the original image ('jpeg','gif','png',...) |
|
24 | format format of the original image ('jpeg','gif','png',...) | |
24 | (this format will be used for the generated thumbnail, too) |
|
25 | (this format will be used for the generated thumbnail, too) | |
25 | """ |
|
26 | """ | |
@@ -41,7 +42,7 b' def generate_thumb(img, thumb_size, form' | |||||
41 | # crop it |
|
42 | # crop it | |
42 | image2 = image.crop( |
|
43 | image2 = image.crop( | |
43 | (xnewsize, ynewsize, xsize - xnewsize, ysize - ynewsize)) |
|
44 | (xnewsize, ynewsize, xsize - xnewsize, ysize - ynewsize)) | |
44 |
# load is necessary after crop |
|
45 | # load is necessary after crop | |
45 | image2.load() |
|
46 | image2.load() | |
46 | # thumbnail of the cropped image (with ANTIALIAS to make it look better) |
|
47 | # thumbnail of the cropped image (with ANTIALIAS to make it look better) | |
47 | image2.thumbnail(thumb_size, Image.ANTIALIAS) |
|
48 | image2.thumbnail(thumb_size, Image.ANTIALIAS) | |
@@ -160,7 +161,9 b' class ImageWithThumbsField(ImageField):' | |||||
160 | """ |
|
161 | """ | |
161 |
|
162 | |||
162 | def __init__(self, verbose_name=None, name=None, width_field=None, |
|
163 | def __init__(self, verbose_name=None, name=None, width_field=None, | |
163 |
height_field=None, sizes=None, |
|
164 | height_field=None, sizes=None, | |
|
165 | preview_width_field=None, preview_height_field=None, | |||
|
166 | **kwargs): | |||
164 | self.verbose_name = verbose_name |
|
167 | self.verbose_name = verbose_name | |
165 | self.name = name |
|
168 | self.name = name | |
166 | self.width_field = width_field |
|
169 | self.width_field = width_field | |
@@ -168,6 +171,46 b' class ImageWithThumbsField(ImageField):' | |||||
168 | self.sizes = sizes |
|
171 | self.sizes = sizes | |
169 | super(ImageField, self).__init__(**kwargs) |
|
172 | super(ImageField, self).__init__(**kwargs) | |
170 |
|
173 | |||
|
174 | if sizes is not None and len(sizes) == 1: | |||
|
175 | self.preview_width_field = preview_width_field | |||
|
176 | self.preview_height_field = preview_height_field | |||
|
177 | ||||
|
178 | def update_dimension_fields(self, instance, force=False, *args, **kwargs): | |||
|
179 | """ | |||
|
180 | Update original image dimension fields and thumb dimension fields | |||
|
181 | (only if 1 thumb size is defined) | |||
|
182 | """ | |||
|
183 | ||||
|
184 | super(ImageWithThumbsField, self).update_dimension_fields(instance, | |||
|
185 | force, *args, | |||
|
186 | **kwargs) | |||
|
187 | thumb_width_field = self.preview_width_field | |||
|
188 | thumb_height_field = self.preview_height_field | |||
|
189 | ||||
|
190 | if thumb_width_field is None or thumb_height_field is None \ | |||
|
191 | or len(self.sizes) != 1: | |||
|
192 | return | |||
|
193 | ||||
|
194 | original_width = getattr(instance, self.width_field) | |||
|
195 | original_height = getattr(instance, self.height_field) | |||
|
196 | ||||
|
197 | if original_width > 0 and original_height > 0: | |||
|
198 | thumb_width, thumb_height = self.sizes[0] | |||
|
199 | ||||
|
200 | w_scale = float(thumb_width) / original_width | |||
|
201 | h_scale = float(thumb_height) / original_height | |||
|
202 | scale_ratio = min(w_scale, h_scale) | |||
|
203 | ||||
|
204 | if scale_ratio >= 1: | |||
|
205 | thumb_width_ratio = original_width | |||
|
206 | thumb_height_ratio = original_height | |||
|
207 | else: | |||
|
208 | thumb_width_ratio = int(original_width * scale_ratio) | |||
|
209 | thumb_height_ratio = int(original_height * scale_ratio) | |||
|
210 | ||||
|
211 | setattr(instance, thumb_width_field, thumb_width_ratio) | |||
|
212 | setattr(instance, thumb_height_field, thumb_height_ratio) | |||
|
213 | ||||
171 |
|
214 | |||
172 | from south.modelsinspector import add_introspection_rules |
|
215 | from south.modelsinspector import add_introspection_rules | |
173 | add_introspection_rules([], ["^boards\.thumbs\.ImageWithThumbsField"]) |
|
216 | add_introspection_rules([], ["^boards\.thumbs\.ImageWithThumbsField"]) |
@@ -31,6 +31,7 b" urlpatterns = patterns(''," | |||||
31 |
|
31 | |||
32 | # /boards/thread/ |
|
32 | # /boards/thread/ | |
33 | url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'), |
|
33 | url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'), | |
|
34 | url(r'^thread/(?P<post_id>\w+)/(?P<mode>\w+)/$', views.thread, name='thread_mode'), | |||
34 | url(r'^settings/$', views.settings, name='settings'), |
|
35 | url(r'^settings/$', views.settings, name='settings'), | |
35 | url(r'^tags/$', views.all_tags, name='tags'), |
|
36 | url(r'^tags/$', views.all_tags, name='tags'), | |
36 | url(r'^captcha/', include('captcha.urls')), |
|
37 | url(r'^captcha/', include('captcha.urls')), |
@@ -7,7 +7,7 b' import re' | |||||
7 |
|
7 | |||
8 | from django.core import serializers |
|
8 | from django.core import serializers | |
9 | from django.core.urlresolvers import reverse |
|
9 | from django.core.urlresolvers import reverse | |
10 | from django.http import HttpResponseRedirect |
|
10 | from django.http import HttpResponseRedirect, Http404 | |
11 | from django.http.response import HttpResponse |
|
11 | from django.http.response import HttpResponse | |
12 | from django.template import RequestContext |
|
12 | from django.template import RequestContext | |
13 | from django.shortcuts import render, redirect, get_object_or_404 |
|
13 | from django.shortcuts import render, redirect, get_object_or_404 | |
@@ -30,6 +30,8 b' import neboard' | |||||
30 |
|
30 | |||
31 |
|
31 | |||
32 | BAN_REASON_SPAM = 'Autoban: spam bot' |
|
32 | BAN_REASON_SPAM = 'Autoban: spam bot' | |
|
33 | MODE_GALLERY = 'gallery' | |||
|
34 | MODE_NORMAL = 'normal' | |||
33 |
|
35 | |||
34 |
|
36 | |||
35 | def index(request, page=0): |
|
37 | def index(request, page=0): | |
@@ -62,6 +64,7 b' def index(request, page=0):' | |||||
62 | # TODO Make this generic for tag and threads list pages |
|
64 | # TODO Make this generic for tag and threads list pages | |
63 | context['threads'] = None if len(threads) == 0 else threads |
|
65 | context['threads'] = None if len(threads) == 0 else threads | |
64 | context['form'] = form |
|
66 | context['form'] = form | |
|
67 | context['current_page'] = int(page) | |||
65 |
|
68 | |||
66 | page_count = Post.objects.get_thread_page_count() |
|
69 | page_count = Post.objects.get_thread_page_count() | |
67 | context['pages'] = range(page_count) |
|
70 | context['pages'] = range(page_count) | |
@@ -154,6 +157,7 b' def tag(request, tag_name, page=0):' | |||||
154 | context = _init_default_context(request) |
|
157 | context = _init_default_context(request) | |
155 | context['threads'] = None if len(threads) == 0 else threads |
|
158 | context['threads'] = None if len(threads) == 0 else threads | |
156 | context['tag'] = tag |
|
159 | context['tag'] = tag | |
|
160 | context['current_page'] = int(page) | |||
157 |
|
161 | |||
158 | page_count = Post.objects.get_thread_page_count(tag=tag) |
|
162 | page_count = Post.objects.get_thread_page_count(tag=tag) | |
159 | context['pages'] = range(page_count) |
|
163 | context['pages'] = range(page_count) | |
@@ -169,7 +173,7 b' def tag(request, tag_name, page=0):' | |||||
169 | context) |
|
173 | context) | |
170 |
|
174 | |||
171 |
|
175 | |||
172 | def thread(request, post_id): |
|
176 | def thread(request, post_id, mode=MODE_NORMAL): | |
173 | """Get all thread posts""" |
|
177 | """Get all thread posts""" | |
174 |
|
178 | |||
175 | if utils.need_include_captcha(request): |
|
179 | if utils.need_include_captcha(request): | |
@@ -209,7 +213,14 b' def thread(request, post_id):' | |||||
209 | context["last_update"] = _datetime_to_epoch(thread_to_show.last_edit_time) |
|
213 | context["last_update"] = _datetime_to_epoch(thread_to_show.last_edit_time) | |
210 | context["thread"] = thread_to_show |
|
214 | context["thread"] = thread_to_show | |
211 |
|
215 | |||
212 | return render(request, 'boards/thread.html', context) |
|
216 | if MODE_NORMAL == mode: | |
|
217 | document = 'boards/thread.html' | |||
|
218 | elif MODE_GALLERY == mode: | |||
|
219 | document = 'boards/thread_gallery.html' | |||
|
220 | else: | |||
|
221 | raise Http404 | |||
|
222 | ||||
|
223 | return render(request, document, context) | |||
213 |
|
224 | |||
214 |
|
225 | |||
215 | def login(request): |
|
226 | def login(request): |
@@ -27,7 +27,7 b' Site: http://neboard.me/' | |||||
27 | # INSTALLATION # |
|
27 | # INSTALLATION # | |
28 |
|
28 | |||
29 | 1. Install all dependencies over pip or system-wide |
|
29 | 1. Install all dependencies over pip or system-wide | |
30 | 2. Setup a database in neboard/settings.py |
|
30 | 2. Setup a database in `neboard/settings.py` | |
31 | 3. Run `./manage.py syncdb` and ensure the database was created |
|
31 | 3. Run `./manage.py syncdb` and ensure the database was created | |
32 | 4. Run `./manage.py migrate boards` to apply all south migrations |
|
32 | 4. Run `./manage.py migrate boards` to apply all south migrations | |
33 |
|
33 | |||
@@ -41,6 +41,15 b' See django-admin command help for detail' | |||||
41 |
|
41 | |||
42 | Also consider using wsgi or fcgi interfaces on production servers. |
|
42 | Also consider using wsgi or fcgi interfaces on production servers. | |
43 |
|
43 | |||
|
44 | # UPGRADE # | |||
|
45 | ||||
|
46 | 1. Backup your project data. | |||
|
47 | 2. Save the settings in `neboard/settings.py` and `boards/settings.py` | |||
|
48 | 3. Copy the project contents over the old project directory | |||
|
49 | 4. Run migrations by `./manage.py migrate boards` | |||
|
50 | ||||
|
51 | You can also just clone the mercurial project and pull it to update | |||
|
52 | ||||
44 | # CONCLUSION # |
|
53 | # CONCLUSION # | |
45 |
|
54 | |||
46 | Enjoy our software and thank you! |
|
55 | Enjoy our software and thank you! |
@@ -12,6 +12,7 b' denied". Use second only for autoban for' | |||||
12 | [DONE] Split up post model into post and thread, |
|
12 | [DONE] Split up post model into post and thread, | |
13 | and move everything that is used only in 1st post to thread model. |
|
13 | and move everything that is used only in 1st post to thread model. | |
14 | [DONE] Show board speed in the lower panel (posts per day) |
|
14 | [DONE] Show board speed in the lower panel (posts per day) | |
|
15 | [DONE] Save image thumbnails size to the separate field | |||
15 |
|
16 | |||
16 | [NOT STARTED] Tree view (JS) |
|
17 | [NOT STARTED] Tree view (JS) | |
17 | [NOT STARTED] Adding tags to images filename |
|
18 | [NOT STARTED] Adding tags to images filename | |
@@ -22,7 +23,6 b' and move everything that is used only in' | |||||
22 | [NOT STARTED] Javascript disabling engine |
|
23 | [NOT STARTED] Javascript disabling engine | |
23 | [NOT STARTED] Group tags by first letter in all tags list |
|
24 | [NOT STARTED] Group tags by first letter in all tags list | |
24 | [NOT STARTED] Character counter in the post field |
|
25 | [NOT STARTED] Character counter in the post field | |
25 | [NOT STARTED] Save image thumbnails size to the separate field |
|
|||
26 | [NOT STARTED] Whitelist functionality. Permin autoban of an address |
|
26 | [NOT STARTED] Whitelist functionality. Permin autoban of an address | |
27 | [NOT STARTED] Statistics module. Count views (optional, may result in bad |
|
27 | [NOT STARTED] Statistics module. Count views (optional, may result in bad | |
28 | performance), posts per day/week/month, users (or IPs) |
|
28 | performance), posts per day/week/month, users (or IPs) |
General Comments 0
You need to be logged in to leave comments.
Login now