##// END OF EJS Templates
Basic support for the generic forms. Still need to fix some things in the form...
neko259 -
r425:abb0b1c9 default
parent child Browse files
Show More
@@ -1,253 +1,253 b''
1 1 import re
2 2 from captcha.fields import CaptchaField
3 3 from django import forms
4 4 from django.forms.util import ErrorList
5 5 from django.utils.translation import ugettext_lazy as _
6 6 import time
7 7 from boards.models.post import TITLE_MAX_LENGTH
8 8 from boards.models import User
9 9 from neboard import settings
10 10 from boards import utils
11 11 import boards.settings as board_settings
12 12
13 13 LAST_POST_TIME = "last_post_time"
14 14 LAST_LOGIN_TIME = "last_login_time"
15 15
16 16
17 17 class PlainErrorList(ErrorList):
18 18 def __unicode__(self):
19 19 return self.as_text()
20 20
21 21 def as_text(self):
22 22 return ''.join([u'(!) %s ' % e for e in self])
23 23
24 24
25 25 class NeboardForm(forms.Form):
26 26
27 27 def as_p(self):
28 28 "Returns this form rendered as HTML <p>s."
29 29 return self._html_output(
30 # TODO Do not show hidden rows in the list here
30 31 normal_row='<div class="form-row">'
31 32 '<div class="form-label">'
32 33 '%(label)s'
33 34 '</div>'
34 35 '<div class="form-input">'
35 36 '%(field)s'
36 37 '</div>'
37 38 '%(help_text)s'
38 39 '</div>',
39 error_row='<div class="form-errors">%s</div>',
40 error_row='<div class="form-row"><div class="form-label"></div><div class="form-errors">%s</div></div>',
40 41 row_ender='</p>',
41 42 help_text_html=' <span class="helptext">%s</span>',
42 43 errors_on_separate_row=True)
43 44
44
45 45 class PostForm(NeboardForm):
46 46
47 47 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
48 48 label=_('Title'))
49 49 text = forms.CharField(widget=forms.Textarea, required=False,
50 50 label=_('Text'))
51 51 image = forms.ImageField(required=False, label=_('Image'))
52 52
53 53 # This field is for spam prevention only
54 54 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
55 55 widget=forms.TextInput(attrs={
56 56 'class': 'form-email'}))
57 57
58 58 session = None
59 59 need_to_ban = False
60 60
61 61 def clean_title(self):
62 62 title = self.cleaned_data['title']
63 63 if title:
64 64 if len(title) > TITLE_MAX_LENGTH:
65 65 raise forms.ValidationError(_('Title must have less than %s '
66 66 'characters') %
67 67 str(TITLE_MAX_LENGTH))
68 68 return title
69 69
70 70 def clean_text(self):
71 71 text = self.cleaned_data['text']
72 72 if text:
73 73 if len(text) > board_settings.MAX_TEXT_LENGTH:
74 74 raise forms.ValidationError(_('Text must have less than %s '
75 75 'characters') %
76 76 str(board_settings
77 77 .MAX_TEXT_LENGTH))
78 78 return text
79 79
80 80 def clean_image(self):
81 81 image = self.cleaned_data['image']
82 82 if image:
83 83 if image._size > board_settings.MAX_IMAGE_SIZE:
84 84 raise forms.ValidationError(
85 85 _('Image must be less than %s bytes')
86 86 % str(board_settings.MAX_IMAGE_SIZE))
87 87 return image
88 88
89 89 def clean(self):
90 90 cleaned_data = super(PostForm, self).clean()
91 91
92 92 if not self.session:
93 93 raise forms.ValidationError('Humans have sessions')
94 94
95 95 if cleaned_data['email']:
96 96 self.need_to_ban = True
97 97 raise forms.ValidationError('A human cannot enter a hidden field')
98 98
99 99 if not self.errors:
100 100 self._clean_text_image()
101 101
102 102 if not self.errors and self.session:
103 103 self._validate_posting_speed()
104 104
105 105 return cleaned_data
106 106
107 107 def _clean_text_image(self):
108 108 text = self.cleaned_data.get('text')
109 109 image = self.cleaned_data.get('image')
110 110
111 111 if (not text) and (not image):
112 112 error_message = _('Either text or image must be entered.')
113 113 self._errors['text'] = self.error_class([error_message])
114 114
115 115 def _validate_posting_speed(self):
116 116 can_post = True
117 117
118 118 if LAST_POST_TIME in self.session:
119 119 now = time.time()
120 120 last_post_time = self.session[LAST_POST_TIME]
121 121
122 122 current_delay = int(now - last_post_time)
123 123
124 124 if current_delay < settings.POSTING_DELAY:
125 125 error_message = _('Wait %s seconds after last posting') % str(
126 126 settings.POSTING_DELAY - current_delay)
127 127 self._errors['text'] = self.error_class([error_message])
128 128
129 129 can_post = False
130 130
131 131 if can_post:
132 132 self.session[LAST_POST_TIME] = time.time()
133 133
134 134
135 135 class ThreadForm(PostForm):
136 136
137 137 regex_tags = re.compile(ur'^[\w\s\d]+$', re.UNICODE)
138 138
139 139 tags = forms.CharField(max_length=100, label=_('Tags'))
140 140
141 141 def clean_tags(self):
142 142 tags = self.cleaned_data['tags']
143 143
144 144 if tags:
145 145 if not self.regex_tags.match(tags):
146 146 raise forms.ValidationError(
147 147 _('Inappropriate characters in tags.'))
148 148
149 149 return tags
150 150
151 151 def clean(self):
152 152 cleaned_data = super(ThreadForm, self).clean()
153 153
154 154 return cleaned_data
155 155
156 156
157 157 class PostCaptchaForm(PostForm):
158 158 captcha = CaptchaField()
159 159
160 160 def __init__(self, *args, **kwargs):
161 161 self.request = kwargs['request']
162 162 del kwargs['request']
163 163
164 164 super(PostCaptchaForm, self).__init__(*args, **kwargs)
165 165
166 166 def clean(self):
167 167 cleaned_data = super(PostCaptchaForm, self).clean()
168 168
169 169 success = self.is_valid()
170 170 utils.update_captcha_access(self.request, success)
171 171
172 172 if success:
173 173 return cleaned_data
174 174 else:
175 175 raise forms.ValidationError(_("Captcha validation failed"))
176 176
177 177
178 178 class ThreadCaptchaForm(ThreadForm):
179 179 captcha = CaptchaField()
180 180
181 181 def __init__(self, *args, **kwargs):
182 182 self.request = kwargs['request']
183 183 del kwargs['request']
184 184
185 185 super(ThreadCaptchaForm, self).__init__(*args, **kwargs)
186 186
187 187 def clean(self):
188 188 cleaned_data = super(ThreadCaptchaForm, self).clean()
189 189
190 190 success = self.is_valid()
191 191 utils.update_captcha_access(self.request, success)
192 192
193 193 if success:
194 194 return cleaned_data
195 195 else:
196 196 raise forms.ValidationError(_("Captcha validation failed"))
197 197
198 198
199 199 class SettingsForm(NeboardForm):
200 200
201 201 theme = forms.ChoiceField(choices=settings.THEMES,
202 202 label=_('Theme'))
203 203
204 204
205 205 class ModeratorSettingsForm(SettingsForm):
206 206
207 207 moderate = forms.BooleanField(required=False, label=_('Enable moderation '
208 208 'panel'))
209 209
210 210
211 211 class LoginForm(NeboardForm):
212 212
213 213 user_id = forms.CharField()
214 214
215 215 session = None
216 216
217 217 def clean_user_id(self):
218 218 user_id = self.cleaned_data['user_id']
219 219 if user_id:
220 220 users = User.objects.filter(user_id=user_id)
221 221 if len(users) == 0:
222 222 raise forms.ValidationError(_('No such user found'))
223 223
224 224 return user_id
225 225
226 226 def _validate_login_speed(self):
227 227 can_post = True
228 228
229 229 if LAST_LOGIN_TIME in self.session:
230 230 now = time.time()
231 231 last_login_time = self.session[LAST_LOGIN_TIME]
232 232
233 233 current_delay = int(now - last_login_time)
234 234
235 235 if current_delay < board_settings.LOGIN_TIMEOUT:
236 236 error_message = _('Wait %s minutes after last login') % str(
237 237 (board_settings.LOGIN_TIMEOUT - current_delay) / 60)
238 238 self._errors['user_id'] = self.error_class([error_message])
239 239
240 240 can_post = False
241 241
242 242 if can_post:
243 243 self.session[LAST_LOGIN_TIME] = time.time()
244 244
245 245 def clean(self):
246 246 if not self.session:
247 247 raise forms.ValidationError('Humans have sessions')
248 248
249 249 self._validate_login_speed()
250 250
251 251 cleaned_data = super(LoginForm, self).clean()
252 252
253 253 return cleaned_data
@@ -1,283 +1,241 b''
1 1 {% extends "boards/base.html" %}
2 2
3 3 {% load i18n %}
4 4 {% load cache %}
5 5 {% load board %}
6 6
7 7 {% block head %}
8 8 {% if tag %}
9 9 <title>Neboard - {{ tag.name }}</title>
10 10 {% else %}
11 11 <title>Neboard</title>
12 12 {% endif %}
13 13
14 14 {% if prev_page %}
15 15 <link rel="next" href="
16 16 {% if tag %}
17 17 {% url "tag" tag_name=tag page=prev_page %}
18 18 {% else %}
19 19 {% url "index" page=prev_page %}
20 20 {% endif %}
21 21 " />
22 22 {% endif %}
23 23 {% if next_page %}
24 24 <link rel="next" href="
25 25 {% if tag %}
26 26 {% url "tag" tag_name=tag page=next_page %}
27 27 {% else %}
28 28 {% url "index" page=next_page %}
29 29 {% endif %}
30 30 " />
31 31 {% endif %}
32 32
33 33 {% endblock %}
34 34
35 35 {% block content %}
36 36
37 37 {% get_current_language as LANGUAGE_CODE %}
38 38
39 39 {% if tag %}
40 40 <div class="tag_info">
41 41 <h2>
42 42 {% if tag in user.fav_tags.all %}
43 43 <a href="{% url 'tag_unsubscribe' tag.name %}?next={{ request.path }}"
44 44 class="fav">β˜…</a>
45 45 {% else %}
46 46 <a href="{% url 'tag_subscribe' tag.name %}?next={{ request.path }}"
47 47 class="not_fav">β˜…</a>
48 48 {% endif %}
49 49 #{{ tag.name }}
50 50 </h2>
51 51 </div>
52 52 {% endif %}
53 53
54 54 {% if threads %}
55 55 {% if prev_page %}
56 56 <div class="page_link">
57 57 <a href="
58 58 {% if tag %}
59 59 {% url "tag" tag_name=tag page=prev_page %}
60 60 {% else %}
61 61 {% url "index" page=prev_page %}
62 62 {% endif %}
63 63 ">{% trans "Previous page" %}</a>
64 64 </div>
65 65 {% endif %}
66 66
67 67 {% for thread in threads %}
68 68 {% cache 600 thread_short thread.id thread.thread.last_edit_time moderator LANGUAGE_CODE %}
69 69 <div class="thread">
70 70 {% if thread.bumpable %}
71 71 <div class="post" id="{{ thread.op.id }}">
72 72 {% else %}
73 73 <div class="post dead_post" id="{{ thread.op.id }}">
74 74 {% endif %}
75 75 {% if thread.op.image %}
76 76 <div class="image">
77 77 <a class="thumb"
78 78 href="{{ thread.op.image.url }}"><img
79 79 src="{{ thread.op.image.url_200x150 }}"
80 80 alt="{{ thread.op.id }}"
81 81 data-width="{{ thread.op.image_width }}"
82 82 data-height="{{ thread.op.image_height }}"/>
83 83 </a>
84 84 </div>
85 85 {% endif %}
86 86 <div class="message">
87 87 <div class="post-info">
88 88 <span class="title">{{ thread.op.title }}</span>
89 89 <a class="post_id" href="{% url 'thread' thread.op.id %}"
90 90 >({{ thread.op.id }})</a>
91 91 [{{ thread.op.pub_time }}]
92 92 [<a class="link" href="
93 93 {% url 'thread' thread.op.id %}#form"
94 94 >{% trans "Reply" %}</a>]
95 95
96 96 {% if moderator %}
97 97 <span class="moderator_info">
98 98 [<a href="
99 99 {% url 'delete' post_id=thread.op.id %}?next={{ request.path }}"
100 100 >{% trans 'Delete' %}</a>]
101 101 ({{ thread.thread.poster_ip }})
102 102 [<a href="
103 103 {% url 'ban' post_id=thread.op.id %}?next={{ request.path }}"
104 104 >{% trans 'Ban IP' %}</a>]
105 105 </span>
106 106 {% endif %}
107 107 </div>
108 108 {% autoescape off %}
109 109 {{ thread.op.text.rendered|truncatewords_html:50 }}
110 110 {% endautoescape %}
111 111 {% if thread.op.is_referenced %}
112 112 <div class="refmap">
113 113 {% trans "Replies" %}:
114 114 {% for ref_post in thread.op.get_sorted_referenced_posts %}
115 115 <a href="{% post_url ref_post.id %}">&gt;&gt;{{ ref_post.id }}</a
116 116 >{% if not forloop.last %},{% endif %}
117 117 {% endfor %}
118 118 </div>
119 119 {% endif %}
120 120 </div>
121 121 <div class="metadata">
122 122 {{ thread.thread.get_images_count }} {% trans 'images' %}.
123 123 {% if thread.thread.tags %}
124 124 <span class="tags">
125 125 {% for tag in thread.thread.get_tags %}
126 126 <a class="tag" href="
127 127 {% url 'tag' tag_name=tag.name %}">
128 128 #{{ tag.name }}</a
129 129 >{% if not forloop.last %},{% endif %}
130 130 {% endfor %}
131 131 </span>
132 132 {% endif %}
133 133 </div>
134 134 </div>
135 135 {% if thread.last_replies.exists %}
136 136 {% if thread.skipped_replies %}
137 137 <div class="skipped_replies">
138 138 <a href="{% url 'thread' thread.op.id %}">
139 139 {% blocktrans with count=thread.skipped_replies %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
140 140 </a>
141 141 </div>
142 142 {% endif %}
143 143 <div class="last-replies">
144 144 {% for post in thread.last_replies %}
145 145 {% if thread.bumpable %}
146 146 <div class="post" id="{{ post.id }}">
147 147 {% else %}
148 148 <div class="post dead_post" id="{{ post.id }}">
149 149 {% endif %}
150 150 {% if post.image %}
151 151 <div class="image">
152 152 <a class="thumb"
153 153 href="{{ post.image.url }}"><img
154 154 src=" {{ post.image.url_200x150 }}"
155 155 alt="{{ post.id }}"
156 156 data-width="{{ post.image_width }}"
157 157 data-height="{{ post.image_height }}"/>
158 158 </a>
159 159 </div>
160 160 {% endif %}
161 161 <div class="message">
162 162 <div class="post-info">
163 163 <span class="title">{{ post.title }}</span>
164 164 <a class="post_id" href="
165 165 {% url 'thread' thread.op.id %}#{{ post.id }}">
166 166 ({{ post.id }})</a>
167 167 [{{ post.pub_time }}]
168 168 </div>
169 169 {% autoescape off %}
170 170 {{ post.text.rendered|truncatewords_html:50 }}
171 171 {% endautoescape %}
172 172 </div>
173 173 {% if post.is_referenced %}
174 174 <div class="refmap">
175 175 {% trans "Replies" %}:
176 176 {% for ref_post in post.get_sorted_referenced_posts %}
177 177 <a href="{% post_url ref_post.id %}">&gt;&gt;{{ ref_post.id }}</a
178 178 >{% if not forloop.last %},{% endif %}
179 179 {% endfor %}
180 180 </div>
181 181 {% endif %}
182 182 </div>
183 183 {% endfor %}
184 184 </div>
185 185 {% endif %}
186 186 </div>
187 187 {% endcache %}
188 188 {% endfor %}
189 189
190 190 {% if next_page %}
191 191 <div class="page_link">
192 192 <a href="
193 193 {% if tag %}
194 194 {% url "tag" tag_name=tag page=next_page %}
195 195 {% else %}
196 196 {% url "index" page=next_page %}
197 197 {% endif %}
198 198 ">{% trans "Next page" %}</a>
199 199 </div>
200 200 {% endif %}
201 201 {% else %}
202 202 <div class="post">
203 203 {% trans 'No threads exist. Create the first one!' %}</div>
204 {% endif %}
204 {% endif %}
205 205
206 <form enctype="multipart/form-data" method="post">{% csrf_token %}
207 206 <div class="post-form-w">
208
209 <div class="form-title">{% trans "Create new thread" %}</div>
210 207 <div class="post-form">
211 <div class="form-row">
212 <div class="form-label">{% trans 'Title' %}</div>
213 <div class="form-input">{{ form.title }}</div>
214 <div class="form-errors">{{ form.title.errors }}</div>
215 </div>
216 <div class="form-row">
217 <div class="form-label">{% trans 'Formatting' %}</div>
218 <div class="form-input" id="mark_panel">
219 <span class="mark_btn" id="quote"><span class="quote">&gt;{% trans 'quote' %}</span></span>
220 <span class="mark_btn" id="italic"><i>{% trans 'italic' %}</i></span>
221 <span class="mark_btn" id="bold"><b>{% trans 'bold' %}</b></span>
222 <span class="mark_btn" id="spoiler"><span class="spoiler">{% trans 'spoiler' %}</span></span>
223 <span class="mark_btn" id="comment"><span class="comment">// {% trans 'comment' %}</span></span>
224 </div>
225 </div>
226 <div class="form-row">
227 <div class="form-label">{% trans 'Text' %}</div>
228 <div class="form-input">{{ form.text }}</div>
229 <div class="form-errors">{{ form.text.errors }}</div>
208 <div class="form-title">{% trans "Create new thread" %}</div>
209 <form enctype="multipart/form-data" method="post">{% csrf_token %}
210 {{ form.as_p }}
211 <div class="form-submit">
212 <input type="submit" value="{% trans "Post" %}"/></div>
213 <div>
214 </form>
215 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
230 216 </div>
231 <div class="form-row">
232 <div class="form-label">{% trans 'Image' %}</div>
233 <div class="form-input">{{ form.image }}</div>
234 <div class="form-errors">{{ form.image.errors }}</div>
235 </div>
236 <div class="form-row">
237 <div class="form-label">{% trans 'Tags' %}</div>
238 <div class="form-input">{{ form.tags }}</div>
239 <div class="form-errors">{{ form.tags.errors }}</div>
240 </div>
241 <div class="form-row form-email">
242 <div class="form-label">{% trans 'e-mail' %}</div>
243 <div class="form-input">{{ form.email }}</div>
244 <div class="form-errors">{{ form.email.errors }}</div>
245 </div>
246 <div class="form-row">
247 {{ form.captcha }}
248 <div class="form-errors">{{ form.captcha.errors }}</div>
249 </div>
250 <div class="form-row">
251 <div class="form-errors">{{ form.other.errors }}</div>
252 </div>
217 <div><a href="{% url "staticpage" name="help" %}">
218 {% trans 'Text syntax' %}</a></div>
253 219 </div>
254 <div class="form-submit">
255 <input type="submit" value="{% trans "Post" %}"/></div>
256 <div>
257 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
258 </div>
259 <div><a href="{% url "staticpage" name="help" %}">
260 {% trans 'Text syntax' %}</a></div>
261 220 </div>
262 </form>
263 221
264 222 {% endblock %}
265 223
266 224 {% block metapanel %}
267 225
268 226 <span class="metapanel">
269 227 <b><a href="{% url "authors" %}">Neboard</a> 1.4</b>
270 228 {% trans "Pages:" %}
271 229 {% for page in pages %}
272 230 [<a href="
273 231 {% if tag %}
274 232 {% url "tag" tag_name=tag page=page %}
275 233 {% else %}
276 234 {% url "index" page=page %}
277 235 {% endif %}
278 236 ">{{ page }}</a>]
279 237 {% endfor %}
280 238 [<a href="rss/">RSS</a>]
281 239 </span>
282 240
283 241 {% endblock %}
@@ -1,163 +1,127 b''
1 1 {% extends "boards/base.html" %}
2 2
3 3 {% load i18n %}
4 4 {% load cache %}
5 5 {% load static from staticfiles %}
6 6 {% load board %}
7 7
8 8 {% block head %}
9 9 <title>Neboard - {{ thread.get_replies.0.get_title }}</title>
10 10 {% endblock %}
11 11
12 12 {% block content %}
13 13 {% spaceless %}
14 14 {% get_current_language as LANGUAGE_CODE %}
15 15
16 16 <script src="{% static 'js/thread_update.js' %}"></script>
17 17 <script src="{% static 'js/thread.js' %}"></script>
18 18
19 19 {% cache 600 thread_view thread.id thread.last_edit_time moderator LANGUAGE_CODE %}
20 20 {% if bumpable %}
21 21 <div class="bar-bg">
22 22 <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress">
23 23 </div>
24 24 <div class="bar-text">
25 25 <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %}
26 26 </div>
27 27 </div>
28 28 {% endif %}
29 29 <div class="thread">
30 30 {% for post in thread.get_replies %}
31 31 {% if bumpable %}
32 32 <div class="post" id="{{ post.id }}">
33 33 {% else %}
34 34 <div class="post dead_post" id="{{ post.id }}">
35 35 {% endif %}
36 36 {% if post.image %}
37 37 <div class="image">
38 38 <a
39 39 class="thumb"
40 40 href="{{ post.image.url }}"><img
41 41 src="{{ post.image.url_200x150 }}"
42 42 alt="{{ post.id }}"
43 43 data-width="{{ post.image_width }}"
44 44 data-height="{{ post.image_height }}"/>
45 45 </a>
46 46 </div>
47 47 {% endif %}
48 48 <div class="message">
49 49 <div class="post-info">
50 50 <span class="title">{{ post.title }}</span>
51 51 <a class="post_id" href="#{{ post.id }}">
52 52 ({{ post.id }})</a>
53 53 [{{ post.pub_time }}]
54 54 [<a href="#" onclick="javascript:addQuickReply('{{ post.id }}')
55 55 ; return false;">&gt;&gt;</a>]
56 56
57 57 {% if moderator %}
58 58 <span class="moderator_info">
59 59 [<a href="{% url 'delete' post_id=post.id %}"
60 60 >{% trans 'Delete' %}</a>]
61 61 ({{ post.poster_ip }})
62 62 [<a href="{% url 'ban' post_id=post.id %}?next={{ request.path }}"
63 63 >{% trans 'Ban IP' %}</a>]
64 64 </span>
65 65 {% endif %}
66 66 </div>
67 67 {% autoescape off %}
68 68 {{ post.text.rendered }}
69 69 {% endautoescape %}
70 70 {% if post.is_referenced %}
71 71 <div class="refmap">
72 72 {% trans "Replies" %}:
73 73 {% for ref_post in post.get_sorted_referenced_posts %}
74 74 <a href="{% post_url ref_post.id %}">&gt;&gt;{{ ref_post.id }}</a
75 75 >{% if not forloop.last %},{% endif %}
76 76 {% endfor %}
77 77 </div>
78 78 {% endif %}
79 79 </div>
80 80 {% if forloop.first %}
81 81 <div class="metadata">
82 82 <span class="tags">
83 83 {% for tag in thread.get_tags %}
84 84 <a class="tag" href="{% url 'tag' tag.name %}">
85 85 #{{ tag.name }}</a
86 86 >{% if not forloop.last %},{% endif %}
87 87 {% endfor %}
88 88 </span>
89 89 </div>
90 90 {% endif %}
91 91 </div>
92 92 {% endfor %}
93 93 </div>
94 94 {% endcache %}
95 95
96 <form id="form" enctype="multipart/form-data" method="post"
97 >{% csrf_token %}
98 <div class="post-form-w">
99 <div class="form-title">{% trans "Reply to thread" %} #{{ thread.get_opening_post.id }}</div>
100 <div class="post-form">
101 <div class="form-row">
102 <div class="form-label">{% trans 'Title' %}</div>
103 <div class="form-input">{{ form.title }}</div>
104 <div class="form-errors">{{ form.title.errors }}</div>
105 </div>
106 <div class="form-row">
107 <div class="form-label">{% trans 'Formatting' %}</div>
108 <div class="form-input" id="mark_panel">
109 <span class="mark_btn" id="quote"><span class="quote">&gt;{% trans 'quote' %}</span></span>
110 <span class="mark_btn" id="italic"><i>{% trans 'italic' %}</i></span>
111 <span class="mark_btn" id="bold"><b>{% trans 'bold' %}</b></span>
112 <span class="mark_btn" id="spoiler"><span class="spoiler">{% trans 'spoiler' %}</span></span>
113 <span class="mark_btn" id="comment"><span class="comment">// {% trans 'comment' %}</span></span>
114 </div>
115 </div>
116 <div class="form-row">
117 <div class="form-label">{% trans 'Text' %}</div>
118 <div class="form-input">{{ form.text }}</div>
119 <div class="form-errors">{{ form.text.errors }}</div>
120 </div>
121 <div class="form-row">
122 <div class="form-label">{% trans 'Image' %}</div>
123 <div class="form-input">{{ form.image }}</div>
124 <div class="form-errors">{{ form.image.errors }}</div>
125 </div>
126 <div class="form-row form-email">
127 <div class="form-label">{% trans 'e-mail' %}</div>
128 <div class="form-input">{{ form.email }}</div>
129 <div class="form-errors">{{ form.email.errors }}</div>
130 </div>
131 <div class="form-row">
132 {{ form.captcha }}
133 <div class="form-errors">{{ form.captcha.errors }}</div>
134 </div>
135 <div class="form-row">
136 <div class="form-errors">{{ form.other.errors }}</div>
137 </div>
96 <div class="post-form-w">
97 <div class="form-title">{% trans "Reply to thread" %} #{{ thread.get_opening_post.id }}</div>
98 <div class="post-form">
99 <form id="form" enctype="multipart/form-data" method="post"
100 >{% csrf_token %}
101 {{ form.as_p }}
102 <div class="form-submit">
103 <input type="submit" value="{% trans "Post" %}"/>
138 104 </div>
139
140 <div class="form-submit"><input type="submit"
141 value="{% trans "Post" %}"/></div>
142 <div><a href="{% url "staticpage" name="help" %}">
143 {% trans 'Text syntax' %}</a></div>
105 </form>
106 <div><a href="{% url "staticpage" name="help" %}">
107 {% trans 'Text syntax' %}</a></div>
144 108 </div>
145 </form>
109 </div>
146 110
147 111 {% endspaceless %}
148 112 {% endblock %}
149 113
150 114 {% block metapanel %}
151 115
152 116 {% get_current_language as LANGUAGE_CODE %}
153 117
154 118 <span class="metapanel" data-last-update="{{ last_update }}">
155 119 {% cache 600 thread_meta thread.last_edit_time moderator LANGUAGE_CODE %}
156 120 <span id="reply-count">{{ thread.get_reply_count }}</span> {% trans 'replies' %},
157 121 <span id="image-count">{{ thread.get_images_count }}</span> {% trans 'images' %}.
158 122 {% trans 'Last update: ' %}{{ thread.last_edit_time }}
159 123 [<a href="rss/">RSS</a>]
160 124 {% endcache %}
161 125 </span>
162 126
163 127 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now