##// END OF EJS Templates
Added button to update thread manually if websocket connection failed
neko259 -
r1011:23c5d871 default
parent child Browse files
Show More
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,397 +1,401 b''
1 # SOME DESCRIPTIVE TITLE.
1 # SOME DESCRIPTIVE TITLE.
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 # This file is distributed under the same license as the PACKAGE package.
3 # This file is distributed under the same license as the PACKAGE package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 #
5 #
6 msgid ""
6 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: 2015-02-24 08:32+0200\n"
10 "POT-Creation-Date: 2015-03-03 23:49+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"
14 "Language: ru\n"
14 "Language: ru\n"
15 "MIME-Version: 1.0\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20
20
21 #: admin.py:22
21 #: admin.py:22
22 msgid "{} posters were banned"
22 msgid "{} posters were banned"
23 msgstr ""
23 msgstr ""
24
24
25 #: authors.py:9
25 #: authors.py:9
26 msgid "author"
26 msgid "author"
27 msgstr "автор"
27 msgstr "автор"
28
28
29 #: authors.py:10
29 #: authors.py:10
30 msgid "developer"
30 msgid "developer"
31 msgstr "разработчик"
31 msgstr "разработчик"
32
32
33 #: authors.py:11
33 #: authors.py:11
34 msgid "javascript developer"
34 msgid "javascript developer"
35 msgstr "разработчик javascript"
35 msgstr "разработчик javascript"
36
36
37 #: authors.py:12
37 #: authors.py:12
38 msgid "designer"
38 msgid "designer"
39 msgstr "дизайнер"
39 msgstr "дизайнер"
40
40
41 #: forms.py:32
41 #: forms.py:33
42 msgid "Type message here. Use formatting panel for more advanced usage."
42 msgid "Type message here. Use formatting panel for more advanced usage."
43 msgstr ""
43 msgstr ""
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
45
45
46 #: forms.py:33
46 #: forms.py:34
47 msgid "tag1 several_words_tag"
47 msgid "tag1 several_words_tag"
48 msgstr "метка1 метка_из_нескольких_слов"
48 msgstr "метка1 метка_из_нескольких_слов"
49
49
50 #: forms.py:35
50 #: forms.py:36
51 msgid "Title"
51 msgid "Title"
52 msgstr "Заголовок"
52 msgstr "Заголовок"
53
53
54 #: forms.py:36
54 #: forms.py:37
55 msgid "Text"
55 msgid "Text"
56 msgstr "Текст"
56 msgstr "Текст"
57
57
58 #: forms.py:37
58 #: forms.py:38
59 msgid "Tag"
59 msgid "Tag"
60 msgstr "Метка"
60 msgstr "Метка"
61
61
62 #: forms.py:38 templates/boards/base.html:38 templates/search/search.html:9
62 #: forms.py:39 templates/boards/base.html:38 templates/search/search.html:9
63 #: templates/search/search.html.py:13
63 #: templates/search/search.html.py:13
64 msgid "Search"
64 msgid "Search"
65 msgstr "Поиск"
65 msgstr "Поиск"
66
66
67 #: forms.py:125
67 #: forms.py:131
68 msgid "Image"
68 msgid "Image"
69 msgstr "Изображение"
69 msgstr "Изображение"
70
70
71 #: forms.py:128
71 #: forms.py:134
72 msgid "Image URL"
72 msgid "Image URL"
73 msgstr "URL изображения"
73 msgstr "URL изображения"
74
74
75 #: forms.py:134
75 #: forms.py:140
76 msgid "e-mail"
76 msgid "e-mail"
77 msgstr ""
77 msgstr ""
78
78
79 #: forms.py:145
79 #: forms.py:151
80 #, python-format
80 #, python-format
81 msgid "Title must have less than %s characters"
81 msgid "Title must have less than %s characters"
82 msgstr "Заголовок должен иметь меньше %s символов"
82 msgstr "Заголовок должен иметь меньше %s символов"
83
83
84 #: forms.py:154
84 #: forms.py:160
85 #, python-format
85 #, python-format
86 msgid "Text must have less than %s characters"
86 msgid "Text must have less than %s characters"
87 msgstr "Текст должен быть короче %s символов"
87 msgstr "Текст должен быть короче %s символов"
88
88
89 #: forms.py:175
89 #: forms.py:181
90 msgid "Invalid URL"
90 msgid "Invalid URL"
91 msgstr "Неверный URL"
91 msgstr "Неверный URL"
92
92
93 #: forms.py:212
93 #: forms.py:218
94 msgid "Either text or image must be entered."
94 msgid "Either text or image must be entered."
95 msgstr "Текст или картинка должны быть введены."
95 msgstr "Текст или картинка должны быть введены."
96
96
97 #: forms.py:219 forms.py:261 forms.py:275
97 #: forms.py:225 forms.py:267 forms.py:281
98 #, python-format
98 #, python-format
99 msgid "Image must be less than %s bytes"
99 msgid "Image must be less than %s bytes"
100 msgstr "Изображение должно быть менее %s байт"
100 msgstr "Изображение должно быть менее %s байт"
101
101
102 #: forms.py:235
102 #: forms.py:241
103 #, python-format
103 #, python-format
104 msgid "Wait %s seconds after last posting"
104 msgid "Wait %s seconds after last posting"
105 msgstr "Подождите %s секунд после последнего постинга"
105 msgstr "Подождите %s секунд после последнего постинга"
106
106
107 #: forms.py:296 templates/boards/rss/post.html:10 templates/boards/tags.html:7
107 #: forms.py:302 templates/boards/rss/post.html:10 templates/boards/tags.html:7
108 msgid "Tags"
108 msgid "Tags"
109 msgstr "Метки"
109 msgstr "Метки"
110
110
111 #: forms.py:303
111 #: forms.py:309
112 msgid "Inappropriate characters in tags."
112 msgid "Inappropriate characters in tags."
113 msgstr "Недопустимые символы в метках."
113 msgstr "Недопустимые символы в метках."
114
114
115 #: forms.py:314
115 #: forms.py:320
116 msgid "Need at least 1 required tag."
116 msgid "Need at least 1 required tag."
117 msgstr "Нужна хотя бы 1 обязательная метка."
117 msgstr "Нужна хотя бы 1 обязательная метка."
118
118
119 #: forms.py:327
119 #: forms.py:333
120 msgid "Theme"
120 msgid "Theme"
121 msgstr "Тема"
121 msgstr "Тема"
122
122
123 #: forms.py:328
123 #: forms.py:334
124 msgid "User name"
124 msgid "User name"
125 msgstr "Имя пользователя"
125 msgstr "Имя пользователя"
126
126
127 #: forms.py:334
127 #: forms.py:340
128 msgid "Inappropriate characters."
128 msgid "Inappropriate characters."
129 msgstr "Недопустимые символы."
129 msgstr "Недопустимые символы."
130
130
131 #: templates/boards/404.html:6
131 #: templates/boards/404.html:6
132 msgid "Not found"
132 msgid "Not found"
133 msgstr "Не найдено"
133 msgstr "Не найдено"
134
134
135 #: templates/boards/404.html:12
135 #: templates/boards/404.html:12
136 msgid "This page does not exist"
136 msgid "This page does not exist"
137 msgstr "Этой страницы не существует"
137 msgstr "Этой страницы не существует"
138
138
139 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
139 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
140 msgid "Authors"
140 msgid "Authors"
141 msgstr "Авторы"
141 msgstr "Авторы"
142
142
143 #: templates/boards/authors.html:26
143 #: templates/boards/authors.html:26
144 msgid "Distributed under the"
144 msgid "Distributed under the"
145 msgstr "Распространяется под"
145 msgstr "Распространяется под"
146
146
147 #: templates/boards/authors.html:28
147 #: templates/boards/authors.html:28
148 msgid "license"
148 msgid "license"
149 msgstr "лицензией"
149 msgstr "лицензией"
150
150
151 #: templates/boards/authors.html:30
151 #: templates/boards/authors.html:30
152 msgid "Repository"
152 msgid "Repository"
153 msgstr "Репозиторий"
153 msgstr "Репозиторий"
154
154
155 #: templates/boards/base.html:13
155 #: templates/boards/base.html:13
156 msgid "Feed"
156 msgid "Feed"
157 msgstr "Лента"
157 msgstr "Лента"
158
158
159 #: templates/boards/base.html:30
159 #: templates/boards/base.html:30
160 msgid "All threads"
160 msgid "All threads"
161 msgstr "Все темы"
161 msgstr "Все темы"
162
162
163 #: templates/boards/base.html:36
163 #: templates/boards/base.html:36
164 msgid "Tag management"
164 msgid "Tag management"
165 msgstr "Управление метками"
165 msgstr "Управление метками"
166
166
167 #: templates/boards/base.html:41 templates/boards/notifications.html:7
167 #: templates/boards/base.html:41 templates/boards/notifications.html:7
168 msgid "Notifications"
168 msgid "Notifications"
169 msgstr "Уведомления"
169 msgstr "Уведомления"
170
170
171 #: templates/boards/base.html:41
171 #: templates/boards/base.html:41
172 msgid "notifications"
172 msgid "notifications"
173 msgstr "уведомлений"
173 msgstr "уведомлений"
174
174
175 #: templates/boards/base.html:44 templates/boards/settings.html:7
175 #: templates/boards/base.html:44 templates/boards/settings.html:7
176 msgid "Settings"
176 msgid "Settings"
177 msgstr "Настройки"
177 msgstr "Настройки"
178
178
179 #: templates/boards/base.html:57
179 #: templates/boards/base.html:57
180 msgid "Admin"
180 msgid "Admin"
181 msgstr "Администрирование"
181 msgstr "Администрирование"
182
182
183 #: templates/boards/base.html:59
183 #: templates/boards/base.html:59
184 #, python-format
184 #, python-format
185 msgid "Speed: %(ppd)s posts per day"
185 msgid "Speed: %(ppd)s posts per day"
186 msgstr "Скорость: %(ppd)s сообщений в день"
186 msgstr "Скорость: %(ppd)s сообщений в день"
187
187
188 #: templates/boards/base.html:61
188 #: templates/boards/base.html:61
189 msgid "Up"
189 msgid "Up"
190 msgstr "Вверх"
190 msgstr "Вверх"
191
191
192 #: templates/boards/login.html:6 templates/boards/login.html.py:16
192 #: templates/boards/login.html:6 templates/boards/login.html.py:16
193 msgid "Login"
193 msgid "Login"
194 msgstr "Вход"
194 msgstr "Вход"
195
195
196 #: templates/boards/login.html:19
196 #: templates/boards/login.html:19
197 msgid "Insert your user id above"
197 msgid "Insert your user id above"
198 msgstr "Вставьте свой ID пользователя выше"
198 msgstr "Вставьте свой ID пользователя выше"
199
199
200 #: templates/boards/notifications.html:16
200 #: templates/boards/notifications.html:16
201 #: templates/boards/posting_general.html:85 templates/search/search.html:22
201 #: templates/boards/posting_general.html:79 templates/search/search.html:22
202 msgid "Previous page"
202 msgid "Previous page"
203 msgstr "Предыдущая страница"
203 msgstr "Предыдущая страница"
204
204
205 #: templates/boards/notifications.html:26
205 #: templates/boards/notifications.html:26
206 #: templates/boards/posting_general.html:125 templates/search/search.html:33
206 #: templates/boards/posting_general.html:117 templates/search/search.html:33
207 msgid "Next page"
207 msgid "Next page"
208 msgstr "Следующая страница"
208 msgstr "Следующая страница"
209
209
210 #: templates/boards/post.html:19 templates/boards/staticpages/help.html:17
210 #: templates/boards/post.html:19 templates/boards/staticpages/help.html:17
211 msgid "Quote"
211 msgid "Quote"
212 msgstr "Цитата"
212 msgstr "Цитата"
213
213
214 #: templates/boards/post.html:35
214 #: templates/boards/post.html:35
215 msgid "Open"
215 msgid "Open"
216 msgstr "Открыть"
216 msgstr "Открыть"
217
217
218 #: templates/boards/post.html:37
218 #: templates/boards/post.html:37
219 msgid "Reply"
219 msgid "Reply"
220 msgstr "Ответ"
220 msgstr "Ответ"
221
221
222 #: templates/boards/post.html:43
222 #: templates/boards/post.html:43
223 msgid "Edit"
223 msgid "Edit"
224 msgstr "Изменить"
224 msgstr "Изменить"
225
225
226 #: templates/boards/post.html:45
226 #: templates/boards/post.html:45
227 msgid "Edit thread"
227 msgid "Edit thread"
228 msgstr "Изменить тему"
228 msgstr "Изменить тему"
229
229
230 #: templates/boards/post.html:75
230 #: templates/boards/post.html:75
231 msgid "Replies"
231 msgid "Replies"
232 msgstr "Ответы"
232 msgstr "Ответы"
233
233
234 #: templates/boards/post.html:86 templates/boards/thread.html:86
234 #: templates/boards/post.html:86 templates/boards/thread.html:86
235 #: templates/boards/thread_gallery.html:59
235 #: templates/boards/thread_gallery.html:59
236 msgid "messages"
236 msgid "messages"
237 msgstr "сообщений"
237 msgstr "сообщений"
238
238
239 #: templates/boards/post.html:87 templates/boards/thread.html:87
239 #: templates/boards/post.html:87 templates/boards/thread.html:87
240 #: templates/boards/thread_gallery.html:60
240 #: templates/boards/thread_gallery.html:60
241 msgid "images"
241 msgid "images"
242 msgstr "изображений"
242 msgstr "изображений"
243
243
244 #: templates/boards/posting_general.html:56
244 #: templates/boards/posting_general.html:52
245 msgid "Show tag"
245 msgid "Show tag"
246 msgstr "Показывать метку"
246 msgstr "Показывать метку"
247
247
248 #: templates/boards/posting_general.html:60
248 #: templates/boards/posting_general.html:56
249 msgid "Hide tag"
249 msgid "Hide tag"
250 msgstr "Скрывать метку"
250 msgstr "Скрывать метку"
251
251
252 #: templates/boards/posting_general.html:67
252 #: templates/boards/posting_general.html:63
253 msgid "Edit tag"
253 msgid "Edit tag"
254 msgstr "Изменить метку"
254 msgstr "Изменить метку"
255
255
256 #: templates/boards/posting_general.html:70
256 #: templates/boards/posting_general.html:66
257 #, python-format
257 #, python-format
258 msgid "This tag has %(thread_count)s threads and %(post_count)s posts."
258 msgid "This tag has %(thread_count)s threads and %(post_count)s posts."
259 msgstr "С этой меткой есть %(thread_count)s тем и %(post_count)s сообщений."
259 msgstr "С этой меткой есть %(thread_count)s тем и %(post_count)s сообщений."
260
260
261 #: templates/boards/posting_general.html:99
261 #: templates/boards/posting_general.html:93
262 #, python-format
262 #, python-format
263 msgid "Skipped %(count)s replies. Open thread to see all replies."
263 msgid "Skipped %(count)s replies. Open thread to see all replies."
264 msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
264 msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
265
265
266 #: templates/boards/posting_general.html:130
266 #: templates/boards/posting_general.html:122
267 msgid "No threads exist. Create the first one!"
267 msgid "No threads exist. Create the first one!"
268 msgstr "Нет тем. Создайте первую!"
268 msgstr "Нет тем. Создайте первую!"
269
269
270 #: templates/boards/posting_general.html:136
270 #: templates/boards/posting_general.html:128
271 msgid "Create new thread"
271 msgid "Create new thread"
272 msgstr "Создать новую тему"
272 msgstr "Создать новую тему"
273
273
274 #: templates/boards/posting_general.html:141 templates/boards/preview.html:16
274 #: templates/boards/posting_general.html:133 templates/boards/preview.html:16
275 #: templates/boards/thread.html:54
275 #: templates/boards/thread.html:53
276 msgid "Post"
276 msgid "Post"
277 msgstr "Отправить"
277 msgstr "Отправить"
278
278
279 #: templates/boards/posting_general.html:146
279 #: templates/boards/posting_general.html:139
280 msgid "Tags must be delimited by spaces. Text or image is required."
280 msgid "Tags must be delimited by spaces. Text or image is required."
281 msgstr ""
281 msgstr ""
282 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
282 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
283
283
284 #: templates/boards/posting_general.html:149 templates/boards/thread.html:59
284 #: templates/boards/posting_general.html:142 templates/boards/thread.html:59
285 msgid "Text syntax"
285 msgid "Text syntax"
286 msgstr "Синтаксис текста"
286 msgstr "Синтаксис текста"
287
287
288 #: templates/boards/posting_general.html:161
288 #: templates/boards/posting_general.html:154
289 msgid "Pages:"
289 msgid "Pages:"
290 msgstr "Страницы: "
290 msgstr "Страницы: "
291
291
292 #: templates/boards/preview.html:6 templates/boards/staticpages/help.html:19
292 #: templates/boards/preview.html:6 templates/boards/staticpages/help.html:19
293 msgid "Preview"
293 msgid "Preview"
294 msgstr "Предпросмотр"
294 msgstr "Предпросмотр"
295
295
296 #: templates/boards/rss/post.html:5
296 #: templates/boards/rss/post.html:5
297 msgid "Post image"
297 msgid "Post image"
298 msgstr "Изображение сообщения"
298 msgstr "Изображение сообщения"
299
299
300 #: templates/boards/settings.html:15
300 #: templates/boards/settings.html:15
301 msgid "You are moderator."
301 msgid "You are moderator."
302 msgstr "Вы модератор."
302 msgstr "Вы модератор."
303
303
304 #: templates/boards/settings.html:19
304 #: templates/boards/settings.html:19
305 msgid "Hidden tags:"
305 msgid "Hidden tags:"
306 msgstr "Скрытые метки:"
306 msgstr "Скрытые метки:"
307
307
308 #: templates/boards/settings.html:26
308 #: templates/boards/settings.html:27
309 msgid "No hidden tags."
309 msgid "No hidden tags."
310 msgstr "Нет скрытых меток."
310 msgstr "Нет скрытых меток."
311
311
312 #: templates/boards/settings.html:35
312 #: templates/boards/settings.html:36
313 msgid "Save"
313 msgid "Save"
314 msgstr "Сохранить"
314 msgstr "Сохранить"
315
315
316 #: templates/boards/staticpages/banned.html:6
316 #: templates/boards/staticpages/banned.html:6
317 msgid "Banned"
317 msgid "Banned"
318 msgstr "Заблокирован"
318 msgstr "Заблокирован"
319
319
320 #: templates/boards/staticpages/banned.html:11
320 #: templates/boards/staticpages/banned.html:11
321 msgid "Your IP address has been banned. Contact the administrator"
321 msgid "Your IP address has been banned. Contact the administrator"
322 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
322 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
323
323
324 #: templates/boards/staticpages/help.html:6
324 #: templates/boards/staticpages/help.html:6
325 #: templates/boards/staticpages/help.html:10
325 #: templates/boards/staticpages/help.html:10
326 msgid "Syntax"
326 msgid "Syntax"
327 msgstr "Синтаксис"
327 msgstr "Синтаксис"
328
328
329 #: templates/boards/staticpages/help.html:11
329 #: templates/boards/staticpages/help.html:11
330 msgid "Italic text"
330 msgid "Italic text"
331 msgstr "Курсивный текст"
331 msgstr "Курсивный текст"
332
332
333 #: templates/boards/staticpages/help.html:12
333 #: templates/boards/staticpages/help.html:12
334 msgid "Bold text"
334 msgid "Bold text"
335 msgstr "Полужирный текст"
335 msgstr "Полужирный текст"
336
336
337 #: templates/boards/staticpages/help.html:13
337 #: templates/boards/staticpages/help.html:13
338 msgid "Spoiler"
338 msgid "Spoiler"
339 msgstr "Спойлер"
339 msgstr "Спойлер"
340
340
341 #: templates/boards/staticpages/help.html:14
341 #: templates/boards/staticpages/help.html:14
342 msgid "Link to a post"
342 msgid "Link to a post"
343 msgstr "Ссылка на сообщение"
343 msgstr "Ссылка на сообщение"
344
344
345 #: templates/boards/staticpages/help.html:15
345 #: templates/boards/staticpages/help.html:15
346 msgid "Strikethrough text"
346 msgid "Strikethrough text"
347 msgstr "Зачеркнутый текст"
347 msgstr "Зачеркнутый текст"
348
348
349 #: templates/boards/staticpages/help.html:16
349 #: templates/boards/staticpages/help.html:16
350 msgid "Comment"
350 msgid "Comment"
351 msgstr "Комментарий"
351 msgstr "Комментарий"
352
352
353 #: templates/boards/staticpages/help.html:19
353 #: templates/boards/staticpages/help.html:19
354 msgid "You can try pasting the text and previewing the result here:"
354 msgid "You can try pasting the text and previewing the result here:"
355 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
355 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
356
356
357 #: templates/boards/tags.html:23
357 #: templates/boards/tags.html:23
358 msgid "No tags found."
358 msgid "No tags found."
359 msgstr "Метки не найдены."
359 msgstr "Метки не найдены."
360
360
361 #: templates/boards/thread.html:19 templates/boards/thread_gallery.html:19
361 #: templates/boards/thread.html:19 templates/boards/thread_gallery.html:19
362 msgid "Normal mode"
362 msgid "Normal mode"
363 msgstr "Нормальный режим"
363 msgstr "Нормальный режим"
364
364
365 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:20
365 #: templates/boards/thread.html:20 templates/boards/thread_gallery.html:20
366 msgid "Gallery mode"
366 msgid "Gallery mode"
367 msgstr "Режим галереи"
367 msgstr "Режим галереи"
368
368
369 #: templates/boards/thread.html:28
369 #: templates/boards/thread.html:28
370 msgid "posts to bumplimit"
370 msgid "posts to bumplimit"
371 msgstr "сообщений до бамплимита"
371 msgstr "сообщений до бамплимита"
372
372
373 #: templates/boards/thread.html:46
373 #: templates/boards/thread.html:46
374 msgid "Reply to thread"
374 msgid "Reply to thread"
375 msgstr "Ответить в тему"
375 msgstr "Ответить в тему"
376
376
377 #: templates/boards/thread.html:85
378 msgid "Update"
379 msgstr "Обновить"
380
377 #: templates/boards/thread.html:88 templates/boards/thread_gallery.html:61
381 #: templates/boards/thread.html:88 templates/boards/thread_gallery.html:61
378 msgid "Last update: "
382 msgid "Last update: "
379 msgstr "Последнее обновление: "
383 msgstr "Последнее обновление: "
380
384
381 #~ msgid "Switch mode"
385 #~ msgid "Switch mode"
382 #~ msgstr "Переключить режим"
386 #~ msgstr "Переключить режим"
383
387
384 #~ msgid "Such image was already posted"
388 #~ msgid "Such image was already posted"
385 #~ msgstr "Такое изображение уже было загружено"
389 #~ msgstr "Такое изображение уже было загружено"
386
390
387 #~ msgid "Invalid master password"
391 #~ msgid "Invalid master password"
388 #~ msgstr "Неверный мастер-пароль"
392 #~ msgstr "Неверный мастер-пароль"
389
393
390 #~ msgid "Wait %s minutes after last login"
394 #~ msgid "Wait %s minutes after last login"
391 #~ msgstr "Подождите %s минут после последнего входа"
395 #~ msgstr "Подождите %s минут после последнего входа"
392
396
393 #~ msgid "Tags:"
397 #~ msgid "Tags:"
394 #~ msgstr "Метки:"
398 #~ msgstr "Метки:"
395
399
396 #~ msgid "Add tag"
400 #~ msgid "Add tag"
397 #~ msgstr "Добавить метку"
401 #~ msgstr "Добавить метку"
@@ -1,330 +1,332 b''
1 /*
1 /*
2 @licstart The following is the entire license notice for the
2 @licstart The following is the entire license notice for the
3 JavaScript code in this page.
3 JavaScript code in this page.
4
4
5
5
6 Copyright (C) 2013-2014 neko259
6 Copyright (C) 2013-2014 neko259
7
7
8 The JavaScript code in this page is free software: you can
8 The JavaScript code in this page is free software: you can
9 redistribute it and/or modify it under the terms of the GNU
9 redistribute it and/or modify it under the terms of the GNU
10 General Public License (GNU GPL) as published by the Free Software
10 General Public License (GNU GPL) as published by the Free Software
11 Foundation, either version 3 of the License, or (at your option)
11 Foundation, either version 3 of the License, or (at your option)
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
13 without even the implied warranty of MERCHANTABILITY or FITNESS
13 without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
15
15
16 As additional permission under GNU GPL version 3 section 7, you
16 As additional permission under GNU GPL version 3 section 7, you
17 may distribute non-source (e.g., minimized or compacted) forms of
17 may distribute non-source (e.g., minimized or compacted) forms of
18 that code without the copy of the GNU GPL normally required by
18 that code without the copy of the GNU GPL normally required by
19 section 4, provided you include this license notice and a URL
19 section 4, provided you include this license notice and a URL
20 through which recipients can access the Corresponding Source.
20 through which recipients can access the Corresponding Source.
21
21
22 @licend The above is the entire license notice
22 @licend The above is the entire license notice
23 for the JavaScript code in this page.
23 for the JavaScript code in this page.
24 */
24 */
25
25
26 var wsUser = '';
26 var wsUser = '';
27
27
28 var unreadPosts = 0;
28 var unreadPosts = 0;
29 var documentOriginalTitle = '';
29 var documentOriginalTitle = '';
30
30
31 // Thread ID does not change, can be stored one time
31 // Thread ID does not change, can be stored one time
32 var threadId = $('div.thread').children('.post').first().attr('id');
32 var threadId = $('div.thread').children('.post').first().attr('id');
33
33
34 /**
34 /**
35 * Connect to websocket server and subscribe to thread updates. On any update we
35 * Connect to websocket server and subscribe to thread updates. On any update we
36 * request a thread diff.
36 * request a thread diff.
37 *
37 *
38 * @returns {boolean} true if connected, false otherwise
38 * @returns {boolean} true if connected, false otherwise
39 */
39 */
40 function connectWebsocket() {
40 function connectWebsocket() {
41 var metapanel = $('.metapanel')[0];
41 var metapanel = $('.metapanel')[0];
42
42
43 var wsHost = metapanel.getAttribute('data-ws-host');
43 var wsHost = metapanel.getAttribute('data-ws-host');
44 var wsPort = metapanel.getAttribute('data-ws-port');
44 var wsPort = metapanel.getAttribute('data-ws-port');
45
45
46 if (wsHost.length > 0 && wsPort.length > 0)
46 if (wsHost.length > 0 && wsPort.length > 0)
47 var centrifuge = new Centrifuge({
47 var centrifuge = new Centrifuge({
48 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
48 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
49 "project": metapanel.getAttribute('data-ws-project'),
49 "project": metapanel.getAttribute('data-ws-project'),
50 "user": wsUser,
50 "user": wsUser,
51 "timestamp": metapanel.getAttribute('data-last-update'),
51 "timestamp": metapanel.getAttribute('data-last-update'),
52 "token": metapanel.getAttribute('data-ws-token'),
52 "token": metapanel.getAttribute('data-ws-token'),
53 "debug": false
53 "debug": false
54 });
54 });
55
55
56 centrifuge.on('error', function(error_message) {
56 centrifuge.on('error', function(error_message) {
57 console.log("Error connecting to websocket server.");
57 console.log("Error connecting to websocket server.");
58 return false;
58 return false;
59 });
59 });
60
60
61 centrifuge.on('connect', function() {
61 centrifuge.on('connect', function() {
62 var channelName = 'thread:' + threadId;
62 var channelName = 'thread:' + threadId;
63 centrifuge.subscribe(channelName, function(message) {
63 centrifuge.subscribe(channelName, function(message) {
64 getThreadDiff();
64 getThreadDiff();
65 });
65 });
66
66
67 // For the case we closed the browser and missed some updates
67 // For the case we closed the browser and missed some updates
68 getThreadDiff();
68 getThreadDiff();
69 $('#autoupdate').text('[+]');
69 $('#autoupdate').hide();
70 });
70 });
71
71
72 centrifuge.connect();
72 centrifuge.connect();
73
73
74 return true;
74 return true;
75 }
75 }
76
76
77 /**
77 /**
78 * Get diff of the posts from the current thread timestamp.
78 * Get diff of the posts from the current thread timestamp.
79 * This is required if the browser was closed and some post updates were
79 * This is required if the browser was closed and some post updates were
80 * missed.
80 * missed.
81 */
81 */
82 function getThreadDiff() {
82 function getThreadDiff() {
83 var lastUpdateTime = $('.metapanel').attr('data-last-update');
83 var lastUpdateTime = $('.metapanel').attr('data-last-update');
84
84
85 var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/';
85 var diffUrl = '/api/diff_thread/' + threadId + '/' + lastUpdateTime + '/';
86
86
87 $.getJSON(diffUrl)
87 $.getJSON(diffUrl)
88 .success(function(data) {
88 .success(function(data) {
89 var addedPosts = data.added;
89 var addedPosts = data.added;
90
90
91 for (var i = 0; i < addedPosts.length; i++) {
91 for (var i = 0; i < addedPosts.length; i++) {
92 var postText = addedPosts[i];
92 var postText = addedPosts[i];
93 var post = $(postText);
93 var post = $(postText);
94
94
95 updatePost(post)
95 updatePost(post)
96 }
96 }
97
97
98 var updatedPosts = data.updated;
98 var updatedPosts = data.updated;
99
99
100 for (var i = 0; i < updatedPosts.length; i++) {
100 for (var i = 0; i < updatedPosts.length; i++) {
101 var postText = updatedPosts[i];
101 var postText = updatedPosts[i];
102 var post = $(postText);
102 var post = $(postText);
103
103
104 updatePost(post)
104 updatePost(post)
105 }
105 }
106
106
107 // TODO Process removed posts if any
107 // TODO Process removed posts if any
108 $('.metapanel').attr('data-last-update', data.last_update);
108 $('.metapanel').attr('data-last-update', data.last_update);
109 })
109 })
110 }
110 }
111
111
112 /**
112 /**
113 * Add or update the post on html page.
113 * Add or update the post on html page.
114 */
114 */
115 function updatePost(postHtml) {
115 function updatePost(postHtml) {
116 // This needs to be set on start because the page is scrolled after posts
116 // This needs to be set on start because the page is scrolled after posts
117 // are added or updated
117 // are added or updated
118 var bottom = isPageBottom();
118 var bottom = isPageBottom();
119
119
120 var post = $(postHtml);
120 var post = $(postHtml);
121
121
122 var threadBlock = $('div.thread');
122 var threadBlock = $('div.thread');
123
123
124 var lastUpdate = '';
124 var lastUpdate = '';
125
125
126 var postId = post.attr('id');
126 var postId = post.attr('id');
127
127
128 // If the post already exists, replace it. Otherwise add as a new one.
128 // If the post already exists, replace it. Otherwise add as a new one.
129 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
129 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
130
130
131 if (existingPosts.size() > 0) {
131 if (existingPosts.size() > 0) {
132 existingPosts.replaceWith(post);
132 existingPosts.replaceWith(post);
133 } else {
133 } else {
134 var threadPosts = threadBlock.children('.post');
134 var threadPosts = threadBlock.children('.post');
135 var lastPost = threadPosts.last();
135 var lastPost = threadPosts.last();
136
136
137 post.appendTo(lastPost.parent());
137 post.appendTo(lastPost.parent());
138
138
139 updateBumplimitProgress(1);
139 updateBumplimitProgress(1);
140 showNewPostsTitle(1);
140 showNewPostsTitle(1);
141
141
142 lastUpdate = post.children('.post-info').first()
142 lastUpdate = post.children('.post-info').first()
143 .children('.pub_time').first().text();
143 .children('.pub_time').first().text();
144
144
145 if (bottom) {
145 if (bottom) {
146 scrollToBottom();
146 scrollToBottom();
147 }
147 }
148 }
148 }
149
149
150 processNewPost(post);
150 processNewPost(post);
151 updateMetadataPanel(lastUpdate)
151 updateMetadataPanel(lastUpdate)
152 }
152 }
153
153
154 /**
154 /**
155 * Initiate a blinking animation on a node to show it was updated.
155 * Initiate a blinking animation on a node to show it was updated.
156 */
156 */
157 function blink(node) {
157 function blink(node) {
158 var blinkCount = 2;
158 var blinkCount = 2;
159
159
160 var nodeToAnimate = node;
160 var nodeToAnimate = node;
161 for (var i = 0; i < blinkCount; i++) {
161 for (var i = 0; i < blinkCount; i++) {
162 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
162 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
163 }
163 }
164 }
164 }
165
165
166 function isPageBottom() {
166 function isPageBottom() {
167 var scroll = $(window).scrollTop() / ($(document).height()
167 var scroll = $(window).scrollTop() / ($(document).height()
168 - $(window).height());
168 - $(window).height());
169
169
170 return scroll == 1
170 return scroll == 1
171 }
171 }
172
172
173 function initAutoupdate() {
173 function initAutoupdate() {
174 return connectWebsocket();
174 return connectWebsocket();
175 }
175 }
176
176
177 function getReplyCount() {
177 function getReplyCount() {
178 return $('.thread').children('.post').length
178 return $('.thread').children('.post').length
179 }
179 }
180
180
181 function getImageCount() {
181 function getImageCount() {
182 return $('.thread').find('img').length
182 return $('.thread').find('img').length
183 }
183 }
184
184
185 /**
185 /**
186 * Update post count, images count and last update time in the metadata
186 * Update post count, images count and last update time in the metadata
187 * panel.
187 * panel.
188 */
188 */
189 function updateMetadataPanel(lastUpdate) {
189 function updateMetadataPanel(lastUpdate) {
190 var replyCountField = $('#reply-count');
190 var replyCountField = $('#reply-count');
191 var imageCountField = $('#image-count');
191 var imageCountField = $('#image-count');
192
192
193 replyCountField.text(getReplyCount());
193 replyCountField.text(getReplyCount());
194 imageCountField.text(getImageCount());
194 imageCountField.text(getImageCount());
195
195
196 if (lastUpdate !== '') {
196 if (lastUpdate !== '') {
197 var lastUpdateField = $('#last-update');
197 var lastUpdateField = $('#last-update');
198 lastUpdateField.text(lastUpdate);
198 lastUpdateField.text(lastUpdate);
199 blink(lastUpdateField);
199 blink(lastUpdateField);
200 }
200 }
201
201
202 blink(replyCountField);
202 blink(replyCountField);
203 blink(imageCountField);
203 blink(imageCountField);
204 }
204 }
205
205
206 /**
206 /**
207 * Update bumplimit progress bar
207 * Update bumplimit progress bar
208 */
208 */
209 function updateBumplimitProgress(postDelta) {
209 function updateBumplimitProgress(postDelta) {
210 var progressBar = $('#bumplimit_progress');
210 var progressBar = $('#bumplimit_progress');
211 if (progressBar) {
211 if (progressBar) {
212 var postsToLimitElement = $('#left_to_limit');
212 var postsToLimitElement = $('#left_to_limit');
213
213
214 var oldPostsToLimit = parseInt(postsToLimitElement.text());
214 var oldPostsToLimit = parseInt(postsToLimitElement.text());
215 var postCount = getReplyCount();
215 var postCount = getReplyCount();
216 var bumplimit = postCount - postDelta + oldPostsToLimit;
216 var bumplimit = postCount - postDelta + oldPostsToLimit;
217
217
218 var newPostsToLimit = bumplimit - postCount;
218 var newPostsToLimit = bumplimit - postCount;
219 if (newPostsToLimit <= 0) {
219 if (newPostsToLimit <= 0) {
220 $('.bar-bg').remove();
220 $('.bar-bg').remove();
221 $('.thread').children('.post').addClass('dead_post');
221 $('.thread').children('.post').addClass('dead_post');
222 } else {
222 } else {
223 postsToLimitElement.text(newPostsToLimit);
223 postsToLimitElement.text(newPostsToLimit);
224 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
224 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
225 }
225 }
226 }
226 }
227 }
227 }
228
228
229 /**
229 /**
230 * Show 'new posts' text in the title if the document is not visible to a user
230 * Show 'new posts' text in the title if the document is not visible to a user
231 */
231 */
232 function showNewPostsTitle(newPostCount) {
232 function showNewPostsTitle(newPostCount) {
233 if (document.hidden) {
233 if (document.hidden) {
234 if (documentOriginalTitle === '') {
234 if (documentOriginalTitle === '') {
235 documentOriginalTitle = document.title;
235 documentOriginalTitle = document.title;
236 }
236 }
237 unreadPosts = unreadPosts + newPostCount;
237 unreadPosts = unreadPosts + newPostCount;
238 document.title = '[' + unreadPosts + '] ' + documentOriginalTitle;
238 document.title = '[' + unreadPosts + '] ' + documentOriginalTitle;
239
239
240 document.addEventListener('visibilitychange', function() {
240 document.addEventListener('visibilitychange', function() {
241 if (documentOriginalTitle !== '') {
241 if (documentOriginalTitle !== '') {
242 document.title = documentOriginalTitle;
242 document.title = documentOriginalTitle;
243 documentOriginalTitle = '';
243 documentOriginalTitle = '';
244 unreadPosts = 0;
244 unreadPosts = 0;
245 }
245 }
246
246
247 document.removeEventListener('visibilitychange', null);
247 document.removeEventListener('visibilitychange', null);
248 });
248 });
249 }
249 }
250 }
250 }
251
251
252 /**
252 /**
253 * Clear all entered values in the form fields
253 * Clear all entered values in the form fields
254 */
254 */
255 function resetForm(form) {
255 function resetForm(form) {
256 form.find('input:text, input:password, input:file, select, textarea').val('');
256 form.find('input:text, input:password, input:file, select, textarea').val('');
257 form.find('input:radio, input:checkbox')
257 form.find('input:radio, input:checkbox')
258 .removeAttr('checked').removeAttr('selected');
258 .removeAttr('checked').removeAttr('selected');
259 $('.file_wrap').find('.file-thumb').remove();
259 $('.file_wrap').find('.file-thumb').remove();
260 }
260 }
261
261
262 /**
262 /**
263 * When the form is posted, this method will be run as a callback
263 * When the form is posted, this method will be run as a callback
264 */
264 */
265 function updateOnPost(response, statusText, xhr, form) {
265 function updateOnPost(response, statusText, xhr, form) {
266 var json = $.parseJSON(response);
266 var json = $.parseJSON(response);
267 var status = json.status;
267 var status = json.status;
268
268
269 showAsErrors(form, '');
269 showAsErrors(form, '');
270
270
271 if (status === 'ok') {
271 if (status === 'ok') {
272 resetForm(form);
272 resetForm(form);
273 getThreadDiff();
273 getThreadDiff();
274 } else {
274 } else {
275 var errors = json.errors;
275 var errors = json.errors;
276 for (var i = 0; i < errors.length; i++) {
276 for (var i = 0; i < errors.length; i++) {
277 var fieldErrors = errors[i];
277 var fieldErrors = errors[i];
278
278
279 var error = fieldErrors.errors;
279 var error = fieldErrors.errors;
280
280
281 showAsErrors(form, error);
281 showAsErrors(form, error);
282 }
282 }
283 }
283 }
284
284
285 scrollToBottom();
285 scrollToBottom();
286 }
286 }
287
287
288 /**
288 /**
289 * Show text in the errors row of the form.
289 * Show text in the errors row of the form.
290 * @param form
290 * @param form
291 * @param text
291 * @param text
292 */
292 */
293 function showAsErrors(form, text) {
293 function showAsErrors(form, text) {
294 form.children('.form-errors').remove();
294 form.children('.form-errors').remove();
295
295
296 if (text.length > 0) {
296 if (text.length > 0) {
297 var errorList = $('<div class="form-errors">' + text + '<div>');
297 var errorList = $('<div class="form-errors">' + text + '<div>');
298 errorList.appendTo(form);
298 errorList.appendTo(form);
299 }
299 }
300 }
300 }
301
301
302 /**
302 /**
303 * Run js methods that are usually run on the document, on the new post
303 * Run js methods that are usually run on the document, on the new post
304 */
304 */
305 function processNewPost(post) {
305 function processNewPost(post) {
306 addRefLinkPreview(post[0]);
306 addRefLinkPreview(post[0]);
307 highlightCode(post);
307 highlightCode(post);
308 blink(post);
308 blink(post);
309 }
309 }
310
310
311 $(document).ready(function(){
311 $(document).ready(function(){
312 if (initAutoupdate()) {
312 if (initAutoupdate()) {
313 // Post form data over AJAX
313 // Post form data over AJAX
314 var threadId = $('div.thread').children('.post').first().attr('id');
314 var threadId = $('div.thread').children('.post').first().attr('id');
315
315
316 var form = $('#form');
316 var form = $('#form');
317
317
318 var options = {
318 var options = {
319 beforeSubmit: function(arr, $form, options) {
319 beforeSubmit: function(arr, $form, options) {
320 showAsErrors($('form'), gettext('Sending message...'));
320 showAsErrors($('form'), gettext('Sending message...'));
321 },
321 },
322 success: updateOnPost,
322 success: updateOnPost,
323 url: '/api/add_post/' + threadId + '/'
323 url: '/api/add_post/' + threadId + '/'
324 };
324 };
325
325
326 form.ajaxForm(options);
326 form.ajaxForm(options);
327
327
328 resetForm(form);
328 resetForm(form);
329 }
329 }
330
331 $('#autoupdate').click(getThreadDiff);
330 });
332 });
@@ -1,93 +1,93 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load cache %}
4 {% load cache %}
5 {% load static from staticfiles %}
5 {% load static from staticfiles %}
6 {% load board %}
6 {% load board %}
7
7
8 {% block head %}
8 {% block head %}
9 <title>{{ opening_post.get_title|striptags|truncatewords:10 }}
9 <title>{{ opening_post.get_title|striptags|truncatewords:10 }}
10 - {{ site_name }}</title>
10 - {{ site_name }}</title>
11 {% endblock %}
11 {% endblock %}
12
12
13 {% block content %}
13 {% block content %}
14 {% get_current_language as LANGUAGE_CODE %}
14 {% get_current_language as LANGUAGE_CODE %}
15
15
16 {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %}
16 {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %}
17
17
18 <div class="image-mode-tab">
18 <div class="image-mode-tab">
19 <a class="current_mode" href="{% url 'thread' opening_post.id %}">{% trans 'Normal mode' %}</a>,
19 <a class="current_mode" href="{% url 'thread' opening_post.id %}">{% trans 'Normal mode' %}</a>,
20 <a href="{% url 'thread_gallery' opening_post.id %}">{% trans 'Gallery mode' %}</a>
20 <a href="{% url 'thread_gallery' opening_post.id %}">{% trans 'Gallery mode' %}</a>
21 </div>
21 </div>
22
22
23 {% if bumpable %}
23 {% if bumpable %}
24 <div class="bar-bg">
24 <div class="bar-bg">
25 <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress">
25 <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress">
26 </div>
26 </div>
27 <div class="bar-text">
27 <div class="bar-text">
28 <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %}
28 <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %}
29 </div>
29 </div>
30 </div>
30 </div>
31 {% endif %}
31 {% endif %}
32
32
33 <div class="thread">
33 <div class="thread">
34 {% with can_bump=thread.can_bump %}
34 {% with can_bump=thread.can_bump %}
35 {% for post in thread.get_replies %}
35 {% for post in thread.get_replies %}
36 {% with is_opening=forloop.first %}
36 {% with is_opening=forloop.first %}
37 {% post_view post moderator=moderator is_opening=is_opening bumpable=can_bump opening_post_id=opening_post.id %}
37 {% post_view post moderator=moderator is_opening=is_opening bumpable=can_bump opening_post_id=opening_post.id %}
38 {% endwith %}
38 {% endwith %}
39 {% endfor %}
39 {% endfor %}
40 {% endwith %}
40 {% endwith %}
41 </div>
41 </div>
42
42
43 {% if not thread.archived %}
43 {% if not thread.archived %}
44 <div class="post-form-w">
44 <div class="post-form-w">
45 <script src="{% static 'js/panel.js' %}"></script>
45 <script src="{% static 'js/panel.js' %}"></script>
46 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}</div>
46 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}</div>
47 <div class="post-form" id="compact-form">
47 <div class="post-form" id="compact-form">
48 <div class="swappable-form-full">
48 <div class="swappable-form-full">
49 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
49 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
50 <div class="compact-form-text"></div>
50 <div class="compact-form-text"></div>
51 {{ form.as_div }}
51 {{ form.as_div }}
52 <div class="form-submit">
52 <div class="form-submit">
53 <input type="submit" value="{% trans "Post" %}"/>
53 <input type="submit" value="{% trans "Post" %}"/>
54 </div>
54 </div>
55 (ctrl-enter)
55 (ctrl-enter)
56 </form>
56 </form>
57 </div>
57 </div>
58 <div><a href="{% url "staticpage" name="help" %}">
58 <div><a href="{% url "staticpage" name="help" %}">
59 {% trans 'Text syntax' %}</a></div>
59 {% trans 'Text syntax' %}</a></div>
60 </div>
60 </div>
61 </div>
61 </div>
62
62
63 <script src="{% static 'js/jquery.form.min.js' %}"></script>
63 <script src="{% static 'js/jquery.form.min.js' %}"></script>
64 <script src="{% static 'js/thread_update.js' %}"></script>
64 <script src="{% static 'js/thread_update.js' %}"></script>
65 <script src="{% static 'js/3party/centrifuge.js' %}"></script>
65 <script src="{% static 'js/3party/centrifuge.js' %}"></script>
66 {% endif %}
66 {% endif %}
67
67
68 <script src="{% static 'js/form.js' %}"></script>
68 <script src="{% static 'js/form.js' %}"></script>
69 <script src="{% static 'js/thread.js' %}"></script>
69 <script src="{% static 'js/thread.js' %}"></script>
70
70
71 {% endcache %}
71 {% endcache %}
72 {% endblock %}
72 {% endblock %}
73
73
74 {% block metapanel %}
74 {% block metapanel %}
75
75
76 {% get_current_language as LANGUAGE_CODE %}
76 {% get_current_language as LANGUAGE_CODE %}
77
77
78 <span class="metapanel"
78 <span class="metapanel"
79 data-last-update="{{ last_update }}"
79 data-last-update="{{ last_update }}"
80 data-ws-token="{{ ws_token }}"
80 data-ws-token="{{ ws_token }}"
81 data-ws-project="{{ ws_project }}"
81 data-ws-project="{{ ws_project }}"
82 data-ws-host="{{ ws_host }}"
82 data-ws-host="{{ ws_host }}"
83 data-ws-port="{{ ws_port }}">
83 data-ws-port="{{ ws_port }}">
84 {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %}
84 {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %}
85 <span id="autoupdate">[-]</span>
85 <button id="autoupdate">{% trans 'Update' %}</button>
86 <span id="reply-count">{{ thread.get_reply_count }}</span>/{{ max_replies }} {% trans 'messages' %},
86 <span id="reply-count">{{ thread.get_reply_count }}</span>/{{ max_replies }} {% trans 'messages' %},
87 <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}.
87 <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}.
88 {% trans 'Last update: ' %}<span id="last-update">{{ thread.last_edit_time|date:'r' }}</span>
88 {% trans 'Last update: ' %}<span id="last-update">{{ thread.last_edit_time|date:'r' }}</span>
89 [<a href="rss/">RSS</a>]
89 [<a href="rss/">RSS</a>]
90 {% endcache %}
90 {% endcache %}
91 </span>
91 </span>
92
92
93 {% endblock %}
93 {% endblock %}
@@ -1,66 +1,66 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load cache %}
4 {% load cache %}
5 {% load static from staticfiles %}
5 {% load static from staticfiles %}
6 {% load board %}
6 {% load board %}
7
7
8 {% block head %}
8 {% block head %}
9 <title>{{ thread.get_opening_post.get_title|striptags|truncatewords:10 }}
9 <title>{{ thread.get_opening_post.get_title|striptags|truncatewords:10 }}
10 - {{ site_name }}</title>
10 - {{ site_name }}</title>
11 {% endblock %}
11 {% endblock %}
12
12
13 {% block content %}
13 {% block content %}
14 {% spaceless %}
14 {% spaceless %}
15 {% get_current_language as LANGUAGE_CODE %}
15 {% get_current_language as LANGUAGE_CODE %}
16
16
17 {% cache 600 thread_gallery_view thread.id thread.last_edit_time LANGUAGE_CODE request.get_host %}
17 {% cache 600 thread_gallery_view thread.id thread.last_edit_time LANGUAGE_CODE request.get_host %}
18 <div class="image-mode-tab">
18 <div class="image-mode-tab">
19 <a href="{% url 'thread' thread.get_opening_post.id %}">{% trans 'Normal mode' %}</a>,
19 <a href="{% url 'thread' thread.get_opening_post.id %}">{% trans 'Normal mode' %}</a>,
20 <a class="current_mode" href="{% url 'thread_gallery' thread.get_opening_post.id %}">{% trans 'Gallery mode' %}</a>
20 <a class="current_mode" href="{% url 'thread_gallery' thread.get_opening_post.id %}">{% trans 'Gallery mode' %}</a>
21 </div>
21 </div>
22
22
23 <div id="posts-table">
23 <div id="posts-table">
24 {% for post in posts %}
24 {% for post in posts %}
25 <div class="gallery_image">
25 <div class="gallery_image">
26 {% with post.get_first_image as image %}
26 {% with post.get_first_image as image %}
27 <div>
27 <div>
28 <a
28 <a
29 class="thumb"
29 class="thumb"
30 href="{{ image.image.url }}"><img
30 href="{{ image.image.url }}"><img
31 src="{{ image.image.url_200x150 }}"
31 src="{{ image.image.url_200x150 }}"
32 alt="{{ post.id }}"
32 alt="{{ post.id }}"
33 width="{{ image.pre_width }}"
33 width="{{ image.pre_width }}"
34 height="{{ image.pre_height }}"
34 height="{{ image.pre_height }}"
35 data-width="{{ image.width }}"
35 data-width="{{ image.width }}"
36 data-height="{{ image.height }}"/>
36 data-height="{{ image.height }}"/>
37 </a>
37 </a>
38 </div>
38 </div>
39 <div class="gallery_image_metadata">
39 <div class="gallery_image_metadata">
40 {{ image.width }}x{{ image.height }}
40 {{ image.width }}x{{ image.height }}
41 {% image_actions image.image.url request.get_host %}
41 {% image_actions image.image.url request.get_host %}
42 </div>
42 </div>
43 {% endwith %}
43 {% endwith %}
44 </div>
44 </div>
45 {% endfor %}
45 {% endfor %}
46 </div>
46 </div>
47 {% endcache %}
47 {% endcache %}
48
48
49 {% endspaceless %}
49 {% endspaceless %}
50 {% endblock %}
50 {% endblock %}
51
51
52 {% block metapanel %}
52 {% block metapanel %}
53
53
54 {% get_current_language as LANGUAGE_CODE %}
54 {% get_current_language as LANGUAGE_CODE %}
55
55
56 <span class="metapanel" data-last-update="{{ last_update }}">
56 <span class="metapanel" data-last-update="{{ last_update }}">
57 {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %}
57 {% cache 600 thread_gallery_meta thread.last_edit_time moderator LANGUAGE_CODE %}
58 <span id="reply-count">{{ thread.get_reply_count }}</span>/{{ max_replies }}
58 <span id="reply-count">{{ thread.get_reply_count }}</span>/{{ max_replies }}
59 {% trans 'messages' %},
59 {% trans 'messages' %},
60 <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}.
60 <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}.
61 {% trans 'Last update: ' %}{{ thread.last_edit_time|date:'r' }}
61 {% trans 'Last update: ' %}{{ thread.last_edit_time|date:'r' }}
62 [<a href="rss/">RSS</a>]
62 [<a href="rss/">RSS</a>]
63 {% endcache %}
63 {% endcache %}
64 </span>
64 </span>
65
65
66 {% endblock %}
66 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now