##// END OF EJS Templates
Fixed get computing. Visually differing get posts in thread.
neko259 -
r42:37e52c98 default
parent child Browse files
Show More
@@ -1,212 +1,212 b''
1 import os
1 import os
2 import re
2 import re
3 from django.db import models
3 from django.db import models
4 from django.utils import timezone
4 from django.utils import timezone
5 import time
5 import time
6
6
7 from neboard import settings
7 from neboard import settings
8 from markupfield.fields import MarkupField
8 from markupfield.fields import MarkupField
9
9
10 import thumbs
10 import thumbs
11
11
12 NO_PARENT = -1
12 NO_PARENT = -1
13 NO_IP = '0.0.0.0'
13 NO_IP = '0.0.0.0'
14 UNKNOWN_UA = ''
14 UNKNOWN_UA = ''
15
15
16
16
17 def update_image_filename(instance, filename):
17 def update_image_filename(instance, filename):
18 """Get unique image filename"""
18 """Get unique image filename"""
19
19
20 path = 'images/'
20 path = 'images/'
21 new_name = str(int(time.mktime(time.gmtime()))) + '_' + filename
21 new_name = str(int(time.mktime(time.gmtime()))) + '_' + filename
22 return os.path.join(path, new_name)
22 return os.path.join(path, new_name)
23
23
24
24
25 class PostManager(models.Manager):
25 class PostManager(models.Manager):
26 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
26 def create_post(self, title, text, image=None, parent_id=NO_PARENT,
27 ip=NO_IP, tags=None):
27 ip=NO_IP, tags=None):
28 post = self.create(title=title,
28 post = self.create(title=title,
29 text=text,
29 text=text,
30 pub_time=timezone.now(),
30 pub_time=timezone.now(),
31 parent=parent_id,
31 parent=parent_id,
32 image=image,
32 image=image,
33 poster_ip=ip,
33 poster_ip=ip,
34 poster_user_agent=UNKNOWN_UA,
34 poster_user_agent=UNKNOWN_UA,
35 last_edit_time=timezone.now())
35 last_edit_time=timezone.now())
36
36
37 if tags:
37 if tags:
38 for tag in tags:
38 for tag in tags:
39 post.tags.add(tag)
39 post.tags.add(tag)
40
40
41 if parent_id != NO_PARENT:
41 if parent_id != NO_PARENT:
42 self._bump_thread(parent_id)
42 self._bump_thread(parent_id)
43 else:
43 else:
44 self._delete_old_threads()
44 self._delete_old_threads()
45
45
46 return post
46 return post
47
47
48 def delete_post(self, post):
48 def delete_post(self, post):
49 children = self.filter(parent=post.id)
49 children = self.filter(parent=post.id)
50 for child in children:
50 for child in children:
51 self.delete_post(child)
51 self.delete_post(child)
52 post.delete()
52 post.delete()
53
53
54 def delete_posts_by_ip(self, ip):
54 def delete_posts_by_ip(self, ip):
55 posts = self.filter(poster_ip=ip)
55 posts = self.filter(poster_ip=ip)
56 for post in posts:
56 for post in posts:
57 self.delete_post(post)
57 self.delete_post(post)
58
58
59 def get_threads(self, tag=None):
59 def get_threads(self, tag=None):
60 if tag:
60 if tag:
61 threads = self.filter(parent=NO_PARENT, tags=tag)
61 threads = self.filter(parent=NO_PARENT, tags=tag)
62 else:
62 else:
63 threads = self.filter(parent=NO_PARENT)
63 threads = self.filter(parent=NO_PARENT)
64 threads = list(threads.order_by('-last_edit_time'))
64 threads = list(threads.order_by('-last_edit_time'))
65
65
66 return threads
66 return threads
67
67
68 def get_thread(self, opening_post_id):
68 def get_thread(self, opening_post_id):
69 opening_post = self.get(id=opening_post_id)
69 opening_post = self.get(id=opening_post_id)
70
70
71 if opening_post.parent == NO_PARENT:
71 if opening_post.parent == NO_PARENT:
72 replies = self.filter(parent=opening_post_id)
72 replies = self.filter(parent=opening_post_id)
73
73
74 thread = [opening_post]
74 thread = [opening_post]
75 thread.extend(replies)
75 thread.extend(replies)
76
76
77 return thread
77 return thread
78
78
79 def exists(self, post_id):
79 def exists(self, post_id):
80 posts = self.filter(id=post_id)
80 posts = self.filter(id=post_id)
81
81
82 return len(posts) > 0
82 return len(posts) > 0
83
83
84 def _delete_old_threads(self):
84 def _delete_old_threads(self):
85 """
85 """
86 Preserves maximum thread count. If there are too many threads,
86 Preserves maximum thread count. If there are too many threads,
87 delete the old ones.
87 delete the old ones.
88 """
88 """
89
89
90 # TODO Try to find a better way to get the active thread count.
90 # TODO Try to find a better way to get the active thread count.
91
91
92 # TODO Move old threads to the archive instead of deleting them.
92 # TODO Move old threads to the archive instead of deleting them.
93 # Maybe make some 'old' field in the model to indicate the thread
93 # Maybe make some 'old' field in the model to indicate the thread
94 # must not be shown and be able for replying.
94 # must not be shown and be able for replying.
95
95
96 threads = self.get_threads()
96 threads = self.get_threads()
97 thread_count = len(threads)
97 thread_count = len(threads)
98
98
99 if thread_count > settings.MAX_THREAD_COUNT:
99 if thread_count > settings.MAX_THREAD_COUNT:
100 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
100 num_threads_to_delete = thread_count - settings.MAX_THREAD_COUNT
101 old_threads = threads[-num_threads_to_delete:]
101 old_threads = threads[-num_threads_to_delete:]
102
102
103 for thread in old_threads:
103 for thread in old_threads:
104 self.delete_post(thread)
104 self.delete_post(thread)
105
105
106 def _bump_thread(self, thread_id):
106 def _bump_thread(self, thread_id):
107 thread = self.get(id=thread_id)
107 thread = self.get(id=thread_id)
108
108
109 replies_count = len(self.get_thread(thread_id))
109 replies_count = len(self.get_thread(thread_id))
110 if replies_count <= settings.MAX_POSTS_PER_THREAD:
110 if replies_count <= settings.MAX_POSTS_PER_THREAD:
111 thread.last_edit_time = timezone.now()
111 thread.last_edit_time = timezone.now()
112 thread.save()
112 thread.save()
113
113
114
114
115 class TagManager(models.Manager):
115 class TagManager(models.Manager):
116 def get_not_empty_tags(self):
116 def get_not_empty_tags(self):
117 all_tags = self.all().order_by('name')
117 all_tags = self.all().order_by('name')
118 tags = []
118 tags = []
119 for tag in all_tags:
119 for tag in all_tags:
120 if not tag.is_empty():
120 if not tag.is_empty():
121 tags.append(tag)
121 tags.append(tag)
122
122
123 return tags
123 return tags
124
124
125
125
126 class Tag(models.Model):
126 class Tag(models.Model):
127 """
127 """
128 A tag is a text node assigned to the post. The tag serves as a board
128 A tag is a text node assigned to the post. The tag serves as a board
129 section. There can be multiple tags for each message
129 section. There can be multiple tags for each message
130 """
130 """
131
131
132 objects = TagManager()
132 objects = TagManager()
133
133
134 name = models.CharField(max_length=100)
134 name = models.CharField(max_length=100)
135 # TODO Connect the tag to its posts to check the number of threads for
135 # TODO Connect the tag to its posts to check the number of threads for
136 # the tag.
136 # the tag.
137
137
138 def __unicode__(self):
138 def __unicode__(self):
139 return self.name
139 return self.name
140
140
141 def is_empty(self):
141 def is_empty(self):
142 return self.get_post_count() == 0
142 return self.get_post_count() == 0
143
143
144 def get_post_count(self):
144 def get_post_count(self):
145 posts_with_tag = Post.objects.get_threads(tag=self)
145 posts_with_tag = Post.objects.get_threads(tag=self)
146 return len(posts_with_tag)
146 return len(posts_with_tag)
147
147
148
148
149 class Post(models.Model):
149 class Post(models.Model):
150 """A post is a message."""
150 """A post is a message."""
151
151
152 objects = PostManager()
152 objects = PostManager()
153
153
154 title = models.CharField(max_length=50)
154 title = models.CharField(max_length=50)
155 pub_time = models.DateTimeField()
155 pub_time = models.DateTimeField()
156 text = MarkupField(default_markup_type='markdown', escape_html=True)
156 text = MarkupField(default_markup_type='markdown', escape_html=True)
157 image = thumbs.ImageWithThumbsField(upload_to=update_image_filename,
157 image = thumbs.ImageWithThumbsField(upload_to=update_image_filename,
158 blank=True, sizes=((200, 150),))
158 blank=True, sizes=((200, 150),))
159 poster_ip = models.IPAddressField()
159 poster_ip = models.IPAddressField()
160 poster_user_agent = models.TextField()
160 poster_user_agent = models.TextField()
161 parent = models.BigIntegerField()
161 parent = models.BigIntegerField()
162 tags = models.ManyToManyField(Tag)
162 tags = models.ManyToManyField(Tag)
163 last_edit_time = models.DateTimeField()
163 last_edit_time = models.DateTimeField()
164
164
165 def __unicode__(self):
165 def __unicode__(self):
166 return self.title + ' (' + self.text.raw + ')'
166 return self.title + ' (' + self.text.raw + ')'
167
167
168 def _get_replies(self):
168 def _get_replies(self):
169 return Post.objects.filter(parent=self.id)
169 return Post.objects.filter(parent=self.id)
170
170
171 def get_reply_count(self):
171 def get_reply_count(self):
172 return len(self._get_replies())
172 return len(self._get_replies())
173
173
174 def get_images_count(self):
174 def get_images_count(self):
175 images_count = 1 if self.image else 0
175 images_count = 1 if self.image else 0
176 for reply in self._get_replies():
176 for reply in self._get_replies():
177 if reply.image:
177 if reply.image:
178 images_count += 1
178 images_count += 1
179
179
180 return images_count
180 return images_count
181
181
182 def get_gets_count(self):
182 def get_gets_count(self):
183 gets_count = 1 if self.is_get() else 0
183 gets_count = 1 if self.is_get() else 0
184 for reply in self._get_replies():
184 for reply in self._get_replies():
185 if reply.is_get():
185 if reply.is_get():
186 gets_count += 1
186 gets_count += 1
187
187
188 return gets_count
188 return gets_count
189
189
190 def is_get(self):
190 def is_get(self):
191 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
191 """If the post has pretty id (1, 1000, 77777), than it is called GET"""
192
192
193 first = self.id == 1
193 first = self.id == 1
194
194
195 # TODO Compile regexes
195 # TODO Compile regexes
196
196
197 id_str = str(self.id)
197 id_str = str(self.id)
198 pretty = re.match(r'\d0+', id_str)
198 pretty = re.match(r'^\d(0)+$', id_str)
199 same_digits = re.match(r'^(.)\1{1,}$', id_str)
199 same_digits = re.match(r'^(.)\1+$', id_str)
200 return first or pretty or same_digits
200 return first or pretty or same_digits
201
201
202
202
203 class Admin(models.Model):
203 class Admin(models.Model):
204 """
204 """
205 Model for admin users
205 Model for admin users
206 """
206 """
207 name = models.CharField(max_length=100)
207 name = models.CharField(max_length=100)
208 password = models.CharField(max_length=100)
208 password = models.CharField(max_length=100)
209
209
210 def __unicode__(self):
210 def __unicode__(self):
211 return self.name + '/' + '*' * len(self.password)
211 return self.name + '/' + '*' * len(self.password)
212
212
@@ -1,162 +1,168 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 .title {
11 .title {
12 font-weight: bold;
12 font-weight: bold;
13 color: #ffcc00;
13 color: #ffcc00;
14 }
14 }
15
15
16 .link, a {
16 .link, a {
17 color: #afdcec;
17 color: #afdcec;
18 }
18 }
19
19
20 .link:hover {
20 .link:hover {
21 color: #fff380;
21 color: #fff380;
22 }
22 }
23
23
24 .post_id {
24 .post_id {
25 color: #ffffff;
25 color: #ffffff;
26 }
26 }
27
27
28 .block {
28 .block {
29 display: inline-block;
29 display: inline-block;
30 vertical-align: top;
30 vertical-align: top;
31 }
31 }
32
32
33 .tag {
33 .tag {
34 color: #b4cfec;
34 color: #b4cfec;
35 }
35 }
36
36
37 .tag:hover {
37 .tag:hover {
38 color: #d0edb4;
38 color: #d0edb4;
39 }
39 }
40
40
41 .post_id {
41 .post_id {
42 color: #fff380;
42 color: #fff380;
43 }
43 }
44
44
45 .post {
45 .post {
46 background: #333;
46 background: #333;
47 margin: 5px;
47 margin: 5px;
48 padding: 10px;
48 padding: 10px;
49 border-radius: 5px;
49 border-radius: 5px;
50 clear: left;
50 clear: left;
51 }
51 }
52
52
53 .metadata {
53 .metadata {
54 padding: 2px;
54 padding: 5px;
55 margin-top: 10px;
55 margin-top: 10px;
56 border: solid 1px #666;
56 border: solid 1px #666;
57 font-size: 0.9em;
57 font-size: 0.9em;
58 color: #ddd;
58 color: #ddd;
59 display: table;
59 }
60 }
60
61
61 #navigation_panel {
62 #navigation_panel {
62 background: #444;
63 background: #444;
63 margin: 5px;
64 margin: 5px;
64 padding: 10px;
65 padding: 10px;
65 border-radius: 5px;
66 border-radius: 5px;
66 color: #eee;
67 color: #eee;
67 }
68 }
68
69
69 #navigation_panel .link {
70 #navigation_panel .link {
70 border-right: 1px solid #fff;
71 border-right: 1px solid #fff;
71 font-weight: bold;
72 font-weight: bold;
72 margin-right: 1ex;
73 margin-right: 1ex;
73 padding-right: 1ex;
74 padding-right: 1ex;
74 }
75 }
75 #navigation_panel .link:last-child {
76 #navigation_panel .link:last-child {
76 border-left: 1px solid #fff;
77 border-left: 1px solid #fff;
77 border-right: none;
78 border-right: none;
78 float: right;
79 float: right;
79 margin-left: 1ex;
80 margin-left: 1ex;
80 margin-right: 0;
81 margin-right: 0;
81 padding-left: 1ex;
82 padding-left: 1ex;
82 padding-right: 0;
83 padding-right: 0;
83 }
84 }
84
85
85 #navigation_panel::after, .post::after {
86 #navigation_panel::after, .post::after {
86 clear: both;
87 clear: both;
87 content: ".";
88 content: ".";
88 display: block;
89 display: block;
89 height: 0;
90 height: 0;
90 line-height: 0;
91 line-height: 0;
91 visibility: hidden;
92 visibility: hidden;
92 }
93 }
93
94
94 p {
95 p {
95 margin-top: .5em;
96 margin-top: .5em;
96 margin-bottom: .5em;
97 margin-bottom: .5em;
97 }
98 }
98
99
99 .post-form-w {
100 .post-form-w {
100 display: table;
101 display: table;
101 background: #333344;
102 background: #333344;
102 border-radius: 5px;
103 border-radius: 5px;
103 color: #fff;
104 color: #fff;
104 padding: 10px;
105 padding: 10px;
105 margin: 5px
106 margin: 5px
106 }
107 }
107
108
108 .form-row {
109 .form-row {
109 display: table-row;
110 display: table-row;
110 }
111 }
111
112
112 .form-label, .form-input {
113 .form-label, .form-input {
113 display: table-cell;
114 display: table-cell;
114 }
115 }
115
116
116 .form-label {
117 .form-label {
117 padding: .25em 1ex .25em 0;
118 padding: .25em 1ex .25em 0;
118 vertical-align: top;
119 vertical-align: top;
119 }
120 }
120
121
121 .form-input {
122 .form-input {
122 padding: .25em 0;
123 padding: .25em 0;
123 }
124 }
124
125
125 .post-form input, .post-form textarea {
126 .post-form input, .post-form textarea {
126 background: #333;
127 background: #333;
127 color: #fff;
128 color: #fff;
128 border: solid 1px;
129 border: solid 1px;
129 padding: 0;
130 padding: 0;
130 width: 100%;
131 width: 100%;
131 }
132 }
132
133
133 .form-submit {
134 .form-submit {
134 border-bottom: 2px solid #ddd;
135 border-bottom: 2px solid #ddd;
135 margin-bottom: .5em;
136 margin-bottom: .5em;
136 padding-bottom: .5em;
137 padding-bottom: .5em;
137 }
138 }
138
139
139 .form-title {
140 .form-title {
140 font-weight: bold;
141 font-weight: bold;
141 }
142 }
142
143
143 input[type="submit"] {
144 input[type="submit"] {
144 background: #222;
145 background: #222;
145 border: solid 1px #fff;
146 border: solid 1px #fff;
146 color: #fff;
147 color: #fff;
147 }
148 }
148
149
149 blockquote {
150 blockquote {
150 border-left: solid 2px;
151 border-left: solid 2px;
151 padding-left: 5px;
152 padding-left: 5px;
152 color: #B1FB17;
153 color: #B1FB17;
153 margin: 0;
154 margin: 0;
154 }
155 }
155
156
156 .post > .image {
157 .post > .image {
157 float: left; margin: 0 1ex .5ex 0;
158 float: left; margin: 0 1ex .5ex 0;
158 }
159 }
159
160
160 .post > .metadata {
161 .post > .metadata {
161 clear: left;
162 clear: left;
163 }
164
165 .get {
166 font-weight: bold;
167 color: #d55;
162 } No newline at end of file
168 }
@@ -1,174 +1,179 b''
1 * {
1 * {
2 font-size: inherit;
2 font-size: inherit;
3 margin: 0;
3 margin: 0;
4 padding: 0;
4 padding: 0;
5 }
5 }
6 html {
6 html {
7 background: #fff;
7 background: #fff;
8 color: #000;
8 color: #000;
9 font: medium sans-serif;
9 font: medium sans-serif;
10 }
10 }
11 a {
11 a {
12 color: inherit;
12 color: inherit;
13 text-decoration: underline;
13 text-decoration: underline;
14 }
14 }
15
15
16 #admin_panel {
16 #admin_panel {
17 background: #182F6F;
17 background: #182F6F;
18 color: #fff;
18 color: #fff;
19 padding: .5ex 1ex .5ex 1ex;
19 padding: .5ex 1ex .5ex 1ex;
20 }
20 }
21
21
22 #navigation_panel {
22 #navigation_panel {
23 background: #182F6F;
23 background: #182F6F;
24 color: #B4CFEC;
24 color: #B4CFEC;
25 margin-bottom: 1em;
25 margin-bottom: 1em;
26 padding: .5ex 1ex 1ex 1ex;
26 padding: .5ex 1ex 1ex 1ex;
27 }
27 }
28 #navigation_panel::after {
28 #navigation_panel::after {
29 clear: both;
29 clear: both;
30 content: ".";
30 content: ".";
31 display: block;
31 display: block;
32 height: 0;
32 height: 0;
33 line-height: 0;
33 line-height: 0;
34 visibility: hidden;
34 visibility: hidden;
35 }
35 }
36
36
37 #navigation_panel a:link, #navigation_panel a:visited, #navigation_panel a:hover {
37 #navigation_panel a:link, #navigation_panel a:visited, #navigation_panel a:hover {
38 text-decoration: none;
38 text-decoration: none;
39 }
39 }
40
40
41 #navigation_panel .link {
41 #navigation_panel .link {
42 border-right: 1px solid #fff;
42 border-right: 1px solid #fff;
43 color: #fff;
43 color: #fff;
44 font-weight: bold;
44 font-weight: bold;
45 margin-right: 1ex;
45 margin-right: 1ex;
46 padding-right: 1ex;
46 padding-right: 1ex;
47 }
47 }
48 #navigation_panel .link:last-child {
48 #navigation_panel .link:last-child {
49 border-left: 1px solid #fff;
49 border-left: 1px solid #fff;
50 border-right: none;
50 border-right: none;
51 float: right;
51 float: right;
52 margin-left: 1ex;
52 margin-left: 1ex;
53 margin-right: 0;
53 margin-right: 0;
54 padding-left: 1ex;
54 padding-left: 1ex;
55 padding-right: 0;
55 padding-right: 0;
56 }
56 }
57
57
58 #navigation_panel .tag {
58 #navigation_panel .tag {
59 color: #fff;
59 color: #fff;
60 }
60 }
61
61
62 .title {
62 .title {
63 color: #182F6F;
63 color: #182F6F;
64 font-weight: bold;
64 font-weight: bold;
65 }
65 }
66
66
67 .post-form-w {
67 .post-form-w {
68 background: #182F6F;
68 background: #182F6F;
69 border-radius: 1ex;
69 border-radius: 1ex;
70 color: #fff;
70 color: #fff;
71 margin: 1em 1ex;
71 margin: 1em 1ex;
72 padding: 1ex;
72 padding: 1ex;
73 }
73 }
74 .post-form {
74 .post-form {
75 display: table;
75 display: table;
76 border-collapse: collapse;
76 border-collapse: collapse;
77 width: 100%;
77 width: 100%;
78
78
79 }
79 }
80 .form-row {
80 .form-row {
81 display: table-row;
81 display: table-row;
82 }
82 }
83 .form-label, .form-input {
83 .form-label, .form-input {
84 display: table-cell;
84 display: table-cell;
85 vertical-align: top;
85 vertical-align: top;
86 }
86 }
87 .form-label {
87 .form-label {
88 padding: .25em 1ex .25em 0;
88 padding: .25em 1ex .25em 0;
89 }
89 }
90 .form-input {
90 .form-input {
91 padding: .25em 0;
91 padding: .25em 0;
92 }
92 }
93 .form-input > * {
93 .form-input > * {
94 background: #fff;
94 background: #fff;
95 color: #000;
95 color: #000;
96 border: none;
96 border: none;
97 padding: 0;
97 padding: 0;
98 resize: vertical;
98 resize: vertical;
99 width: 100%;
99 width: 100%;
100 }
100 }
101 .form-submit {
101 .form-submit {
102 border-bottom: 1px solid #666;
102 border-bottom: 1px solid #666;
103 margin-bottom: .5em;
103 margin-bottom: .5em;
104 padding-bottom: .5em;
104 padding-bottom: .5em;
105 }
105 }
106 .form-title {
106 .form-title {
107 font-weight: bold;
107 font-weight: bold;
108 margin-bottom: .5em;
108 margin-bottom: .5em;
109 }
109 }
110 .post-form .settings_item {
110 .post-form .settings_item {
111 margin: .5em 0;
111 margin: .5em 0;
112 }
112 }
113 .form-submit input {
113 .form-submit input {
114 margin-top: .5em;
114 margin-top: .5em;
115 padding: .2em 1ex;
115 padding: .2em 1ex;
116 }
116 }
117 .form-label {
117 .form-label {
118 text-align: right;
118 text-align: right;
119 }
119 }
120
120
121 .block {
121 .block {
122 display: inline-block;
122 display: inline-block;
123 vertical-align: top;
123 vertical-align: top;
124 }
124 }
125
125
126 .post_id {
126 .post_id {
127 color: #a00;
127 color: #a00;
128 }
128 }
129
129
130 .post {
130 .post {
131 background: #FFF;
131 background: #FFF;
132 border-bottom: 1px solid #182F6F;
132 border-bottom: 1px solid #182F6F;
133 margin: 0 1ex 1em 1ex;
133 margin: 0 1ex 1em 1ex;
134 overflow-x: auto;
134 overflow-x: auto;
135 padding-bottom: 1em;
135 padding-bottom: 1em;
136 }
136 }
137
137
138 .metadata {
138 .metadata {
139 background: #C0E4E8;
139 background: #C0E4E8;
140 border: 1px solid #7F9699;
140 border: 1px solid #7F9699;
141 border-radius: .4ex;
141 border-radius: .4ex;
142 display: table;
142 display: table;
143 margin-top: .5em;
143 margin-top: .5em;
144 padding: .4em;
144 padding: .4em;
145 }
145 }
146
146
147 .post ul, .post ol {
147 .post ul, .post ol {
148 margin: .5em 0 .5em 3ex;
148 margin: .5em 0 .5em 3ex;
149 }
149 }
150 .post li {
150 .post li {
151 margin: .2em 0;
151 margin: .2em 0;
152 }
152 }
153 .post p {
153 .post p {
154 margin: .5em 0;
154 margin: .5em 0;
155 }
155 }
156 .post blockquote {
156 .post blockquote {
157 border-left: 3px solid #182F6F;
157 border-left: 3px solid #182F6F;
158 margin: .5em 0 .5em 3ex;
158 margin: .5em 0 .5em 3ex;
159 padding-left: 1ex;
159 padding-left: 1ex;
160 }
160 }
161 .post blockquote > blockquote {
161 .post blockquote > blockquote {
162 padding-top: .1em;
162 padding-top: .1em;
163 }
163 }
164
164
165 .post > .image {
165 .post > .image {
166 float: left;
166 float: left;
167 margin-right: 1ex;
167 margin-right: 1ex;
168 }
168 }
169 .post > .metadata {
169 .post > .metadata {
170 clear: left;
170 clear: left;
171 }
171 }
172
172 .post {
173 .post {
173 clear: left;
174 clear: left;
174 }
175 }
176
177 .post > .message .get {
178 color: #182F6F; font-weight: bold;
179 } No newline at end of file
@@ -1,76 +1,81 b''
1 {% extends "base.html" %}
1 {% extends "base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load markup %}
4 {% load markup %}
5
5
6 {% block head %}
6 {% block head %}
7 <title>Neboard</title>
7 <title>Neboard</title>
8 {% endblock %}
8 {% endblock %}
9
9
10 {% block content %}
10 {% block content %}
11
11
12 {% if posts %}
12 {% if posts %}
13 {% for post in posts %}
13 {% for post in posts %}
14 <a name="{{ post.id }}"></a>
14 <a name="{{ post.id }}"></a>
15 <div class="post">
15 <div class="post">
16 {% if post.image %}
16 {% if post.image %}
17 <div class="image">
17 <div class="image">
18 <a href="{{ post.image.url }}"><img
18 <a href="{{ post.image.url }}"><img
19 src="{{ post.image.url_200x150 }}" />
19 src="{{ post.image.url_200x150 }}" />
20 </a>
20 </a>
21 </div>
21 </div>
22 {% endif %}
22 {% endif %}
23 <div class="message">
23 <div class="message">
24 <span class="title">{{ post.title }}</span>
24 <span class="title">{{ post.title }}</span>
25 <a class="post_id" href="#{{ post.id }}">
25 <a class="post_id" href="#{{ post.id }}">
26 (#{{ post.id }})</a>
26 (#{{ post.id }})</a>
27 [{{ post.pub_time }}]
27 [{{ post.pub_time }}]
28 {% if post.is_get %}
29 <span class="get">
30 {% trans "Get!" %}
31 </span>
32 {% endif %}
28 {% autoescape off %}
33 {% autoescape off %}
29 {{ post.text.rendered }}
34 {{ post.text.rendered }}
30 {% endautoescape %}
35 {% endautoescape %}
31 </div>
36 </div>
32 {% if post.tags.all %}
37 {% if post.tags.all %}
33 <div class="metadata">
38 <div class="metadata">
34 <span class="tags">{% trans 'Tags' %}:
39 <span class="tags">{% trans 'Tags' %}:
35 {% for tag in post.tags.all %}
40 {% for tag in post.tags.all %}
36 <a class="tag" href="{% url 'tag' tag.name %}">
41 <a class="tag" href="{% url 'tag' tag.name %}">
37 {{ tag.name }}</a>
42 {{ tag.name }}</a>
38 {% endfor %}
43 {% endfor %}
39 </span>
44 </span>
40 </div>
45 </div>
41 {% endif %}
46 {% endif %}
42 </div>
47 </div>
43 {% endfor %}
48 {% endfor %}
44 {% else %}
49 {% else %}
45 No threads found.
50 No threads found.
46 <hr />
51 <hr />
47 {% endif %}
52 {% endif %}
48
53
49 <form enctype="multipart/form-data" method="post">{% csrf_token %}
54 <form enctype="multipart/form-data" method="post">{% csrf_token %}
50 <div class="post-form-w">
55 <div class="post-form-w">
51 <div class="form-title">{% trans "Reply to thread" %}</div>
56 <div class="form-title">{% trans "Reply to thread" %}</div>
52 <div class="post-form">
57 <div class="post-form">
53 <div class="form-row">
58 <div class="form-row">
54 <div class="form-label">{% trans 'Title' %}</div>
59 <div class="form-label">{% trans 'Title' %}</div>
55 <div class="form-input">{{ form.title }}</div>
60 <div class="form-input">{{ form.title }}</div>
56 </div>
61 </div>
57 <div class="form-row">
62 <div class="form-row">
58 <div class="form-label">{% trans 'Text' %}</div>
63 <div class="form-label">{% trans 'Text' %}</div>
59 <div class="form-input">{{ form.text }}</div>
64 <div class="form-input">{{ form.text }}</div>
60 </div>
65 </div>
61 <div class="form-row">
66 <div class="form-row">
62 <div class="form-label">{% trans 'Image' %}</div>
67 <div class="form-label">{% trans 'Image' %}</div>
63 <div class="form-input">{{ form.image }}</div>
68 <div class="form-input">{{ form.image }}</div>
64 </div>
69 </div>
65 </div>
70 </div>
66 <div class="form-submit"><input type="submit"
71 <div class="form-submit"><input type="submit"
67 value="{% trans "Post" %}"/></div>
72 value="{% trans "Post" %}"/></div>
68 <div>Use <a
73 <div>Use <a
69 href="http://daringfireball.net/projects/markdown/basics">
74 href="http://daringfireball.net/projects/markdown/basics">
70 markdown</a> syntax for posting.</div>
75 markdown</a> syntax for posting.</div>
71 <div>Example: *<i>italic</i>*, **<b>bold</b>**</div>
76 <div>Example: *<i>italic</i>*, **<b>bold</b>**</div>
72 <div>Insert quotes with "&gt;"</div>
77 <div>Insert quotes with "&gt;"</div>
73 </div>
78 </div>
74 </form>
79 </form>
75
80
76 {% endblock %}
81 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now