Show More
@@ -1,253 +1,256 b'' | |||||
1 | import re |
|
1 | import re | |
2 | from captcha.fields import CaptchaField |
|
2 | from captcha.fields import CaptchaField | |
3 | from django import forms |
|
3 | from django import forms | |
4 | from django.forms.util import ErrorList |
|
4 | from django.forms.util import ErrorList | |
5 | from django.utils.translation import ugettext_lazy as _ |
|
5 | from django.utils.translation import ugettext_lazy as _ | |
6 | import time |
|
6 | import time | |
7 | from boards.models.post import TITLE_MAX_LENGTH |
|
7 | from boards.models.post import TITLE_MAX_LENGTH | |
8 | from boards.models import User |
|
8 | from boards.models import User | |
9 | from neboard import settings |
|
9 | from neboard import settings | |
10 | from boards import utils |
|
10 | from boards import utils | |
11 | import boards.settings as board_settings |
|
11 | import boards.settings as board_settings | |
12 |
|
12 | |||
13 | LAST_POST_TIME = "last_post_time" |
|
13 | LAST_POST_TIME = "last_post_time" | |
14 | LAST_LOGIN_TIME = "last_login_time" |
|
14 | LAST_LOGIN_TIME = "last_login_time" | |
15 |
|
15 | |||
16 |
|
16 | |||
17 | class PlainErrorList(ErrorList): |
|
17 | class PlainErrorList(ErrorList): | |
18 | def __unicode__(self): |
|
18 | def __unicode__(self): | |
19 | return self.as_text() |
|
19 | return self.as_text() | |
20 |
|
20 | |||
21 | def as_text(self): |
|
21 | def as_text(self): | |
22 | return ''.join([u'(!) %s ' % e for e in self]) |
|
22 | return ''.join([u'(!) %s ' % e for e in self]) | |
23 |
|
23 | |||
24 |
|
24 | |||
25 | class NeboardForm(forms.Form): |
|
25 | class NeboardForm(forms.Form): | |
26 |
|
26 | |||
27 |
def as_ |
|
27 | def as_div(self): | |
28 |
"Returns this form rendered as HTML < |
|
28 | "Returns this form rendered as HTML <as_div>s." | |
29 | return self._html_output( |
|
29 | return self._html_output( | |
30 | # TODO Do not show hidden rows in the list here |
|
30 | # TODO Do not show hidden rows in the list here | |
31 | normal_row='<div class="form-row">' |
|
31 | normal_row='<div class="form-row">' | |
32 | '<div class="form-label">' |
|
32 | '<div class="form-label">' | |
33 | '%(label)s' |
|
33 | '%(label)s' | |
34 | '</div>' |
|
34 | '</div>' | |
35 | '<div class="form-input">' |
|
35 | '<div class="form-input">' | |
36 | '%(field)s' |
|
36 | '%(field)s' | |
37 | '</div>' |
|
37 | '</div>' | |
38 | '%(help_text)s' |
|
38 | '%(help_text)s' | |
39 | '</div>', |
|
39 | '</div>', | |
40 | error_row='<div class="form-row"><div class="form-label"></div><div class="form-errors">%s</div></div>', |
|
40 | error_row='<div class="form-row">' | |
41 | row_ender='</p>', |
|
41 | '<div class="form-label"></div>' | |
42 | help_text_html=' <span class="helptext">%s</span>', |
|
42 | '<div class="form-errors">%s</div>' | |
|
43 | '</div>', | |||
|
44 | row_ender='</div>', | |||
|
45 | help_text_html='%s', | |||
43 | errors_on_separate_row=True) |
|
46 | errors_on_separate_row=True) | |
44 |
|
47 | |||
45 | class PostForm(NeboardForm): |
|
48 | class PostForm(NeboardForm): | |
46 |
|
49 | |||
47 | title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False, |
|
50 | title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False, | |
48 | label=_('Title')) |
|
51 | label=_('Title')) | |
49 | text = forms.CharField(widget=forms.Textarea, required=False, |
|
52 | text = forms.CharField(widget=forms.Textarea, required=False, | |
50 | label=_('Text')) |
|
53 | label=_('Text')) | |
51 | image = forms.ImageField(required=False, label=_('Image')) |
|
54 | image = forms.ImageField(required=False, label=_('Image')) | |
52 |
|
55 | |||
53 | # This field is for spam prevention only |
|
56 | # This field is for spam prevention only | |
54 | email = forms.CharField(max_length=100, required=False, label=_('e-mail'), |
|
57 | email = forms.CharField(max_length=100, required=False, label=_('e-mail'), | |
55 | widget=forms.TextInput(attrs={ |
|
58 | widget=forms.TextInput(attrs={ | |
56 | 'class': 'form-email'})) |
|
59 | 'class': 'form-email'})) | |
57 |
|
60 | |||
58 | session = None |
|
61 | session = None | |
59 | need_to_ban = False |
|
62 | need_to_ban = False | |
60 |
|
63 | |||
61 | def clean_title(self): |
|
64 | def clean_title(self): | |
62 | title = self.cleaned_data['title'] |
|
65 | title = self.cleaned_data['title'] | |
63 | if title: |
|
66 | if title: | |
64 | if len(title) > TITLE_MAX_LENGTH: |
|
67 | if len(title) > TITLE_MAX_LENGTH: | |
65 | raise forms.ValidationError(_('Title must have less than %s ' |
|
68 | raise forms.ValidationError(_('Title must have less than %s ' | |
66 | 'characters') % |
|
69 | 'characters') % | |
67 | str(TITLE_MAX_LENGTH)) |
|
70 | str(TITLE_MAX_LENGTH)) | |
68 | return title |
|
71 | return title | |
69 |
|
72 | |||
70 | def clean_text(self): |
|
73 | def clean_text(self): | |
71 | text = self.cleaned_data['text'] |
|
74 | text = self.cleaned_data['text'] | |
72 | if text: |
|
75 | if text: | |
73 | if len(text) > board_settings.MAX_TEXT_LENGTH: |
|
76 | if len(text) > board_settings.MAX_TEXT_LENGTH: | |
74 | raise forms.ValidationError(_('Text must have less than %s ' |
|
77 | raise forms.ValidationError(_('Text must have less than %s ' | |
75 | 'characters') % |
|
78 | 'characters') % | |
76 | str(board_settings |
|
79 | str(board_settings | |
77 | .MAX_TEXT_LENGTH)) |
|
80 | .MAX_TEXT_LENGTH)) | |
78 | return text |
|
81 | return text | |
79 |
|
82 | |||
80 | def clean_image(self): |
|
83 | def clean_image(self): | |
81 | image = self.cleaned_data['image'] |
|
84 | image = self.cleaned_data['image'] | |
82 | if image: |
|
85 | if image: | |
83 | if image._size > board_settings.MAX_IMAGE_SIZE: |
|
86 | if image._size > board_settings.MAX_IMAGE_SIZE: | |
84 | raise forms.ValidationError( |
|
87 | raise forms.ValidationError( | |
85 | _('Image must be less than %s bytes') |
|
88 | _('Image must be less than %s bytes') | |
86 | % str(board_settings.MAX_IMAGE_SIZE)) |
|
89 | % str(board_settings.MAX_IMAGE_SIZE)) | |
87 | return image |
|
90 | return image | |
88 |
|
91 | |||
89 | def clean(self): |
|
92 | def clean(self): | |
90 | cleaned_data = super(PostForm, self).clean() |
|
93 | cleaned_data = super(PostForm, self).clean() | |
91 |
|
94 | |||
92 | if not self.session: |
|
95 | if not self.session: | |
93 | raise forms.ValidationError('Humans have sessions') |
|
96 | raise forms.ValidationError('Humans have sessions') | |
94 |
|
97 | |||
95 | if cleaned_data['email']: |
|
98 | if cleaned_data['email']: | |
96 | self.need_to_ban = True |
|
99 | self.need_to_ban = True | |
97 | raise forms.ValidationError('A human cannot enter a hidden field') |
|
100 | raise forms.ValidationError('A human cannot enter a hidden field') | |
98 |
|
101 | |||
99 | if not self.errors: |
|
102 | if not self.errors: | |
100 | self._clean_text_image() |
|
103 | self._clean_text_image() | |
101 |
|
104 | |||
102 | if not self.errors and self.session: |
|
105 | if not self.errors and self.session: | |
103 | self._validate_posting_speed() |
|
106 | self._validate_posting_speed() | |
104 |
|
107 | |||
105 | return cleaned_data |
|
108 | return cleaned_data | |
106 |
|
109 | |||
107 | def _clean_text_image(self): |
|
110 | def _clean_text_image(self): | |
108 | text = self.cleaned_data.get('text') |
|
111 | text = self.cleaned_data.get('text') | |
109 | image = self.cleaned_data.get('image') |
|
112 | image = self.cleaned_data.get('image') | |
110 |
|
113 | |||
111 | if (not text) and (not image): |
|
114 | if (not text) and (not image): | |
112 | error_message = _('Either text or image must be entered.') |
|
115 | error_message = _('Either text or image must be entered.') | |
113 | self._errors['text'] = self.error_class([error_message]) |
|
116 | self._errors['text'] = self.error_class([error_message]) | |
114 |
|
117 | |||
115 | def _validate_posting_speed(self): |
|
118 | def _validate_posting_speed(self): | |
116 | can_post = True |
|
119 | can_post = True | |
117 |
|
120 | |||
118 | if LAST_POST_TIME in self.session: |
|
121 | if LAST_POST_TIME in self.session: | |
119 | now = time.time() |
|
122 | now = time.time() | |
120 | last_post_time = self.session[LAST_POST_TIME] |
|
123 | last_post_time = self.session[LAST_POST_TIME] | |
121 |
|
124 | |||
122 | current_delay = int(now - last_post_time) |
|
125 | current_delay = int(now - last_post_time) | |
123 |
|
126 | |||
124 | if current_delay < settings.POSTING_DELAY: |
|
127 | if current_delay < settings.POSTING_DELAY: | |
125 | error_message = _('Wait %s seconds after last posting') % str( |
|
128 | error_message = _('Wait %s seconds after last posting') % str( | |
126 | settings.POSTING_DELAY - current_delay) |
|
129 | settings.POSTING_DELAY - current_delay) | |
127 | self._errors['text'] = self.error_class([error_message]) |
|
130 | self._errors['text'] = self.error_class([error_message]) | |
128 |
|
131 | |||
129 | can_post = False |
|
132 | can_post = False | |
130 |
|
133 | |||
131 | if can_post: |
|
134 | if can_post: | |
132 | self.session[LAST_POST_TIME] = time.time() |
|
135 | self.session[LAST_POST_TIME] = time.time() | |
133 |
|
136 | |||
134 |
|
137 | |||
135 | class ThreadForm(PostForm): |
|
138 | class ThreadForm(PostForm): | |
136 |
|
139 | |||
137 | regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE) |
|
140 | regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE) | |
138 |
|
141 | |||
139 | tags = forms.CharField(max_length=100, label=_('Tags')) |
|
142 | tags = forms.CharField(max_length=100, label=_('Tags')) | |
140 |
|
143 | |||
141 | def clean_tags(self): |
|
144 | def clean_tags(self): | |
142 | tags = self.cleaned_data['tags'] |
|
145 | tags = self.cleaned_data['tags'] | |
143 |
|
146 | |||
144 | if tags: |
|
147 | if tags: | |
145 | if not self.regex_tags.match(tags): |
|
148 | if not self.regex_tags.match(tags): | |
146 | raise forms.ValidationError( |
|
149 | raise forms.ValidationError( | |
147 | _('Inappropriate characters in tags.')) |
|
150 | _('Inappropriate characters in tags.')) | |
148 |
|
151 | |||
149 | return tags |
|
152 | return tags | |
150 |
|
153 | |||
151 | def clean(self): |
|
154 | def clean(self): | |
152 | cleaned_data = super(ThreadForm, self).clean() |
|
155 | cleaned_data = super(ThreadForm, self).clean() | |
153 |
|
156 | |||
154 | return cleaned_data |
|
157 | return cleaned_data | |
155 |
|
158 | |||
156 |
|
159 | |||
157 | class PostCaptchaForm(PostForm): |
|
160 | class PostCaptchaForm(PostForm): | |
158 | captcha = CaptchaField() |
|
161 | captcha = CaptchaField() | |
159 |
|
162 | |||
160 | def __init__(self, *args, **kwargs): |
|
163 | def __init__(self, *args, **kwargs): | |
161 | self.request = kwargs['request'] |
|
164 | self.request = kwargs['request'] | |
162 | del kwargs['request'] |
|
165 | del kwargs['request'] | |
163 |
|
166 | |||
164 | super(PostCaptchaForm, self).__init__(*args, **kwargs) |
|
167 | super(PostCaptchaForm, self).__init__(*args, **kwargs) | |
165 |
|
168 | |||
166 | def clean(self): |
|
169 | def clean(self): | |
167 | cleaned_data = super(PostCaptchaForm, self).clean() |
|
170 | cleaned_data = super(PostCaptchaForm, self).clean() | |
168 |
|
171 | |||
169 | success = self.is_valid() |
|
172 | success = self.is_valid() | |
170 | utils.update_captcha_access(self.request, success) |
|
173 | utils.update_captcha_access(self.request, success) | |
171 |
|
174 | |||
172 | if success: |
|
175 | if success: | |
173 | return cleaned_data |
|
176 | return cleaned_data | |
174 | else: |
|
177 | else: | |
175 | raise forms.ValidationError(_("Captcha validation failed")) |
|
178 | raise forms.ValidationError(_("Captcha validation failed")) | |
176 |
|
179 | |||
177 |
|
180 | |||
178 | class ThreadCaptchaForm(ThreadForm): |
|
181 | class ThreadCaptchaForm(ThreadForm): | |
179 | captcha = CaptchaField() |
|
182 | captcha = CaptchaField() | |
180 |
|
183 | |||
181 | def __init__(self, *args, **kwargs): |
|
184 | def __init__(self, *args, **kwargs): | |
182 | self.request = kwargs['request'] |
|
185 | self.request = kwargs['request'] | |
183 | del kwargs['request'] |
|
186 | del kwargs['request'] | |
184 |
|
187 | |||
185 | super(ThreadCaptchaForm, self).__init__(*args, **kwargs) |
|
188 | super(ThreadCaptchaForm, self).__init__(*args, **kwargs) | |
186 |
|
189 | |||
187 | def clean(self): |
|
190 | def clean(self): | |
188 | cleaned_data = super(ThreadCaptchaForm, self).clean() |
|
191 | cleaned_data = super(ThreadCaptchaForm, self).clean() | |
189 |
|
192 | |||
190 | success = self.is_valid() |
|
193 | success = self.is_valid() | |
191 | utils.update_captcha_access(self.request, success) |
|
194 | utils.update_captcha_access(self.request, success) | |
192 |
|
195 | |||
193 | if success: |
|
196 | if success: | |
194 | return cleaned_data |
|
197 | return cleaned_data | |
195 | else: |
|
198 | else: | |
196 | raise forms.ValidationError(_("Captcha validation failed")) |
|
199 | raise forms.ValidationError(_("Captcha validation failed")) | |
197 |
|
200 | |||
198 |
|
201 | |||
199 | class SettingsForm(NeboardForm): |
|
202 | class SettingsForm(NeboardForm): | |
200 |
|
203 | |||
201 | theme = forms.ChoiceField(choices=settings.THEMES, |
|
204 | theme = forms.ChoiceField(choices=settings.THEMES, | |
202 | label=_('Theme')) |
|
205 | label=_('Theme')) | |
203 |
|
206 | |||
204 |
|
207 | |||
205 | class ModeratorSettingsForm(SettingsForm): |
|
208 | class ModeratorSettingsForm(SettingsForm): | |
206 |
|
209 | |||
207 | moderate = forms.BooleanField(required=False, label=_('Enable moderation ' |
|
210 | moderate = forms.BooleanField(required=False, label=_('Enable moderation ' | |
208 | 'panel')) |
|
211 | 'panel')) | |
209 |
|
212 | |||
210 |
|
213 | |||
211 | class LoginForm(NeboardForm): |
|
214 | class LoginForm(NeboardForm): | |
212 |
|
215 | |||
213 | user_id = forms.CharField() |
|
216 | user_id = forms.CharField() | |
214 |
|
217 | |||
215 | session = None |
|
218 | session = None | |
216 |
|
219 | |||
217 | def clean_user_id(self): |
|
220 | def clean_user_id(self): | |
218 | user_id = self.cleaned_data['user_id'] |
|
221 | user_id = self.cleaned_data['user_id'] | |
219 | if user_id: |
|
222 | if user_id: | |
220 | users = User.objects.filter(user_id=user_id) |
|
223 | users = User.objects.filter(user_id=user_id) | |
221 | if len(users) == 0: |
|
224 | if len(users) == 0: | |
222 | raise forms.ValidationError(_('No such user found')) |
|
225 | raise forms.ValidationError(_('No such user found')) | |
223 |
|
226 | |||
224 | return user_id |
|
227 | return user_id | |
225 |
|
228 | |||
226 | def _validate_login_speed(self): |
|
229 | def _validate_login_speed(self): | |
227 | can_post = True |
|
230 | can_post = True | |
228 |
|
231 | |||
229 | if LAST_LOGIN_TIME in self.session: |
|
232 | if LAST_LOGIN_TIME in self.session: | |
230 | now = time.time() |
|
233 | now = time.time() | |
231 | last_login_time = self.session[LAST_LOGIN_TIME] |
|
234 | last_login_time = self.session[LAST_LOGIN_TIME] | |
232 |
|
235 | |||
233 | current_delay = int(now - last_login_time) |
|
236 | current_delay = int(now - last_login_time) | |
234 |
|
237 | |||
235 | if current_delay < board_settings.LOGIN_TIMEOUT: |
|
238 | if current_delay < board_settings.LOGIN_TIMEOUT: | |
236 | error_message = _('Wait %s minutes after last login') % str( |
|
239 | error_message = _('Wait %s minutes after last login') % str( | |
237 | (board_settings.LOGIN_TIMEOUT - current_delay) / 60) |
|
240 | (board_settings.LOGIN_TIMEOUT - current_delay) / 60) | |
238 | self._errors['user_id'] = self.error_class([error_message]) |
|
241 | self._errors['user_id'] = self.error_class([error_message]) | |
239 |
|
242 | |||
240 | can_post = False |
|
243 | can_post = False | |
241 |
|
244 | |||
242 | if can_post: |
|
245 | if can_post: | |
243 | self.session[LAST_LOGIN_TIME] = time.time() |
|
246 | self.session[LAST_LOGIN_TIME] = time.time() | |
244 |
|
247 | |||
245 | def clean(self): |
|
248 | def clean(self): | |
246 | if not self.session: |
|
249 | if not self.session: | |
247 | raise forms.ValidationError('Humans have sessions') |
|
250 | raise forms.ValidationError('Humans have sessions') | |
248 |
|
251 | |||
249 | self._validate_login_speed() |
|
252 | self._validate_login_speed() | |
250 |
|
253 | |||
251 | cleaned_data = super(LoginForm, self).clean() |
|
254 | cleaned_data = super(LoginForm, self).clean() | |
252 |
|
255 | |||
253 | return cleaned_data |
|
256 | return cleaned_data |
@@ -1,359 +1,357 b'' | |||||
1 | html { |
|
1 | html { | |
2 | background: #555; |
|
2 | background: #555; | |
3 | color: #ffffff; |
|
3 | color: #ffffff; | |
4 | } |
|
4 | } | |
5 |
|
5 | |||
6 | #admin_panel { |
|
6 | #admin_panel { | |
7 | background: #FF0000; |
|
7 | background: #FF0000; | |
8 | color: #00FF00 |
|
8 | color: #00FF00 | |
9 | } |
|
9 | } | |
10 |
|
10 | |||
11 | .input_field { |
|
11 | .input_field { | |
12 |
|
12 | |||
13 | } |
|
13 | } | |
14 |
|
14 | |||
15 | .input_field_name { |
|
15 | .input_field_name { | |
16 |
|
16 | |||
17 | } |
|
17 | } | |
18 |
|
18 | |||
19 | .input_field_error { |
|
19 | .input_field_error { | |
20 | color: #FF0000; |
|
20 | color: #FF0000; | |
21 | } |
|
21 | } | |
22 |
|
22 | |||
23 |
|
||||
24 | .title { |
|
23 | .title { | |
25 | font-weight: bold; |
|
24 | font-weight: bold; | |
26 | color: #ffcc00; |
|
25 | color: #ffcc00; | |
27 | font-size: 2ex; |
|
26 | font-size: 2ex; | |
28 | } |
|
27 | } | |
29 |
|
28 | |||
30 | .link, a { |
|
29 | .link, a { | |
31 | color: #afdcec; |
|
30 | color: #afdcec; | |
32 | } |
|
31 | } | |
33 |
|
32 | |||
34 | .block { |
|
33 | .block { | |
35 | display: inline-block; |
|
34 | display: inline-block; | |
36 | vertical-align: top; |
|
35 | vertical-align: top; | |
37 | } |
|
36 | } | |
38 |
|
37 | |||
39 | .tag { |
|
38 | .tag { | |
40 | color: #b4cfec; |
|
39 | color: #b4cfec; | |
41 | } |
|
40 | } | |
42 |
|
41 | |||
43 | .post_id { |
|
42 | .post_id { | |
44 | color: #fff380; |
|
43 | color: #fff380; | |
45 | } |
|
44 | } | |
46 |
|
45 | |||
47 | .post, .dead_post, #posts-table { |
|
46 | .post, .dead_post, #posts-table { | |
48 | background: #333; |
|
47 | background: #333; | |
49 | margin: 5px; |
|
48 | margin: 5px; | |
50 | padding: 10px; |
|
49 | padding: 10px; | |
51 | border: solid 1px #888; |
|
50 | border: solid 1px #888; | |
52 | clear: left; |
|
51 | clear: left; | |
53 | word-wrap: break-word; |
|
52 | word-wrap: break-word; | |
54 | } |
|
53 | } | |
55 |
|
54 | |||
56 | .metadata { |
|
55 | .metadata { | |
57 | padding-top: 5px; |
|
56 | padding-top: 5px; | |
58 | margin-top: 10px; |
|
57 | margin-top: 10px; | |
59 | border-top: solid 1px #666; |
|
58 | border-top: solid 1px #666; | |
60 | font-size: 0.9em; |
|
59 | font-size: 0.9em; | |
61 | color: #ddd; |
|
60 | color: #ddd; | |
62 | } |
|
61 | } | |
63 |
|
62 | |||
64 | .navigation_panel, .tag_info { |
|
63 | .navigation_panel, .tag_info { | |
65 | background: #444; |
|
64 | background: #444; | |
66 | margin: 5px; |
|
65 | margin: 5px; | |
67 | padding: 10px; |
|
66 | padding: 10px; | |
68 | border: solid 1px #888; |
|
67 | border: solid 1px #888; | |
69 | color: #eee; |
|
68 | color: #eee; | |
70 | } |
|
69 | } | |
71 |
|
70 | |||
72 | .navigation_panel .link { |
|
71 | .navigation_panel .link { | |
73 | border-right: 1px solid #fff; |
|
72 | border-right: 1px solid #fff; | |
74 | font-weight: bold; |
|
73 | font-weight: bold; | |
75 | margin-right: 1ex; |
|
74 | margin-right: 1ex; | |
76 | padding-right: 1ex; |
|
75 | padding-right: 1ex; | |
77 | } |
|
76 | } | |
78 | .navigation_panel .link:last-child { |
|
77 | .navigation_panel .link:last-child { | |
79 | border-left: 1px solid #fff; |
|
78 | border-left: 1px solid #fff; | |
80 | border-right: none; |
|
79 | border-right: none; | |
81 | float: right; |
|
80 | float: right; | |
82 | margin-left: 1ex; |
|
81 | margin-left: 1ex; | |
83 | margin-right: 0; |
|
82 | margin-right: 0; | |
84 | padding-left: 1ex; |
|
83 | padding-left: 1ex; | |
85 | padding-right: 0; |
|
84 | padding-right: 0; | |
86 | } |
|
85 | } | |
87 |
|
86 | |||
88 | .navigation_panel::after, .post::after { |
|
87 | .navigation_panel::after, .post::after { | |
89 | clear: both; |
|
88 | clear: both; | |
90 | content: "."; |
|
89 | content: "."; | |
91 | display: block; |
|
90 | display: block; | |
92 | height: 0; |
|
91 | height: 0; | |
93 | line-height: 0; |
|
92 | line-height: 0; | |
94 | visibility: hidden; |
|
93 | visibility: hidden; | |
95 | } |
|
94 | } | |
96 |
|
95 | |||
97 | p { |
|
96 | p { | |
98 | margin-top: .5em; |
|
97 | margin-top: .5em; | |
99 | margin-bottom: .5em; |
|
98 | margin-bottom: .5em; | |
100 | } |
|
99 | } | |
101 |
|
100 | |||
102 | .post-form-w { |
|
101 | .post-form-w { | |
103 | display: table; |
|
102 | display: table; | |
104 | background: #333344; |
|
103 | background: #333344; | |
105 | border: solid 1px #888; |
|
104 | border: solid 1px #888; | |
106 | color: #fff; |
|
105 | color: #fff; | |
107 | padding: 10px; |
|
106 | padding: 10px; | |
108 | margin: 5px; |
|
107 | margin: 5px; | |
109 | } |
|
108 | } | |
110 |
|
109 | |||
111 | .form-row { |
|
110 | .form-row { | |
112 | display: table-row; |
|
111 | display: table-row; | |
113 | } |
|
112 | } | |
114 |
|
113 | |||
115 | .form-label, .form-input, .form-errors { |
|
114 | .form-label, .form-input, .form-errors { | |
116 | display: table-cell; |
|
115 | display: table-cell; | |
117 | } |
|
116 | } | |
118 |
|
117 | |||
119 | .form-label { |
|
118 | .form-label { | |
120 | padding: .25em 1ex .25em 0; |
|
119 | padding: .25em 1ex .25em 0; | |
121 | vertical-align: top; |
|
120 | vertical-align: top; | |
122 | } |
|
121 | } | |
123 |
|
122 | |||
124 | .form-input { |
|
123 | .form-input { | |
125 | padding: .25em 0; |
|
124 | padding: .25em 0; | |
126 | } |
|
125 | } | |
127 |
|
126 | |||
128 | .form-errors { |
|
127 | .form-errors { | |
129 | padding-left: 1ex; |
|
128 | font-weight: bolder; | |
130 | font-weight: bold; |
|
|||
131 | vertical-align: middle; |
|
129 | vertical-align: middle; | |
132 | } |
|
130 | } | |
133 |
|
131 | |||
134 | .post-form input, .post-form textarea { |
|
132 | .post-form input, .post-form textarea { | |
135 | background: #333; |
|
133 | background: #333; | |
136 | color: #fff; |
|
134 | color: #fff; | |
137 | border: solid 1px; |
|
135 | border: solid 1px; | |
138 | padding: 0; |
|
136 | padding: 0; | |
139 | width: 100%; |
|
137 | width: 100%; | |
140 | font: medium sans; |
|
138 | font: medium sans; | |
141 | } |
|
139 | } | |
142 |
|
140 | |||
143 | .form-submit { |
|
141 | .form-submit { | |
144 | border-bottom: 2px solid #ddd; |
|
142 | display: table; | |
145 |
margin-bottom: |
|
143 | margin-bottom: 1ex; | |
146 | padding-bottom: .5em; |
|
|||
147 | } |
|
144 | } | |
148 |
|
145 | |||
149 | .form-title { |
|
146 | .form-title { | |
150 | font-weight: bold; |
|
147 | font-weight: bold; | |
151 | font-size: 2.5ex; |
|
148 | font-size: 2.5ex; | |
152 | text-decoration: underline; |
|
149 | text-decoration: underline; | |
153 | } |
|
150 | } | |
154 |
|
151 | |||
155 | input[type="submit"] { |
|
152 | input[type="submit"] { | |
156 | background: #222; |
|
153 | background: #222; | |
157 |
border: solid |
|
154 | border: solid 2px #fff; | |
158 | color: #fff; |
|
155 | color: #fff; | |
|
156 | padding: 0.5ex; | |||
|
157 | } | |||
|
158 | ||||
|
159 | input[type="submit"]:hover { | |||
|
160 | background: #060; | |||
159 | } |
|
161 | } | |
160 |
|
162 | |||
161 | blockquote { |
|
163 | blockquote { | |
162 | border-left: solid 2px; |
|
164 | border-left: solid 2px; | |
163 | padding-left: 5px; |
|
165 | padding-left: 5px; | |
164 | color: #B1FB17; |
|
166 | color: #B1FB17; | |
165 | margin: 0; |
|
167 | margin: 0; | |
166 | } |
|
168 | } | |
167 |
|
169 | |||
168 | .post > .image { |
|
170 | .post > .image { | |
169 | float: left; |
|
171 | float: left; | |
170 | margin: 0 1ex .5ex 0; |
|
172 | margin: 0 1ex .5ex 0; | |
171 | min-width: 1px; |
|
173 | min-width: 1px; | |
172 | text-align: center; |
|
174 | text-align: center; | |
173 | display: table-row; |
|
175 | display: table-row; | |
174 |
|
176 | |||
175 | height: 150px; |
|
177 | height: 150px; | |
176 | } |
|
178 | } | |
177 |
|
179 | |||
178 | .post > .metadata { |
|
180 | .post > .metadata { | |
179 | clear: left; |
|
181 | clear: left; | |
180 | } |
|
182 | } | |
181 |
|
183 | |||
182 | .get { |
|
184 | .get { | |
183 | font-weight: bold; |
|
185 | font-weight: bold; | |
184 | color: #d55; |
|
186 | color: #d55; | |
185 | } |
|
187 | } | |
186 |
|
188 | |||
187 | * { |
|
189 | * { | |
188 | text-decoration: none; |
|
190 | text-decoration: none; | |
189 | } |
|
191 | } | |
190 |
|
192 | |||
191 | .dead_post { |
|
193 | .dead_post { | |
192 | background-color: #442222; |
|
194 | background-color: #442222; | |
193 | } |
|
195 | } | |
194 |
|
196 | |||
195 | .mark_btn { |
|
197 | .mark_btn { | |
196 | padding: 2px 4px; |
|
198 | padding: 2px 4px; | |
197 | border: 1px solid; |
|
199 | border: 1px solid; | |
198 | } |
|
200 | } | |
199 |
|
201 | |||
200 | .mark_btn:hover { |
|
202 | .mark_btn:hover { | |
201 | background: #555; |
|
203 | background: #555; | |
202 | } |
|
204 | } | |
203 |
|
205 | |||
204 | .quote { |
|
206 | .quote { | |
205 | color: #92cf38; |
|
207 | color: #92cf38; | |
206 | font-style: italic; |
|
208 | font-style: italic; | |
207 | } |
|
209 | } | |
208 |
|
210 | |||
209 | .spoiler { |
|
211 | .spoiler { | |
210 | background: white; |
|
212 | background: white; | |
211 | color: white; |
|
213 | color: white; | |
212 | } |
|
214 | } | |
213 |
|
215 | |||
214 | .spoiler:hover { |
|
216 | .spoiler:hover { | |
215 | color: black; |
|
217 | color: black; | |
216 | } |
|
218 | } | |
217 |
|
219 | |||
218 | .comment { |
|
220 | .comment { | |
219 | color: #eb2; |
|
221 | color: #eb2; | |
220 | font-style: italic; |
|
222 | font-style: italic; | |
221 | } |
|
223 | } | |
222 |
|
224 | |||
223 | a:hover { |
|
225 | a:hover { | |
224 | text-decoration: underline; |
|
226 | text-decoration: underline; | |
225 | } |
|
227 | } | |
226 |
|
228 | |||
227 | .last-replies { |
|
229 | .last-replies { | |
228 | margin-left: 3ex; |
|
230 | margin-left: 3ex; | |
229 | } |
|
231 | } | |
230 |
|
232 | |||
231 | .thread { |
|
233 | .thread { | |
232 | margin-bottom: 3ex; |
|
234 | margin-bottom: 3ex; | |
233 | } |
|
235 | } | |
234 |
|
236 | |||
235 | .post:target { |
|
237 | .post:target { | |
236 | border: solid 2px white; |
|
238 | border: solid 2px white; | |
237 | } |
|
239 | } | |
238 |
|
240 | |||
239 | pre{ |
|
241 | pre{ | |
240 | white-space:pre-wrap |
|
242 | white-space:pre-wrap | |
241 | } |
|
243 | } | |
242 |
|
244 | |||
243 | li { |
|
245 | li { | |
244 | list-style-position: inside; |
|
246 | list-style-position: inside; | |
245 | } |
|
247 | } | |
246 |
|
248 | |||
247 | .fancybox-skin { |
|
249 | .fancybox-skin { | |
248 | position: relative; |
|
250 | position: relative; | |
249 | background-color: #fff; |
|
251 | background-color: #fff; | |
250 | color: #ddd; |
|
252 | color: #ddd; | |
251 | text-shadow: none; |
|
253 | text-shadow: none; | |
252 | } |
|
254 | } | |
253 |
|
255 | |||
254 | .fancybox-image { |
|
256 | .fancybox-image { | |
255 | border: 1px solid black; |
|
257 | border: 1px solid black; | |
256 | } |
|
258 | } | |
257 |
|
259 | |||
258 | .image-mode-tab { |
|
260 | .image-mode-tab { | |
259 | background: #444; |
|
261 | background: #444; | |
260 | color: #eee; |
|
262 | color: #eee; | |
261 | display: table; |
|
263 | display: table; | |
262 | margin: 5px; |
|
264 | margin: 5px; | |
263 | padding: 5px; |
|
265 | padding: 5px; | |
264 | border: 1px solid #888; |
|
266 | border: 1px solid #888; | |
265 | } |
|
267 | } | |
266 |
|
268 | |||
267 | .image-mode-tab > label { |
|
269 | .image-mode-tab > label { | |
268 | margin: 0 1ex; |
|
270 | margin: 0 1ex; | |
269 | } |
|
271 | } | |
270 |
|
272 | |||
271 | .image-mode-tab > label > input { |
|
273 | .image-mode-tab > label > input { | |
272 | margin-right: .5ex; |
|
274 | margin-right: .5ex; | |
273 | } |
|
275 | } | |
274 |
|
276 | |||
275 | #posts-table { |
|
277 | #posts-table { | |
276 | margin: 5px; |
|
278 | margin: 5px; | |
277 | } |
|
279 | } | |
278 |
|
280 | |||
279 | .tag_info { |
|
281 | .tag_info { | |
280 | display: table; |
|
282 | display: table; | |
281 | } |
|
283 | } | |
282 |
|
284 | |||
283 | .tag_info > h2 { |
|
285 | .tag_info > h2 { | |
284 | margin: 0; |
|
286 | margin: 0; | |
285 | } |
|
287 | } | |
286 |
|
288 | |||
287 | .post-info { |
|
289 | .post-info { | |
288 | color: #ddd; |
|
290 | color: #ddd; | |
289 | } |
|
291 | } | |
290 |
|
292 | |||
291 | .moderator_info { |
|
293 | .moderator_info { | |
292 | color: #e99d41; |
|
294 | color: #e99d41; | |
293 | border: dashed 1px; |
|
295 | border: dashed 1px; | |
294 | padding: 3px; |
|
296 | padding: 3px; | |
295 | } |
|
297 | } | |
296 |
|
298 | |||
297 | .refmap { |
|
299 | .refmap { | |
298 | font-size: 0.9em; |
|
300 | font-size: 0.9em; | |
299 | color: #ccc; |
|
301 | color: #ccc; | |
300 | margin-top: 1em; |
|
302 | margin-top: 1em; | |
301 | } |
|
303 | } | |
302 |
|
304 | |||
303 | input[type="submit"]:hover { |
|
|||
304 | background: #555; |
|
|||
305 | } |
|
|||
306 |
|
||||
307 | .fav { |
|
305 | .fav { | |
308 | color: yellow; |
|
306 | color: yellow; | |
309 | } |
|
307 | } | |
310 |
|
308 | |||
311 | .not_fav { |
|
309 | .not_fav { | |
312 | color: #ccc; |
|
310 | color: #ccc; | |
313 | } |
|
311 | } | |
314 |
|
312 | |||
315 | .role { |
|
313 | .role { | |
316 | text-decoration: underline; |
|
314 | text-decoration: underline; | |
317 | } |
|
315 | } | |
318 |
|
316 | |||
319 | .form-email { |
|
317 | .form-email { | |
320 | display: none; |
|
318 | display: none; | |
321 | } |
|
319 | } | |
322 |
|
320 | |||
323 | .footer { |
|
321 | .footer { | |
324 | margin: 5px; |
|
322 | margin: 5px; | |
325 | } |
|
323 | } | |
326 |
|
324 | |||
327 | .bar-value { |
|
325 | .bar-value { | |
328 | background: rgba(50, 55, 164, 0.45); |
|
326 | background: rgba(50, 55, 164, 0.45); | |
329 | font-size: 0.9em; |
|
327 | font-size: 0.9em; | |
330 | height: 1.5em; |
|
328 | height: 1.5em; | |
331 | } |
|
329 | } | |
332 |
|
330 | |||
333 | .bar-bg { |
|
331 | .bar-bg { | |
334 | position: relative; |
|
332 | position: relative; | |
335 | border: solid 1px #888; |
|
333 | border: solid 1px #888; | |
336 | margin: 5px; |
|
334 | margin: 5px; | |
337 | overflow: hidden; |
|
335 | overflow: hidden; | |
338 | } |
|
336 | } | |
339 |
|
337 | |||
340 | .bar-text { |
|
338 | .bar-text { | |
341 | padding: 2px; |
|
339 | padding: 2px; | |
342 | position: absolute; |
|
340 | position: absolute; | |
343 | left: 0; |
|
341 | left: 0; | |
344 | top: 0; |
|
342 | top: 0; | |
345 | } |
|
343 | } | |
346 |
|
344 | |||
347 | .page_link { |
|
345 | .page_link { | |
348 | display: table; |
|
346 | display: table; | |
349 | background: #444; |
|
347 | background: #444; | |
350 | margin: 5px; |
|
348 | margin: 5px; | |
351 | border: solid 1px #888; |
|
349 | border: solid 1px #888; | |
352 | padding: 5px; |
|
350 | padding: 5px; | |
353 | font-weight: bolder; |
|
351 | font-weight: bolder; | |
354 | color: #eee; |
|
352 | color: #eee; | |
355 | } |
|
353 | } | |
356 |
|
354 | |||
357 | .skipped_replies { |
|
355 | .skipped_replies { | |
358 | margin: 5px; |
|
356 | margin: 5px; | |
359 | } |
|
357 | } |
@@ -1,241 +1,242 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 board %} |
|
5 | {% load board %} | |
6 |
|
6 | |||
7 | {% block head %} |
|
7 | {% block head %} | |
8 | {% if tag %} |
|
8 | {% if tag %} | |
9 | <title>Neboard - {{ tag.name }}</title> |
|
9 | <title>Neboard - {{ tag.name }}</title> | |
10 | {% else %} |
|
10 | {% else %} | |
11 | <title>Neboard</title> |
|
11 | <title>Neboard</title> | |
12 | {% endif %} |
|
12 | {% endif %} | |
13 |
|
13 | |||
14 | {% if prev_page %} |
|
14 | {% if prev_page %} | |
15 | <link rel="next" href=" |
|
15 | <link rel="next" href=" | |
16 | {% if tag %} |
|
16 | {% if tag %} | |
17 | {% url "tag" tag_name=tag page=prev_page %} |
|
17 | {% url "tag" tag_name=tag page=prev_page %} | |
18 | {% else %} |
|
18 | {% else %} | |
19 | {% url "index" page=prev_page %} |
|
19 | {% url "index" page=prev_page %} | |
20 | {% endif %} |
|
20 | {% endif %} | |
21 | " /> |
|
21 | " /> | |
22 | {% endif %} |
|
22 | {% endif %} | |
23 | {% if next_page %} |
|
23 | {% if next_page %} | |
24 | <link rel="next" href=" |
|
24 | <link rel="next" href=" | |
25 | {% if tag %} |
|
25 | {% if tag %} | |
26 | {% url "tag" tag_name=tag page=next_page %} |
|
26 | {% url "tag" tag_name=tag page=next_page %} | |
27 | {% else %} |
|
27 | {% else %} | |
28 | {% url "index" page=next_page %} |
|
28 | {% url "index" page=next_page %} | |
29 | {% endif %} |
|
29 | {% endif %} | |
30 | " /> |
|
30 | " /> | |
31 | {% endif %} |
|
31 | {% endif %} | |
32 |
|
32 | |||
33 | {% endblock %} |
|
33 | {% endblock %} | |
34 |
|
34 | |||
35 | {% block content %} |
|
35 | {% block content %} | |
36 |
|
36 | |||
37 | {% get_current_language as LANGUAGE_CODE %} |
|
37 | {% get_current_language as LANGUAGE_CODE %} | |
38 |
|
38 | |||
39 | {% if tag %} |
|
39 | {% if tag %} | |
40 | <div class="tag_info"> |
|
40 | <div class="tag_info"> | |
41 | <h2> |
|
41 | <h2> | |
42 | {% if tag in user.fav_tags.all %} |
|
42 | {% if tag in user.fav_tags.all %} | |
43 | <a href="{% url 'tag_unsubscribe' tag.name %}?next={{ request.path }}" |
|
43 | <a href="{% url 'tag_unsubscribe' tag.name %}?next={{ request.path }}" | |
44 | class="fav">β </a> |
|
44 | class="fav">β </a> | |
45 | {% else %} |
|
45 | {% else %} | |
46 | <a href="{% url 'tag_subscribe' tag.name %}?next={{ request.path }}" |
|
46 | <a href="{% url 'tag_subscribe' tag.name %}?next={{ request.path }}" | |
47 | class="not_fav">β </a> |
|
47 | class="not_fav">β </a> | |
48 | {% endif %} |
|
48 | {% endif %} | |
49 | #{{ tag.name }} |
|
49 | #{{ tag.name }} | |
50 | </h2> |
|
50 | </h2> | |
51 | </div> |
|
51 | </div> | |
52 | {% endif %} |
|
52 | {% endif %} | |
53 |
|
53 | |||
54 | {% if threads %} |
|
54 | {% if threads %} | |
55 | {% if prev_page %} |
|
55 | {% if prev_page %} | |
56 | <div class="page_link"> |
|
56 | <div class="page_link"> | |
57 | <a href=" |
|
57 | <a href=" | |
58 | {% if tag %} |
|
58 | {% if tag %} | |
59 | {% url "tag" tag_name=tag page=prev_page %} |
|
59 | {% url "tag" tag_name=tag page=prev_page %} | |
60 | {% else %} |
|
60 | {% else %} | |
61 | {% url "index" page=prev_page %} |
|
61 | {% url "index" page=prev_page %} | |
62 | {% endif %} |
|
62 | {% endif %} | |
63 | ">{% trans "Previous page" %}</a> |
|
63 | ">{% trans "Previous page" %}</a> | |
64 | </div> |
|
64 | </div> | |
65 | {% endif %} |
|
65 | {% endif %} | |
66 |
|
66 | |||
67 | {% for thread in threads %} |
|
67 | {% for thread in threads %} | |
68 | {% cache 600 thread_short thread.id thread.thread.last_edit_time moderator LANGUAGE_CODE %} |
|
68 | {% cache 600 thread_short thread.id thread.thread.last_edit_time moderator LANGUAGE_CODE %} | |
69 | <div class="thread"> |
|
69 | <div class="thread"> | |
70 | {% if thread.bumpable %} |
|
70 | {% if thread.bumpable %} | |
71 | <div class="post" id="{{ thread.op.id }}"> |
|
71 | <div class="post" id="{{ thread.op.id }}"> | |
72 | {% else %} |
|
72 | {% else %} | |
73 | <div class="post dead_post" id="{{ thread.op.id }}"> |
|
73 | <div class="post dead_post" id="{{ thread.op.id }}"> | |
74 | {% endif %} |
|
74 | {% endif %} | |
75 | {% if thread.op.image %} |
|
75 | {% if thread.op.image %} | |
76 | <div class="image"> |
|
76 | <div class="image"> | |
77 | <a class="thumb" |
|
77 | <a class="thumb" | |
78 | href="{{ thread.op.image.url }}"><img |
|
78 | href="{{ thread.op.image.url }}"><img | |
79 | src="{{ thread.op.image.url_200x150 }}" |
|
79 | src="{{ thread.op.image.url_200x150 }}" | |
80 | alt="{{ thread.op.id }}" |
|
80 | alt="{{ thread.op.id }}" | |
81 | data-width="{{ thread.op.image_width }}" |
|
81 | data-width="{{ thread.op.image_width }}" | |
82 | data-height="{{ thread.op.image_height }}"/> |
|
82 | data-height="{{ thread.op.image_height }}"/> | |
83 | </a> |
|
83 | </a> | |
84 | </div> |
|
84 | </div> | |
85 | {% endif %} |
|
85 | {% endif %} | |
86 | <div class="message"> |
|
86 | <div class="message"> | |
87 | <div class="post-info"> |
|
87 | <div class="post-info"> | |
88 | <span class="title">{{ thread.op.title }}</span> |
|
88 | <span class="title">{{ thread.op.title }}</span> | |
89 | <a class="post_id" href="{% url 'thread' thread.op.id %}" |
|
89 | <a class="post_id" href="{% url 'thread' thread.op.id %}" | |
90 | >({{ thread.op.id }})</a> |
|
90 | >({{ thread.op.id }})</a> | |
91 | [{{ thread.op.pub_time }}] |
|
91 | [{{ thread.op.pub_time }}] | |
92 | [<a class="link" href=" |
|
92 | [<a class="link" href=" | |
93 | {% url 'thread' thread.op.id %}#form" |
|
93 | {% url 'thread' thread.op.id %}#form" | |
94 | >{% trans "Reply" %}</a>] |
|
94 | >{% trans "Reply" %}</a>] | |
95 |
|
95 | |||
96 | {% if moderator %} |
|
96 | {% if moderator %} | |
97 | <span class="moderator_info"> |
|
97 | <span class="moderator_info"> | |
98 | [<a href=" |
|
98 | [<a href=" | |
99 | {% url 'delete' post_id=thread.op.id %}?next={{ request.path }}" |
|
99 | {% url 'delete' post_id=thread.op.id %}?next={{ request.path }}" | |
100 | >{% trans 'Delete' %}</a>] |
|
100 | >{% trans 'Delete' %}</a>] | |
101 | ({{ thread.thread.poster_ip }}) |
|
101 | ({{ thread.thread.poster_ip }}) | |
102 | [<a href=" |
|
102 | [<a href=" | |
103 | {% url 'ban' post_id=thread.op.id %}?next={{ request.path }}" |
|
103 | {% url 'ban' post_id=thread.op.id %}?next={{ request.path }}" | |
104 | >{% trans 'Ban IP' %}</a>] |
|
104 | >{% trans 'Ban IP' %}</a>] | |
105 | </span> |
|
105 | </span> | |
106 | {% endif %} |
|
106 | {% endif %} | |
107 | </div> |
|
107 | </div> | |
108 | {% autoescape off %} |
|
108 | {% autoescape off %} | |
109 | {{ thread.op.text.rendered|truncatewords_html:50 }} |
|
109 | {{ thread.op.text.rendered|truncatewords_html:50 }} | |
110 | {% endautoescape %} |
|
110 | {% endautoescape %} | |
111 | {% if thread.op.is_referenced %} |
|
111 | {% if thread.op.is_referenced %} | |
112 | <div class="refmap"> |
|
112 | <div class="refmap"> | |
113 | {% trans "Replies" %}: |
|
113 | {% trans "Replies" %}: | |
114 | {% for ref_post in thread.op.get_sorted_referenced_posts %} |
|
114 | {% for ref_post in thread.op.get_sorted_referenced_posts %} | |
115 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a |
|
115 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a | |
116 | >{% if not forloop.last %},{% endif %} |
|
116 | >{% if not forloop.last %},{% endif %} | |
117 | {% endfor %} |
|
117 | {% endfor %} | |
118 | </div> |
|
118 | </div> | |
119 | {% endif %} |
|
119 | {% endif %} | |
120 | </div> |
|
120 | </div> | |
121 | <div class="metadata"> |
|
121 | <div class="metadata"> | |
122 | {{ thread.thread.get_images_count }} {% trans 'images' %}. |
|
122 | {{ thread.thread.get_images_count }} {% trans 'images' %}. | |
123 | {% if thread.thread.tags %} |
|
123 | {% if thread.thread.tags %} | |
124 | <span class="tags"> |
|
124 | <span class="tags"> | |
125 | {% for tag in thread.thread.get_tags %} |
|
125 | {% for tag in thread.thread.get_tags %} | |
126 | <a class="tag" href=" |
|
126 | <a class="tag" href=" | |
127 | {% url 'tag' tag_name=tag.name %}"> |
|
127 | {% url 'tag' tag_name=tag.name %}"> | |
128 | #{{ tag.name }}</a |
|
128 | #{{ tag.name }}</a | |
129 | >{% if not forloop.last %},{% endif %} |
|
129 | >{% if not forloop.last %},{% endif %} | |
130 | {% endfor %} |
|
130 | {% endfor %} | |
131 | </span> |
|
131 | </span> | |
132 | {% endif %} |
|
132 | {% endif %} | |
133 | </div> |
|
133 | </div> | |
134 | </div> |
|
134 | </div> | |
135 | {% if thread.last_replies.exists %} |
|
135 | {% if thread.last_replies.exists %} | |
136 | {% if thread.skipped_replies %} |
|
136 | {% if thread.skipped_replies %} | |
137 | <div class="skipped_replies"> |
|
137 | <div class="skipped_replies"> | |
138 | <a href="{% url 'thread' thread.op.id %}"> |
|
138 | <a href="{% url 'thread' thread.op.id %}"> | |
139 | {% blocktrans with count=thread.skipped_replies %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %} |
|
139 | {% blocktrans with count=thread.skipped_replies %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %} | |
140 | </a> |
|
140 | </a> | |
141 | </div> |
|
141 | </div> | |
142 | {% endif %} |
|
142 | {% endif %} | |
143 | <div class="last-replies"> |
|
143 | <div class="last-replies"> | |
144 | {% for post in thread.last_replies %} |
|
144 | {% for post in thread.last_replies %} | |
145 | {% if thread.bumpable %} |
|
145 | {% if thread.bumpable %} | |
146 | <div class="post" id="{{ post.id }}"> |
|
146 | <div class="post" id="{{ post.id }}"> | |
147 | {% else %} |
|
147 | {% else %} | |
148 | <div class="post dead_post" id="{{ post.id }}"> |
|
148 | <div class="post dead_post" id="{{ post.id }}"> | |
149 | {% endif %} |
|
149 | {% endif %} | |
150 | {% if post.image %} |
|
150 | {% if post.image %} | |
151 | <div class="image"> |
|
151 | <div class="image"> | |
152 | <a class="thumb" |
|
152 | <a class="thumb" | |
153 | href="{{ post.image.url }}"><img |
|
153 | href="{{ post.image.url }}"><img | |
154 | src=" {{ post.image.url_200x150 }}" |
|
154 | src=" {{ post.image.url_200x150 }}" | |
155 | alt="{{ post.id }}" |
|
155 | alt="{{ post.id }}" | |
156 | data-width="{{ post.image_width }}" |
|
156 | data-width="{{ post.image_width }}" | |
157 | data-height="{{ post.image_height }}"/> |
|
157 | data-height="{{ post.image_height }}"/> | |
158 | </a> |
|
158 | </a> | |
159 | </div> |
|
159 | </div> | |
160 | {% endif %} |
|
160 | {% endif %} | |
161 | <div class="message"> |
|
161 | <div class="message"> | |
162 | <div class="post-info"> |
|
162 | <div class="post-info"> | |
163 | <span class="title">{{ post.title }}</span> |
|
163 | <span class="title">{{ post.title }}</span> | |
164 | <a class="post_id" href=" |
|
164 | <a class="post_id" href=" | |
165 | {% url 'thread' thread.op.id %}#{{ post.id }}"> |
|
165 | {% url 'thread' thread.op.id %}#{{ post.id }}"> | |
166 | ({{ post.id }})</a> |
|
166 | ({{ post.id }})</a> | |
167 | [{{ post.pub_time }}] |
|
167 | [{{ post.pub_time }}] | |
168 | </div> |
|
168 | </div> | |
169 | {% autoescape off %} |
|
169 | {% autoescape off %} | |
170 | {{ post.text.rendered|truncatewords_html:50 }} |
|
170 | {{ post.text.rendered|truncatewords_html:50 }} | |
171 | {% endautoescape %} |
|
171 | {% endautoescape %} | |
172 | </div> |
|
172 | </div> | |
173 | {% if post.is_referenced %} |
|
173 | {% if post.is_referenced %} | |
174 | <div class="refmap"> |
|
174 | <div class="refmap"> | |
175 | {% trans "Replies" %}: |
|
175 | {% trans "Replies" %}: | |
176 | {% for ref_post in post.get_sorted_referenced_posts %} |
|
176 | {% for ref_post in post.get_sorted_referenced_posts %} | |
177 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a |
|
177 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a | |
178 | >{% if not forloop.last %},{% endif %} |
|
178 | >{% if not forloop.last %},{% endif %} | |
179 | {% endfor %} |
|
179 | {% endfor %} | |
180 | </div> |
|
180 | </div> | |
181 | {% endif %} |
|
181 | {% endif %} | |
182 | </div> |
|
182 | </div> | |
183 | {% endfor %} |
|
183 | {% endfor %} | |
184 | </div> |
|
184 | </div> | |
185 | {% endif %} |
|
185 | {% endif %} | |
186 | </div> |
|
186 | </div> | |
187 | {% endcache %} |
|
187 | {% endcache %} | |
188 | {% endfor %} |
|
188 | {% endfor %} | |
189 |
|
189 | |||
190 | {% if next_page %} |
|
190 | {% if next_page %} | |
191 | <div class="page_link"> |
|
191 | <div class="page_link"> | |
192 | <a href=" |
|
192 | <a href=" | |
193 | {% if tag %} |
|
193 | {% if tag %} | |
194 | {% url "tag" tag_name=tag page=next_page %} |
|
194 | {% url "tag" tag_name=tag page=next_page %} | |
195 | {% else %} |
|
195 | {% else %} | |
196 | {% url "index" page=next_page %} |
|
196 | {% url "index" page=next_page %} | |
197 | {% endif %} |
|
197 | {% endif %} | |
198 | ">{% trans "Next page" %}</a> |
|
198 | ">{% trans "Next page" %}</a> | |
199 | </div> |
|
199 | </div> | |
200 | {% endif %} |
|
200 | {% endif %} | |
201 | {% else %} |
|
201 | {% else %} | |
202 | <div class="post"> |
|
202 | <div class="post"> | |
203 | {% trans 'No threads exist. Create the first one!' %}</div> |
|
203 | {% trans 'No threads exist. Create the first one!' %}</div> | |
204 | {% endif %} |
|
204 | {% endif %} | |
205 |
|
205 | |||
206 | <div class="post-form-w"> |
|
206 | <div class="post-form-w"> | |
207 | <div class="post-form"> |
|
207 | <div class="post-form"> | |
208 | <div class="form-title">{% trans "Create new thread" %}</div> |
|
208 | <div class="form-title">{% trans "Create new thread" %}</div> | |
209 | <form enctype="multipart/form-data" method="post">{% csrf_token %} |
|
209 | <form enctype="multipart/form-data" method="post">{% csrf_token %} | |
210 |
{{ form.as_ |
|
210 | {{ form.as_div }} | |
211 | <div class="form-submit"> |
|
211 | <div class="form-submit"> | |
212 |
<input type="submit" value="{% trans "Post" %}"/> |
|
212 | <input type="submit" value="{% trans "Post" %}"/> | |
213 | <div> |
|
213 | </div> | |
214 | </form> |
|
214 | </form> | |
|
215 | <div> | |||
215 | {% trans 'Tags must be delimited by spaces. Text or image is required.' %} |
|
216 | {% trans 'Tags must be delimited by spaces. Text or image is required.' %} | |
216 | </div> |
|
217 | </div> | |
217 | <div><a href="{% url "staticpage" name="help" %}"> |
|
218 | <div><a href="{% url "staticpage" name="help" %}"> | |
218 | {% trans 'Text syntax' %}</a></div> |
|
219 | {% trans 'Text syntax' %}</a></div> | |
219 | </div> |
|
220 | </div> | |
220 | </div> |
|
221 | </div> | |
221 |
|
222 | |||
222 | {% endblock %} |
|
223 | {% endblock %} | |
223 |
|
224 | |||
224 | {% block metapanel %} |
|
225 | {% block metapanel %} | |
225 |
|
226 | |||
226 | <span class="metapanel"> |
|
227 | <span class="metapanel"> | |
227 | <b><a href="{% url "authors" %}">Neboard</a> 1.4</b> |
|
228 | <b><a href="{% url "authors" %}">Neboard</a> 1.4</b> | |
228 | {% trans "Pages:" %} |
|
229 | {% trans "Pages:" %} | |
229 | {% for page in pages %} |
|
230 | {% for page in pages %} | |
230 | [<a href=" |
|
231 | [<a href=" | |
231 | {% if tag %} |
|
232 | {% if tag %} | |
232 | {% url "tag" tag_name=tag page=page %} |
|
233 | {% url "tag" tag_name=tag page=page %} | |
233 | {% else %} |
|
234 | {% else %} | |
234 | {% url "index" page=page %} |
|
235 | {% url "index" page=page %} | |
235 | {% endif %} |
|
236 | {% endif %} | |
236 | ">{{ page }}</a>] |
|
237 | ">{{ page }}</a>] | |
237 | {% endfor %} |
|
238 | {% endfor %} | |
238 | [<a href="rss/">RSS</a>] |
|
239 | [<a href="rss/">RSS</a>] | |
239 | </span> |
|
240 | </span> | |
240 |
|
241 | |||
241 | {% endblock %} |
|
242 | {% endblock %} |
@@ -1,36 +1,37 b'' | |||||
1 | {% extends "boards/base.html" %} |
|
1 | {% extends "boards/base.html" %} | |
2 |
|
2 | |||
3 | {% load i18n %} |
|
3 | {% load i18n %} | |
4 | {% load humanize %} |
|
4 | {% load humanize %} | |
5 |
|
5 | |||
6 | {% block head %} |
|
6 | {% block head %} | |
7 | <title>Neboard settings</title> |
|
7 | <title>Neboard settings</title> | |
8 | {% endblock %} |
|
8 | {% endblock %} | |
9 |
|
9 | |||
10 | {% block content %} |
|
10 | {% block content %} | |
11 |
|
11 | |||
12 | <div class="post"> |
|
12 | <div class="post"> | |
13 | <p> |
|
13 | <p> | |
14 | {% trans 'User:' %} <b>{{ user.user_id }}</b>. |
|
14 | {% trans 'User:' %} <b>{{ user.user_id }}</b>. | |
15 | {% if user.is_moderator %} |
|
15 | {% if user.is_moderator %} | |
16 | {% trans 'You are moderator.' %} |
|
16 | {% trans 'You are moderator.' %} | |
17 | {% endif %} |
|
17 | {% endif %} | |
18 | </p> |
|
18 | </p> | |
19 | <p>{% trans 'Posts:' %} {{ user.get_post_count }}</p> |
|
19 | <p>{% trans 'Posts:' %} {{ user.get_post_count }}</p> | |
20 | <p>{% trans 'First access:' %} {{ user.registration_time|naturaltime }}</p> |
|
20 | <p>{% trans 'First access:' %} {{ user.registration_time|naturaltime }}</p> | |
21 | {% if user.get_last_access_time %} |
|
21 | {% if user.get_last_access_time %} | |
22 | <p>{% trans 'Last access:' %} {{ user.get_last_access_time|naturaltime }}</p> |
|
22 | <p>{% trans 'Last access:' %} {{ user.get_last_access_time|naturaltime }}</p> | |
23 | {% endif %} |
|
23 | {% endif %} | |
24 | </div> |
|
24 | </div> | |
25 |
|
25 | |||
26 | <div class="post-form-w"> |
|
26 | <div class="post-form-w"> | |
27 | <div class="post-form"> |
|
27 | <div class="post-form"> | |
28 | <form method="post">{% csrf_token %} |
|
28 | <form method="post">{% csrf_token %} | |
29 |
{{ form.as_ |
|
29 | {{ form.as_div }} | |
30 | <hr /> |
|
30 | <div class="form-submit"> | |
31 | <input type="submit" value="{% trans "Save" %}" /> |
|
31 | <input type="submit" value="{% trans "Save" %}" /> | |
|
32 | </div> | |||
32 | </form> |
|
33 | </form> | |
33 | </div> |
|
34 | </div> | |
34 | </div> |
|
35 | </div> | |
35 |
|
36 | |||
36 | {% endblock %} |
|
37 | {% endblock %} |
@@ -1,127 +1,127 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>Neboard - {{ thread.get_replies.0.get_title }}</title> |
|
9 | <title>Neboard - {{ thread.get_replies.0.get_title }}</title> | |
10 | {% endblock %} |
|
10 | {% endblock %} | |
11 |
|
11 | |||
12 | {% block content %} |
|
12 | {% block content %} | |
13 | {% spaceless %} |
|
13 | {% spaceless %} | |
14 | {% get_current_language as LANGUAGE_CODE %} |
|
14 | {% get_current_language as LANGUAGE_CODE %} | |
15 |
|
15 | |||
16 | <script src="{% static 'js/thread_update.js' %}"></script> |
|
16 | <script src="{% static 'js/thread_update.js' %}"></script> | |
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 | {% if bumpable %} |
|
20 | {% if bumpable %} | |
21 | <div class="bar-bg"> |
|
21 | <div class="bar-bg"> | |
22 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> |
|
22 | <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress"> | |
23 | </div> |
|
23 | </div> | |
24 | <div class="bar-text"> |
|
24 | <div class="bar-text"> | |
25 | <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %} |
|
25 | <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %} | |
26 | </div> |
|
26 | </div> | |
27 | </div> |
|
27 | </div> | |
28 | {% endif %} |
|
28 | {% endif %} | |
29 | <div class="thread"> |
|
29 | <div class="thread"> | |
30 | {% for post in thread.get_replies %} |
|
30 | {% for post in thread.get_replies %} | |
31 | {% if bumpable %} |
|
31 | {% if bumpable %} | |
32 | <div class="post" id="{{ post.id }}"> |
|
32 | <div class="post" id="{{ post.id }}"> | |
33 | {% else %} |
|
33 | {% else %} | |
34 | <div class="post dead_post" id="{{ post.id }}"> |
|
34 | <div class="post dead_post" id="{{ post.id }}"> | |
35 | {% endif %} |
|
35 | {% endif %} | |
36 | {% if post.image %} |
|
36 | {% if post.image %} | |
37 | <div class="image"> |
|
37 | <div class="image"> | |
38 | <a |
|
38 | <a | |
39 | class="thumb" |
|
39 | class="thumb" | |
40 | href="{{ post.image.url }}"><img |
|
40 | href="{{ post.image.url }}"><img | |
41 | src="{{ post.image.url_200x150 }}" |
|
41 | src="{{ post.image.url_200x150 }}" | |
42 | alt="{{ post.id }}" |
|
42 | alt="{{ post.id }}" | |
43 | data-width="{{ post.image_width }}" |
|
43 | data-width="{{ post.image_width }}" | |
44 | data-height="{{ post.image_height }}"/> |
|
44 | data-height="{{ post.image_height }}"/> | |
45 | </a> |
|
45 | </a> | |
46 | </div> |
|
46 | </div> | |
47 | {% endif %} |
|
47 | {% endif %} | |
48 | <div class="message"> |
|
48 | <div class="message"> | |
49 | <div class="post-info"> |
|
49 | <div class="post-info"> | |
50 | <span class="title">{{ post.title }}</span> |
|
50 | <span class="title">{{ post.title }}</span> | |
51 | <a class="post_id" href="#{{ post.id }}"> |
|
51 | <a class="post_id" href="#{{ post.id }}"> | |
52 | ({{ post.id }})</a> |
|
52 | ({{ post.id }})</a> | |
53 | [{{ post.pub_time }}] |
|
53 | [{{ post.pub_time }}] | |
54 | [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}') |
|
54 | [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}') | |
55 | ; return false;">>></a>] |
|
55 | ; return false;">>></a>] | |
56 |
|
56 | |||
57 | {% if moderator %} |
|
57 | {% if moderator %} | |
58 | <span class="moderator_info"> |
|
58 | <span class="moderator_info"> | |
59 | [<a href="{% url 'delete' post_id=post.id %}" |
|
59 | [<a href="{% url 'delete' post_id=post.id %}" | |
60 | >{% trans 'Delete' %}</a>] |
|
60 | >{% trans 'Delete' %}</a>] | |
61 | ({{ post.poster_ip }}) |
|
61 | ({{ post.poster_ip }}) | |
62 | [<a href="{% url 'ban' post_id=post.id %}?next={{ request.path }}" |
|
62 | [<a href="{% url 'ban' post_id=post.id %}?next={{ request.path }}" | |
63 | >{% trans 'Ban IP' %}</a>] |
|
63 | >{% trans 'Ban IP' %}</a>] | |
64 | </span> |
|
64 | </span> | |
65 | {% endif %} |
|
65 | {% endif %} | |
66 | </div> |
|
66 | </div> | |
67 | {% autoescape off %} |
|
67 | {% autoescape off %} | |
68 | {{ post.text.rendered }} |
|
68 | {{ post.text.rendered }} | |
69 | {% endautoescape %} |
|
69 | {% endautoescape %} | |
70 | {% if post.is_referenced %} |
|
70 | {% if post.is_referenced %} | |
71 | <div class="refmap"> |
|
71 | <div class="refmap"> | |
72 | {% trans "Replies" %}: |
|
72 | {% trans "Replies" %}: | |
73 | {% for ref_post in post.get_sorted_referenced_posts %} |
|
73 | {% for ref_post in post.get_sorted_referenced_posts %} | |
74 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a |
|
74 | <a href="{% post_url ref_post.id %}">>>{{ ref_post.id }}</a | |
75 | >{% if not forloop.last %},{% endif %} |
|
75 | >{% if not forloop.last %},{% endif %} | |
76 | {% endfor %} |
|
76 | {% endfor %} | |
77 | </div> |
|
77 | </div> | |
78 | {% endif %} |
|
78 | {% endif %} | |
79 | </div> |
|
79 | </div> | |
80 | {% if forloop.first %} |
|
80 | {% if forloop.first %} | |
81 | <div class="metadata"> |
|
81 | <div class="metadata"> | |
82 | <span class="tags"> |
|
82 | <span class="tags"> | |
83 | {% for tag in thread.get_tags %} |
|
83 | {% for tag in thread.get_tags %} | |
84 | <a class="tag" href="{% url 'tag' tag.name %}"> |
|
84 | <a class="tag" href="{% url 'tag' tag.name %}"> | |
85 | #{{ tag.name }}</a |
|
85 | #{{ tag.name }}</a | |
86 | >{% if not forloop.last %},{% endif %} |
|
86 | >{% if not forloop.last %},{% endif %} | |
87 | {% endfor %} |
|
87 | {% endfor %} | |
88 | </span> |
|
88 | </span> | |
89 | </div> |
|
89 | </div> | |
90 | {% endif %} |
|
90 | {% endif %} | |
91 | </div> |
|
91 | </div> | |
92 | {% endfor %} |
|
92 | {% endfor %} | |
93 | </div> |
|
93 | </div> | |
94 | {% endcache %} |
|
94 | {% endcache %} | |
95 |
|
95 | |||
96 | <div class="post-form-w"> |
|
96 | <div class="post-form-w"> | |
97 | <div class="form-title">{% trans "Reply to thread" %} #{{ thread.get_opening_post.id }}</div> |
|
97 | <div class="form-title">{% trans "Reply to thread" %} #{{ thread.get_opening_post.id }}</div> | |
98 | <div class="post-form"> |
|
98 | <div class="post-form"> | |
99 | <form id="form" enctype="multipart/form-data" method="post" |
|
99 | <form id="form" enctype="multipart/form-data" method="post" | |
100 | >{% csrf_token %} |
|
100 | >{% csrf_token %} | |
101 |
{{ form.as_ |
|
101 | {{ form.as_div }} | |
102 | <div class="form-submit"> |
|
102 | <div class="form-submit"> | |
103 | <input type="submit" value="{% trans "Post" %}"/> |
|
103 | <input type="submit" value="{% trans "Post" %}"/> | |
104 | </div> |
|
104 | </div> | |
105 | </form> |
|
105 | </form> | |
106 | <div><a href="{% url "staticpage" name="help" %}"> |
|
106 | <div><a href="{% url "staticpage" name="help" %}"> | |
107 | {% trans 'Text syntax' %}</a></div> |
|
107 | {% trans 'Text syntax' %}</a></div> | |
108 | </div> |
|
108 | </div> | |
109 | </div> |
|
109 | </div> | |
110 |
|
110 | |||
111 | {% endspaceless %} |
|
111 | {% endspaceless %} | |
112 | {% endblock %} |
|
112 | {% endblock %} | |
113 |
|
113 | |||
114 | {% block metapanel %} |
|
114 | {% block metapanel %} | |
115 |
|
115 | |||
116 | {% get_current_language as LANGUAGE_CODE %} |
|
116 | {% get_current_language as LANGUAGE_CODE %} | |
117 |
|
117 | |||
118 | <span class="metapanel" data-last-update="{{ last_update }}"> |
|
118 | <span class="metapanel" data-last-update="{{ last_update }}"> | |
119 | {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %} |
|
119 | {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %} | |
120 | <span id="reply-count">{{ thread.get_reply_count }}</span> {% trans 'replies' %}, |
|
120 | <span id="reply-count">{{ thread.get_reply_count }}</span> {% trans 'replies' %}, | |
121 | <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}. |
|
121 | <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}. | |
122 | {% trans 'Last update: ' %}{{ thread.last_edit_time }} |
|
122 | {% trans 'Last update: ' %}{{ thread.last_edit_time }} | |
123 | [<a href="rss/">RSS</a>] |
|
123 | [<a href="rss/">RSS</a>] | |
124 | {% endcache %} |
|
124 | {% endcache %} | |
125 | </span> |
|
125 | </span> | |
126 |
|
126 | |||
127 | {% endblock %} |
|
127 | {% endblock %} |
General Comments 0
You need to be logged in to leave comments.
Login now