##// END OF EJS Templates
Since we show sections on the landing page now, always show all tags in the tags view
neko259 -
r1741:58ced8b0 default
parent child Browse files
Show More
@@ -1,145 +1,145 b''
1 import hashlib
1 import hashlib
2 from boards.models.attachment import FILE_TYPES_IMAGE
2 from boards.models.attachment import FILE_TYPES_IMAGE
3 from django.template.loader import render_to_string
3 from django.template.loader import render_to_string
4 from django.db import models
4 from django.db import models
5 from django.db.models import Count
5 from django.db.models import Count
6 from django.core.urlresolvers import reverse
6 from django.core.urlresolvers import reverse
7
7
8 from boards.models import Attachment
8 from boards.models import Attachment
9 from boards.models.base import Viewable
9 from boards.models.base import Viewable
10 from boards.models.thread import STATUS_ACTIVE, STATUS_BUMPLIMIT, STATUS_ARCHIVE
10 from boards.models.thread import STATUS_ACTIVE, STATUS_BUMPLIMIT, STATUS_ARCHIVE
11 from boards.utils import cached_result
11 from boards.utils import cached_result
12 import boards
12 import boards
13
13
14 __author__ = 'neko259'
14 __author__ = 'neko259'
15
15
16
16
17 RELATED_TAGS_COUNT = 5
17 RELATED_TAGS_COUNT = 5
18
18
19
19
20 class TagManager(models.Manager):
20 class TagManager(models.Manager):
21
21
22 def get_not_empty_tags(self):
22 def get_not_empty_tags(self):
23 """
23 """
24 Gets tags that have non-archived threads.
24 Gets tags that have non-archived threads.
25 """
25 """
26
26
27 return self.annotate(num_threads=Count('thread_tags')).filter(num_threads__gt=0)\
27 return self.annotate(num_threads=Count('thread_tags')).filter(num_threads__gt=0)\
28 .order_by('-required', 'name')
28 .order_by('name')
29
29
30 def get_tag_url_list(self, tags: list) -> str:
30 def get_tag_url_list(self, tags: list) -> str:
31 """
31 """
32 Gets a comma-separated list of tag links.
32 Gets a comma-separated list of tag links.
33 """
33 """
34
34
35 return ', '.join([tag.get_view() for tag in tags])
35 return ', '.join([tag.get_view() for tag in tags])
36
36
37
37
38 class Tag(models.Model, Viewable):
38 class Tag(models.Model, Viewable):
39 """
39 """
40 A tag is a text node assigned to the thread. The tag serves as a board
40 A tag is a text node assigned to the thread. The tag serves as a board
41 section. There can be multiple tags for each thread
41 section. There can be multiple tags for each thread
42 """
42 """
43
43
44 objects = TagManager()
44 objects = TagManager()
45
45
46 class Meta:
46 class Meta:
47 app_label = 'boards'
47 app_label = 'boards'
48 ordering = ('name',)
48 ordering = ('name',)
49
49
50 name = models.CharField(max_length=100, db_index=True, unique=True)
50 name = models.CharField(max_length=100, db_index=True, unique=True)
51 required = models.BooleanField(default=False, db_index=True)
51 required = models.BooleanField(default=False, db_index=True)
52 description = models.TextField(blank=True)
52 description = models.TextField(blank=True)
53
53
54 parent = models.ForeignKey('Tag', null=True, blank=True,
54 parent = models.ForeignKey('Tag', null=True, blank=True,
55 related_name='children')
55 related_name='children')
56
56
57 def __str__(self):
57 def __str__(self):
58 return self.name
58 return self.name
59
59
60 def is_empty(self) -> bool:
60 def is_empty(self) -> bool:
61 """
61 """
62 Checks if the tag has some threads.
62 Checks if the tag has some threads.
63 """
63 """
64
64
65 return self.get_thread_count() == 0
65 return self.get_thread_count() == 0
66
66
67 def get_thread_count(self, status=None) -> int:
67 def get_thread_count(self, status=None) -> int:
68 threads = self.get_threads()
68 threads = self.get_threads()
69 if status is not None:
69 if status is not None:
70 threads = threads.filter(status=status)
70 threads = threads.filter(status=status)
71 return threads.count()
71 return threads.count()
72
72
73 def get_active_thread_count(self) -> int:
73 def get_active_thread_count(self) -> int:
74 return self.get_thread_count(status=STATUS_ACTIVE)
74 return self.get_thread_count(status=STATUS_ACTIVE)
75
75
76 def get_bumplimit_thread_count(self) -> int:
76 def get_bumplimit_thread_count(self) -> int:
77 return self.get_thread_count(status=STATUS_BUMPLIMIT)
77 return self.get_thread_count(status=STATUS_BUMPLIMIT)
78
78
79 def get_archived_thread_count(self) -> int:
79 def get_archived_thread_count(self) -> int:
80 return self.get_thread_count(status=STATUS_ARCHIVE)
80 return self.get_thread_count(status=STATUS_ARCHIVE)
81
81
82 def get_absolute_url(self):
82 def get_absolute_url(self):
83 return reverse('tag', kwargs={'tag_name': self.name})
83 return reverse('tag', kwargs={'tag_name': self.name})
84
84
85 def get_threads(self):
85 def get_threads(self):
86 return self.thread_tags.order_by('-bump_time')
86 return self.thread_tags.order_by('-bump_time')
87
87
88 def is_required(self):
88 def is_required(self):
89 return self.required
89 return self.required
90
90
91 def get_view(self):
91 def get_view(self):
92 link = '<a class="tag" href="{}">{}</a>'.format(
92 link = '<a class="tag" href="{}">{}</a>'.format(
93 self.get_absolute_url(), self.name)
93 self.get_absolute_url(), self.name)
94 if self.is_required():
94 if self.is_required():
95 link = '<b>{}</b>'.format(link)
95 link = '<b>{}</b>'.format(link)
96 return link
96 return link
97
97
98 @cached_result()
98 @cached_result()
99 def get_post_count(self):
99 def get_post_count(self):
100 return self.get_threads().aggregate(num_posts=Count('replies'))['num_posts']
100 return self.get_threads().aggregate(num_posts=Count('replies'))['num_posts']
101
101
102 def get_description(self):
102 def get_description(self):
103 return self.description
103 return self.description
104
104
105 def get_random_image_post(self, status=[STATUS_ACTIVE, STATUS_BUMPLIMIT]):
105 def get_random_image_post(self, status=[STATUS_ACTIVE, STATUS_BUMPLIMIT]):
106 posts = boards.models.Post.objects.filter(attachments__mimetype__in=FILE_TYPES_IMAGE)\
106 posts = boards.models.Post.objects.filter(attachments__mimetype__in=FILE_TYPES_IMAGE)\
107 .annotate(images_count=Count(
107 .annotate(images_count=Count(
108 'attachments')).filter(images_count__gt=0, thread__tags__in=[self])
108 'attachments')).filter(images_count__gt=0, thread__tags__in=[self])
109 if status is not None:
109 if status is not None:
110 posts = posts.filter(thread__status__in=status)
110 posts = posts.filter(thread__status__in=status)
111 return posts.order_by('?').first()
111 return posts.order_by('?').first()
112
112
113 def get_first_letter(self):
113 def get_first_letter(self):
114 return self.name and self.name[0] or ''
114 return self.name and self.name[0] or ''
115
115
116 def get_related_tags(self):
116 def get_related_tags(self):
117 return set(Tag.objects.filter(thread_tags__in=self.get_threads()).exclude(
117 return set(Tag.objects.filter(thread_tags__in=self.get_threads()).exclude(
118 id=self.id).order_by('?')[:RELATED_TAGS_COUNT])
118 id=self.id).order_by('?')[:RELATED_TAGS_COUNT])
119
119
120 @cached_result()
120 @cached_result()
121 def get_color(self):
121 def get_color(self):
122 """
122 """
123 Gets color hashed from the tag name.
123 Gets color hashed from the tag name.
124 """
124 """
125 return hashlib.md5(self.name.encode()).hexdigest()[:6]
125 return hashlib.md5(self.name.encode()).hexdigest()[:6]
126
126
127 def get_parent(self):
127 def get_parent(self):
128 return self.parent
128 return self.parent
129
129
130 def get_all_parents(self):
130 def get_all_parents(self):
131 parents = list()
131 parents = list()
132 parent = self.get_parent()
132 parent = self.get_parent()
133 if parent and parent not in parents:
133 if parent and parent not in parents:
134 parents.insert(0, parent)
134 parents.insert(0, parent)
135 parents = parent.get_all_parents() + parents
135 parents = parent.get_all_parents() + parents
136
136
137 return parents
137 return parents
138
138
139 def get_children(self):
139 def get_children(self):
140 return self.children
140 return self.children
141
141
142 def get_images(self):
142 def get_images(self):
143 return Attachment.objects.filter(
143 return Attachment.objects.filter(
144 attachment_posts__thread__tags__in=[self]).filter(
144 attachment_posts__thread__tags__in=[self]).filter(
145 mimetype__in=FILE_TYPES_IMAGE).order_by('-attachment_posts__pub_time')
145 mimetype__in=FILE_TYPES_IMAGE).order_by('-attachment_posts__pub_time')
@@ -1,209 +1,208 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load board %}
4 {% load board %}
5 {% load static %}
5 {% load static %}
6 {% load tz %}
6 {% load tz %}
7
7
8 {% block head %}
8 {% block head %}
9 <meta name="robots" content="noindex">
9 <meta name="robots" content="noindex">
10
10
11 {% if tag %}
11 {% if tag %}
12 <title>{{ tag.name }} - {{ site_name }}</title>
12 <title>{{ tag.name }} - {{ site_name }}</title>
13 {% else %}
13 {% else %}
14 <title>{{ site_name }}</title>
14 <title>{{ site_name }}</title>
15 {% endif %}
15 {% endif %}
16
16
17 {% if prev_page_link %}
17 {% if prev_page_link %}
18 <link rel="prev" href="{{ prev_page_link }}" />
18 <link rel="prev" href="{{ prev_page_link }}" />
19 {% endif %}
19 {% endif %}
20 {% if next_page_link %}
20 {% if next_page_link %}
21 <link rel="next" href="{{ next_page_link }}" />
21 <link rel="next" href="{{ next_page_link }}" />
22 {% endif %}
22 {% endif %}
23
23
24 {% endblock %}
24 {% endblock %}
25
25
26 {% block content %}
26 {% block content %}
27
27
28 {% get_current_language as LANGUAGE_CODE %}
28 {% get_current_language as LANGUAGE_CODE %}
29 {% get_current_timezone as TIME_ZONE %}
29 {% get_current_timezone as TIME_ZONE %}
30
30
31 {% for banner in banners %}
31 {% for banner in banners %}
32 <div class="post">
32 <div class="post">
33 <div class="title">{{ banner.title }}</div>
33 <div class="title">{{ banner.title }}</div>
34 <div>{{ banner.get_text|safe }}</div>
34 <div>{{ banner.get_text|safe }}</div>
35 <div>{% trans 'Details' %}: <a href="{{ banner.post.get_absolute_url }}">>>{{ banner.post.id }}</a></div>
35 <div>{% trans 'Details' %}: <a href="{{ banner.post.get_absolute_url }}">>>{{ banner.post.id }}</a></div>
36 </div>
36 </div>
37 {% endfor %}
37 {% endfor %}
38
38
39 {% if tag %}
39 {% if tag %}
40 <div class="tag_info" style="border-bottom: solid .5ex #{{ tag.get_color }}">
40 <div class="tag_info" style="border-bottom: solid .5ex #{{ tag.get_color }}">
41 {% if random_image_post %}
41 {% if random_image_post %}
42 <div class="tag-image">
42 <div class="tag-image">
43 {% with image=random_image_post.get_first_image %}
43 {% with image=random_image_post.get_first_image %}
44 <a href="{{ random_image_post.get_absolute_url }}"><img
44 <a href="{{ random_image_post.get_absolute_url }}"><img
45 src="{{ image.get_thumb_url }}"
45 src="{{ image.get_thumb_url }}"
46 width="{{ image.get_preview_size.0 }}"
46 width="{{ image.get_preview_size.0 }}"
47 height="{{ image.get_preview_size.1 }}"
47 height="{{ image.get_preview_size.1 }}"
48 alt="{{ random_image_post.id }}"/></a>
48 alt="{{ random_image_post.id }}"/></a>
49 {% endwith %}
49 {% endwith %}
50 </div>
50 </div>
51 {% endif %}
51 {% endif %}
52 <div class="tag-text-data">
52 <div class="tag-text-data">
53 <h2>
53 <h2>
54 /{{ tag.get_view|safe }}/
54 /{{ tag.get_view|safe }}/
55 </h2>
55 </h2>
56 {% if perms.change_tag %}
56 {% if perms.change_tag %}
57 <div class="moderator_info"><a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></div>
57 <div class="moderator_info"><a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></div>
58 {% endif %}
58 {% endif %}
59 <p>
59 <p>
60 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
60 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
61 {% if is_favorite %}
61 {% if is_favorite %}
62 <button name="method" value="unsubscribe" class="fav">★ {% trans "Remove from favorites" %}</button>
62 <button name="method" value="unsubscribe" class="fav">★ {% trans "Remove from favorites" %}</button>
63 {% else %}
63 {% else %}
64 <button name="method" value="subscribe" class="not_fav">★ {% trans "Add to favorites" %}</button>
64 <button name="method" value="subscribe" class="not_fav">★ {% trans "Add to favorites" %}</button>
65 {% endif %}
65 {% endif %}
66 </form>
66 </form>
67 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
67 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
68 {% if is_hidden %}
68 {% if is_hidden %}
69 <button name="method" value="unhide" class="fav">{% trans "Show" %}</button>
69 <button name="method" value="unhide" class="fav">{% trans "Show" %}</button>
70 {% else %}
70 {% else %}
71 <button name="method" value="hide" class="not_fav">{% trans "Hide" %}</button>
71 <button name="method" value="hide" class="not_fav">{% trans "Hide" %}</button>
72 {% endif %}
72 {% endif %}
73 </form>
73 </form>
74 <a href="{% url 'tag_gallery' tag.name %}">{% trans 'Gallery' %}</a>
74 <a href="{% url 'tag_gallery' tag.name %}">{% trans 'Gallery' %}</a>
75 </p>
75 </p>
76 {% if tag.get_description %}
76 {% if tag.get_description %}
77 <p>{{ tag.get_description|safe }}</p>
77 <p>{{ tag.get_description|safe }}</p>
78 {% endif %}
78 {% endif %}
79 <p>
79 <p>
80 {% with active_count=tag.get_active_thread_count bumplimit_count=tag.get_bumplimit_thread_count archived_count=tag.get_archived_thread_count %}
80 {% with active_count=tag.get_active_thread_count bumplimit_count=tag.get_bumplimit_thread_count archived_count=tag.get_archived_thread_count %}
81 {% if active_count %}
81 {% if active_count %}
82 ● {{ active_count }}&ensp;
82 ● {{ active_count }}&ensp;
83 {% endif %}
83 {% endif %}
84 {% if bumplimit_count %}
84 {% if bumplimit_count %}
85 ◍ {{ bumplimit_count }}&ensp;
85 ◍ {{ bumplimit_count }}&ensp;
86 {% endif %}
86 {% endif %}
87 {% if archived_count %}
87 {% if archived_count %}
88 ○ {{ archived_count }}&ensp;
88 ○ {{ archived_count }}&ensp;
89 {% endif %}
89 {% endif %}
90 {% endwith %}
90 {% endwith %}
91 ♥ {{ tag.get_post_count }}
91 ♥ {{ tag.get_post_count }}
92 </p>
92 </p>
93 {% if tag.get_all_parents %}
93 {% if tag.get_all_parents %}
94 <p>
94 <p>
95 {% for parent in tag.get_all_parents %}
95 {% for parent in tag.get_all_parents %}
96 {{ parent.get_view|safe }} &gt;
96 {{ parent.get_view|safe }} &gt;
97 {% endfor %}
97 {% endfor %}
98 {{ tag.get_view|safe }}
98 {{ tag.get_view|safe }}
99 </p>
99 </p>
100 {% endif %}
100 {% endif %}
101 {% if tag.get_children.all %}
101 {% if tag.get_children.all %}
102 <p>
102 <p>
103 {% trans "Subsections: " %}
103 {% trans "Subsections: " %}
104 {% for child in tag.get_children.all %}
104 {% for child in tag.get_children.all %}
105 {{ child.get_view|safe }}{% if not forloop.last%}, {% endif %}
105 {{ child.get_view|safe }}{% if not forloop.last%}, {% endif %}
106 {% endfor %}
106 {% endfor %}
107 </p>
107 </p>
108 {% endif %}
108 {% endif %}
109 </div>
109 </div>
110 </div>
110 </div>
111 {% endif %}
111 {% endif %}
112
112
113 {% if threads %}
113 {% if threads %}
114 {% if prev_page_link %}
114 {% if prev_page_link %}
115 <div class="page_link">
115 <div class="page_link">
116 <a href="{{ prev_page_link }}">&lt;&lt; {% trans "Previous page" %} &lt;&lt;</a>
116 <a href="{{ prev_page_link }}">&lt;&lt; {% trans "Previous page" %} &lt;&lt;</a>
117 </div>
117 </div>
118 {% endif %}
118 {% endif %}
119
119
120 {% for thread in threads %}
120 {% for thread in threads %}
121 <div class="thread">
121 <div class="thread">
122 {% post_view thread.get_opening_post thread=thread truncated=True need_open_link=True %}
122 {% post_view thread.get_opening_post thread=thread truncated=True need_open_link=True %}
123 {% if not thread.archived %}
123 {% if not thread.archived %}
124 {% with last_replies=thread.get_last_replies %}
124 {% with last_replies=thread.get_last_replies %}
125 {% if last_replies %}
125 {% if last_replies %}
126 {% with skipped_replies_count=thread.get_skipped_replies_count %}
126 {% with skipped_replies_count=thread.get_skipped_replies_count %}
127 {% if skipped_replies_count %}
127 {% if skipped_replies_count %}
128 <div class="skipped_replies">
128 <div class="skipped_replies">
129 <a href="{% url 'thread' thread.get_opening_post_id %}">
129 <a href="{% url 'thread' thread.get_opening_post_id %}">
130 {% blocktrans count count=skipped_replies_count %}Skipped {{ count }} reply. Open thread to see all replies.{% plural %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
130 {% blocktrans count count=skipped_replies_count %}Skipped {{ count }} reply. Open thread to see all replies.{% plural %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
131 </a>
131 </a>
132 </div>
132 </div>
133 {% endif %}
133 {% endif %}
134 {% endwith %}
134 {% endwith %}
135 <div class="last-replies">
135 <div class="last-replies">
136 {% for post in last_replies %}
136 {% for post in last_replies %}
137 {% post_view post truncated=True %}
137 {% post_view post truncated=True %}
138 {% endfor %}
138 {% endfor %}
139 </div>
139 </div>
140 {% endif %}
140 {% endif %}
141 {% endwith %}
141 {% endwith %}
142 {% endif %}
142 {% endif %}
143 </div>
143 </div>
144 {% endfor %}
144 {% endfor %}
145
145
146 {% if next_page_link %}
146 {% if next_page_link %}
147 <div class="page_link">
147 <div class="page_link">
148 <a href="{{ next_page_link }}">&gt;&gt; {% trans "Next page" %} &gt;&gt;</a>
148 <a href="{{ next_page_link }}">&gt;&gt; {% trans "Next page" %} &gt;&gt;</a>
149 </div>
149 </div>
150 {% endif %}
150 {% endif %}
151 {% else %}
151 {% else %}
152 <div class="post">
152 <div class="post">
153 {% trans 'No threads exist. Create the first one!' %}</div>
153 {% trans 'No threads exist. Create the first one!' %}</div>
154 {% endif %}
154 {% endif %}
155
155
156 <div class="post-form-w">
156 <div class="post-form-w">
157 <script src="{% static 'js/panel.js' %}"></script>
157 <script src="{% static 'js/panel.js' %}"></script>
158 <div class="post-form" data-hasher="{% static 'js/3party/sha256.js' %}"
158 <div class="post-form" data-hasher="{% static 'js/3party/sha256.js' %}"
159 data-pow-script="{% static 'js/proof_of_work.js' %}">
159 data-pow-script="{% static 'js/proof_of_work.js' %}">
160 <div class="form-title">{% trans "Create new thread" %}</div>
160 <div class="form-title">{% trans "Create new thread" %}</div>
161 <div class="swappable-form-full">
161 <div class="swappable-form-full">
162 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
162 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
163 {{ form.as_div }}
163 {{ form.as_div }}
164 <div class="form-submit">
164 <div class="form-submit">
165 <input type="submit" value="{% trans "Post" %}"/>
165 <input type="submit" value="{% trans "Post" %}"/>
166 <button id="preview-button" type="button" onclick="return false;">{% trans 'Preview' %}</button>
166 <button id="preview-button" type="button" onclick="return false;">{% trans 'Preview' %}</button>
167 <button id="file-source-button" type="button" onclick="return false;">{% trans 'Change file source' %}</button>
167 <button id="file-source-button" type="button" onclick="return false;">{% trans 'Change file source' %}</button>
168 </div>
168 </div>
169 </form>
169 </form>
170 </div>
170 </div>
171 <div>
171 <div>
172 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
172 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
173 {% with size=max_file_size|filesizeformat %}
173 {% with size=max_file_size|filesizeformat %}
174 {% blocktrans %}Max file size is {{ size }}.{% endblocktrans %}
174 {% blocktrans %}Max file size is {{ size }}.{% endblocktrans %}
175 {% endwith %}
175 {% endwith %}
176 </div>
176 </div>
177 <div id="preview-text"></div>
177 <div id="preview-text"></div>
178 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
178 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
179 <div><a href="{% url "tags" "required" %}">{% trans 'Tags' %}</a></div>
180 </div>
179 </div>
181 </div>
180 </div>
182
181
183 <script src="{% static 'js/form.js' %}"></script>
182 <script src="{% static 'js/form.js' %}"></script>
184 <script src="{% static 'js/3party/jquery.blockUI.js' %}"></script>
183 <script src="{% static 'js/3party/jquery.blockUI.js' %}"></script>
185 <script src="{% static 'js/thread_create.js' %}"></script>
184 <script src="{% static 'js/thread_create.js' %}"></script>
186
185
187 {% endblock %}
186 {% endblock %}
188
187
189 {% block metapanel %}
188 {% block metapanel %}
190
189
191 <span class="metapanel">
190 <span class="metapanel">
192 {% trans "Pages:" %}
191 {% trans "Pages:" %}
193 [
192 [
194 {% with dividers=paginator.get_dividers %}
193 {% with dividers=paginator.get_dividers %}
195 {% for page in paginator.get_divided_range %}
194 {% for page in paginator.get_divided_range %}
196 {% if page in dividers %}
195 {% if page in dividers %}
197 …,
196 …,
198 {% endif %}
197 {% endif %}
199 <a
198 <a
200 {% ifequal page current_page.number %}
199 {% ifequal page current_page.number %}
201 class="current_page"
200 class="current_page"
202 {% endifequal %}
201 {% endifequal %}
203 href="{% page_url paginator page %}">{{ page }}</a>{% if not forloop.last %},{% endif %}
202 href="{% page_url paginator page %}">{{ page }}</a>{% if not forloop.last %},{% endif %}
204 {% endfor %}
203 {% endfor %}
205 {% endwith %}
204 {% endwith %}
206 ]
205 ]
207 </span>
206 </span>
208
207
209 {% endblock %}
208 {% endblock %}
@@ -1,94 +1,94 b''
1 {% load staticfiles %}
1 {% load staticfiles %}
2 {% load i18n %}
2 {% load i18n %}
3 {% load l10n %}
3 {% load l10n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5
5
6 <!DOCTYPE html>
6 <!DOCTYPE html>
7 <html>
7 <html>
8 <head>
8 <head>
9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
9 <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}" media="all"/>
10 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/highlight.css' %}" media="all"/>
10 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/highlight.css' %}" media="all"/>
11 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/jquery-ui.min.css' %}" media="all"/>
11 <link rel="stylesheet" type="text/css" href="{% static 'css/3party/jquery-ui.min.css' %}" media="all"/>
12 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
12 <link rel="stylesheet" type="text/css" href="{% static theme_css %}" media="all"/>
13
13
14 {% if rss_url %}
14 {% if rss_url %}
15 <link rel="alternate" type="application/rss+xml" href="{{ rss_url }}" title="{% trans 'Feed' %}"/>
15 <link rel="alternate" type="application/rss+xml" href="{{ rss_url }}" title="{% trans 'Feed' %}"/>
16 {% endif %}
16 {% endif %}
17
17
18 <link rel="icon" type="image/png"
18 <link rel="icon" type="image/png"
19 href="{% static 'favicon.png' %}">
19 href="{% static 'favicon.png' %}">
20
20
21 <meta name="viewport" content="width=device-width, initial-scale=1"/>
21 <meta name="viewport" content="width=device-width, initial-scale=1"/>
22 <meta charset="utf-8"/>
22 <meta charset="utf-8"/>
23
23
24 {% block head %}{% endblock %}
24 {% block head %}{% endblock %}
25 </head>
25 </head>
26 <body data-image-viewer="{{ image_viewer }}"
26 <body data-image-viewer="{{ image_viewer }}"
27 data-pow-difficulty="{{ pow_difficulty }}"
27 data-pow-difficulty="{{ pow_difficulty }}"
28 data-update-script="{% static 'js/updates.js' %}">
28 data-update-script="{% static 'js/updates.js' %}">
29 <script src="{% static 'js/jquery-2.2.0.min.js' %}"></script>
29 <script src="{% static 'js/jquery-2.2.0.min.js' %}"></script>
30
30
31 <header class="navigation_panel">
31 <header class="navigation_panel">
32 <a class="link" href="{% url 'landing' %}">{{ site_name }}</a>
32 <a class="link" href="{% url 'landing' %}">{{ site_name }}</a>
33 <a href="{% url 'index' %}" title="{% trans "All threads" %}">~~~</a>,
33 <a href="{% url 'index' %}" title="{% trans "All threads" %}">~~~</a>,
34 {% if tags_str %}
34 {% if tags_str %}
35 <form action="{% url 'index' %}" method="post" class="post-button-form">{% csrf_token %}
35 <form action="{% url 'index' %}" method="post" class="post-button-form">{% csrf_token %}
36 {% if only_favorites %}
36 {% if only_favorites %}
37 <button name="method" value="toggle_fav" class="fav"></button>,
37 <button name="method" value="toggle_fav" class="fav"></button>,
38 {% else %}
38 {% else %}
39 <button name="method" value="toggle_fav" class="not_fav"></button>,
39 <button name="method" value="toggle_fav" class="not_fav"></button>,
40 {% endif %}
40 {% endif %}
41 </form>
41 </form>
42 {{ tags_str|safe }},
42 {{ tags_str|safe }},
43 {% endif %}
43 {% endif %}
44 <a href="{% url 'tags' 'required'%}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
44 <a href="{% url 'tags' %}" title="{% trans 'Tag management' %}">{% trans "tags" %}</a>,
45 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
45 <a href="{% url 'search' %}" title="{% trans 'Search' %}">{% trans 'search' %}</a>,
46 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
46 <a href="{% url 'feed' %}" title="{% trans 'Feed' %}">{% trans 'feed' %}</a>,
47 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'images' %}</a>{% if has_fav_threads %},
47 <a href="{% url 'random' %}" title="{% trans 'Random images' %}">{% trans 'images' %}</a>{% if has_fav_threads %},
48
48
49 <a href="{% url 'feed' %}?favorites" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count" {% if not new_post_count %}style="display: none" {% endif %}>{{ new_post_count }}</span></a>
49 <a href="{% url 'feed' %}?favorites" id="fav-panel-btn">{% trans 'favorites' %} <span id="new-fav-post-count" {% if not new_post_count %}style="display: none" {% endif %}>{{ new_post_count }}</span></a>
50 {% endif %}
50 {% endif %}
51
51
52 {% if usernames %}
52 {% if usernames %}
53 <a class="right-link link" href="{% url 'notifications' %}" title="{% trans 'Notifications' %}">
53 <a class="right-link link" href="{% url 'notifications' %}" title="{% trans 'Notifications' %}">
54 {% trans 'Notifications' %}
54 {% trans 'Notifications' %}
55 {% ifnotequal new_notifications_count 0 %}
55 {% ifnotequal new_notifications_count 0 %}
56 (<b>{{ new_notifications_count }}</b>)
56 (<b>{{ new_notifications_count }}</b>)
57 {% endifnotequal %}
57 {% endifnotequal %}
58 </a>
58 </a>
59 {% endif %}
59 {% endif %}
60
60
61 <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
61 <a class="right-link link" href="{% url 'settings' %}">{% trans 'Settings' %}</a>
62 </header>
62 </header>
63
63
64 <div id="fav-panel"><div class="post">{% trans "Loading..." %}</div></div>
64 <div id="fav-panel"><div class="post">{% trans "Loading..." %}</div></div>
65
65
66 {% block content %}{% endblock %}
66 {% block content %}{% endblock %}
67
67
68 <script src="{% static 'js/3party/jquery-ui.min.js' %}"></script>
68 <script src="{% static 'js/3party/jquery-ui.min.js' %}"></script>
69 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
69 <script src="{% static 'js/jquery.mousewheel.js' %}"></script>
70 <script src="{% static 'js/3party/highlight.min.js' %}"></script>
70 <script src="{% static 'js/3party/highlight.min.js' %}"></script>
71
71
72 <script src="{% url 'js_info_dict' %}"></script>
72 <script src="{% url 'js_info_dict' %}"></script>
73
73
74 <script src="{% static 'js/popup.js' %}"></script>
74 <script src="{% static 'js/popup.js' %}"></script>
75 <script src="{% static 'js/image.js' %}"></script>
75 <script src="{% static 'js/image.js' %}"></script>
76 <script src="{% static 'js/refpopup.js' %}"></script>
76 <script src="{% static 'js/refpopup.js' %}"></script>
77 <script src="{% static 'js/main.js' %}"></script>
77 <script src="{% static 'js/main.js' %}"></script>
78
78
79 <footer class="navigation_panel">
79 <footer class="navigation_panel">
80 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
80 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
81 {% block metapanel %}{% endblock %}
81 {% block metapanel %}{% endblock %}
82 {% if rss_url %}
82 {% if rss_url %}
83 [<a href="{{ rss_url }}">RSS</a>]
83 [<a href="{{ rss_url }}">RSS</a>]
84 {% endif %}
84 {% endif %}
85 [<a href="{% url 'admin:index' %}">{% trans 'Admin' %}</a>]
85 [<a href="{% url 'admin:index' %}">{% trans 'Admin' %}</a>]
86 [<a href="{% url 'index' %}?order=pub">{% trans 'New threads' %}</a>]
86 [<a href="{% url 'index' %}?order=pub">{% trans 'New threads' %}</a>]
87 {% with ppd=posts_per_day|floatformat:2 %}
87 {% with ppd=posts_per_day|floatformat:2 %}
88 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
88 {% blocktrans %}Speed: {{ ppd }} posts per day{% endblocktrans %}
89 {% endwith %}
89 {% endwith %}
90 <a class="link" href="#top" id="up">{% trans 'Up' %}</a>
90 <a class="link" href="#top" id="up">{% trans 'Up' %}</a>
91 </footer>
91 </footer>
92
92
93 </body>
93 </body>
94 </html>
94 </html>
@@ -1,47 +1,28 b''
1 {% extends "boards/base.html" %}
1 {% extends "boards/base.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4
4
5 {% block head %}
5 {% block head %}
6 <title>Neboard - {% trans "Tags" %}</title>
6 <title>{{ site_name }} - {% trans "Tags" %}</title>
7 {% endblock %}
7 {% endblock %}
8
8
9 {% block content %}
9 {% block content %}
10
10
11 {% regroup section_tags by get_first_letter as section_tag_list %}
12 {% regroup all_tags by get_first_letter as other_tag_list %}
11 {% regroup all_tags by get_first_letter as other_tag_list %}
13
12
14 <div class="post">
13 <div class="post">
15 {% if section_tags %}
16 <div>
17 {% trans 'Sections:' %}
18 {% for letter in section_tag_list %}
19 <br />({{ letter.grouper|upper }})
20 {% for tag in letter.list %}
21 {% autoescape off %}
22 {{ tag.get_view }}{% if not forloop.last %},{% endif %}
23 {% endautoescape %}
24 {% endfor %}
25 {% endfor %}
26 </div>
27 {% endif %}
28 {% if all_tags %}
14 {% if all_tags %}
29 <div>
15 <div>
30 {% trans 'Other tags:' %}
31 {% for letter in other_tag_list %}
16 {% for letter in other_tag_list %}
32 <br />({{ letter.grouper|upper }})
17 <br />({{ letter.grouper|upper }})
33 {% for tag in letter.list %}
18 {% for tag in letter.list %}
34 {% autoescape off %}
19 {% autoescape off %}
35 {{ tag.get_view }}{% if not forloop.last %},{% endif %}
20 {{ tag.get_view }}{% if not forloop.last %},{% endif %}
36 {% endautoescape %}
21 {% endautoescape %}
37 {% endfor %}
22 {% endfor %}
38 {% endfor %}
23 {% endfor %}
39 </div>
24 </div>
40 {% endif %}
25 {% endif %}
41
42 {% if query %}
43 <div><a href="{% url 'tags' %}">{% trans 'All tags...' %}</a></div>
44 {% endif %}
45 </div>
26 </div>
46
27
47 {% endblock %}
28 {% endblock %}
@@ -1,97 +1,97 b''
1 from django.conf.urls import url
1 from django.conf.urls import url
2
2
3 import neboard
3 import neboard
4
4
5 from boards import views
5 from boards import views
6 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
6 from boards.rss import AllThreadsFeed, TagThreadsFeed, ThreadPostsFeed
7 from boards.views import api, tag_threads, all_threads, \
7 from boards.views import api, tag_threads, all_threads, \
8 settings, all_tags, feed, alias
8 settings, all_tags, feed, alias
9 from boards.views.authors import AuthorsView
9 from boards.views.authors import AuthorsView
10 from boards.views.notifications import NotificationView
10 from boards.views.notifications import NotificationView
11 from boards.views.static import StaticPageView
11 from boards.views.static import StaticPageView
12 from boards.views.preview import PostPreviewView
12 from boards.views.preview import PostPreviewView
13 from boards.views.sync import get_post_sync_data, response_get, response_list
13 from boards.views.sync import get_post_sync_data, response_get, response_list
14 from boards.views.random import RandomImageView
14 from boards.views.random import RandomImageView
15 from boards.views.tag_gallery import TagGalleryView
15 from boards.views.tag_gallery import TagGalleryView
16 from boards.views.translation import cached_javascript_catalog
16 from boards.views.translation import cached_javascript_catalog
17 from boards.views.search import BoardSearchView
17 from boards.views.search import BoardSearchView
18 from boards.views.landing import LandingView
18 from boards.views.landing import LandingView
19
19
20
20
21 js_info_dict = {
21 js_info_dict = {
22 'packages': ('boards',),
22 'packages': ('boards',),
23 }
23 }
24
24
25 urlpatterns = [
25 urlpatterns = [
26 # /boards/
26 # /boards/
27 url(r'^all/$', all_threads.AllThreadsView.as_view(), name='index'),
27 url(r'^all/$', all_threads.AllThreadsView.as_view(), name='index'),
28
28
29 # /boards/tag/tag_name/
29 # /boards/tag/tag_name/
30 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
30 url(r'^tag/(?P<tag_name>\w+)/$', tag_threads.TagView.as_view(),
31 name='tag'),
31 name='tag'),
32
32
33 # /boards/thread/
33 # /boards/thread/
34 url(r'^thread/(?P<post_id>\d+)/$', views.thread.NormalThreadView.as_view(),
34 url(r'^thread/(?P<post_id>\d+)/$', views.thread.NormalThreadView.as_view(),
35 name='thread'),
35 name='thread'),
36 url(r'^thread/(?P<post_id>\d+)/mode/gallery/$', views.thread.GalleryThreadView.as_view(),
36 url(r'^thread/(?P<post_id>\d+)/mode/gallery/$', views.thread.GalleryThreadView.as_view(),
37 name='thread_gallery'),
37 name='thread_gallery'),
38 url(r'^thread/(?P<post_id>\d+)/mode/tree/$', views.thread.TreeThreadView.as_view(),
38 url(r'^thread/(?P<post_id>\d+)/mode/tree/$', views.thread.TreeThreadView.as_view(),
39 name='thread_tree'),
39 name='thread_tree'),
40 # /feed/
40 # /feed/
41 url(r'^feed/$', views.feed.FeedView.as_view(), name='feed'),
41 url(r'^feed/$', views.feed.FeedView.as_view(), name='feed'),
42
42
43 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
43 url(r'^settings/$', settings.SettingsView.as_view(), name='settings'),
44 url(r'^aliases/(?P<category>\w+)/$', alias.AliasesView.as_view(), name='aliases'),
44 url(r'^aliases/(?P<category>\w+)/$', alias.AliasesView.as_view(), name='aliases'),
45 url(r'^tags/(?P<query>\w+)?/?$', all_tags.AllTagsView.as_view(), name='tags'),
45 url(r'^tags/$', all_tags.AllTagsView.as_view(), name='tags'),
46 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
46 url(r'^authors/$', AuthorsView.as_view(), name='authors'),
47
47
48 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
48 url(r'^banned/$', views.banned.BannedView.as_view(), name='banned'),
49 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
49 url(r'^staticpage/(?P<name>\w+)/$', StaticPageView.as_view(),
50 name='staticpage'),
50 name='staticpage'),
51
51
52 url(r'^random/$', RandomImageView.as_view(), name='random'),
52 url(r'^random/$', RandomImageView.as_view(), name='random'),
53 url(r'^tag/(?P<tag_name>\w+)/gallery/$', TagGalleryView.as_view(), name='tag_gallery'),
53 url(r'^tag/(?P<tag_name>\w+)/gallery/$', TagGalleryView.as_view(), name='tag_gallery'),
54 url(r'^search/$', BoardSearchView.as_view(), name='search'),
54 url(r'^search/$', BoardSearchView.as_view(), name='search'),
55 url(r'^$', LandingView.as_view(), name='landing'),
55 url(r'^$', LandingView.as_view(), name='landing'),
56
56
57 # RSS feeds
57 # RSS feeds
58 url(r'^rss/$', AllThreadsFeed()),
58 url(r'^rss/$', AllThreadsFeed()),
59 url(r'^page/(?P<page>\d+)/rss/$', AllThreadsFeed()),
59 url(r'^page/(?P<page>\d+)/rss/$', AllThreadsFeed()),
60 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
60 url(r'^tag/(?P<tag_name>\w+)/rss/$', TagThreadsFeed()),
61 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
61 url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/rss/$', TagThreadsFeed()),
62 url(r'^thread/(?P<post_id>\d+)/rss/$', ThreadPostsFeed()),
62 url(r'^thread/(?P<post_id>\d+)/rss/$', ThreadPostsFeed()),
63
63
64 # i18n
64 # i18n
65 url(r'^jsi18n/$', cached_javascript_catalog, js_info_dict,
65 url(r'^jsi18n/$', cached_javascript_catalog, js_info_dict,
66 name='js_info_dict'),
66 name='js_info_dict'),
67
67
68 # API
68 # API
69 url(r'^api/post/(?P<post_id>\d+)/$', api.get_post, name="get_post"),
69 url(r'^api/post/(?P<post_id>\d+)/$', api.get_post, name="get_post"),
70 url(r'^api/diff_thread/$', api.api_get_threaddiff, name="get_thread_diff"),
70 url(r'^api/diff_thread/$', api.api_get_threaddiff, name="get_thread_diff"),
71 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
71 url(r'^api/threads/(?P<count>\w+)/$', api.api_get_threads,
72 name='get_threads'),
72 name='get_threads'),
73 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
73 url(r'^api/tags/$', api.api_get_tags, name='get_tags'),
74 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
74 url(r'^api/thread/(?P<opening_post_id>\w+)/$', api.api_get_thread_posts,
75 name='get_thread'),
75 name='get_thread'),
76 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
76 url(r'^api/add_post/(?P<opening_post_id>\w+)/$', api.api_add_post,
77 name='add_post'),
77 name='add_post'),
78 url(r'^api/notifications/(?P<username>\w+)/$', api.api_get_notifications,
78 url(r'^api/notifications/(?P<username>\w+)/$', api.api_get_notifications,
79 name='api_notifications'),
79 name='api_notifications'),
80 url(r'^api/preview/$', api.api_get_preview, name='preview'),
80 url(r'^api/preview/$', api.api_get_preview, name='preview'),
81 url(r'^api/new_posts/$', api.api_get_new_posts, name='new_posts'),
81 url(r'^api/new_posts/$', api.api_get_new_posts, name='new_posts'),
82 url(r'^api/stickers/$', api.api_get_stickers, name='get_stickers'),
82 url(r'^api/stickers/$', api.api_get_stickers, name='get_stickers'),
83
83
84 # Sync protocol API
84 # Sync protocol API
85 url(r'^api/sync/list/$', response_list, name='api_sync_list'),
85 url(r'^api/sync/list/$', response_list, name='api_sync_list'),
86 url(r'^api/sync/get/$', response_get, name='api_sync_get'),
86 url(r'^api/sync/get/$', response_get, name='api_sync_get'),
87
87
88 # Notifications
88 # Notifications
89 url(r'^notifications/(?P<username>\w+)/$', NotificationView.as_view(), name='notifications'),
89 url(r'^notifications/(?P<username>\w+)/$', NotificationView.as_view(), name='notifications'),
90 url(r'^notifications/$', NotificationView.as_view(), name='notifications'),
90 url(r'^notifications/$', NotificationView.as_view(), name='notifications'),
91
91
92 # Post preview
92 # Post preview
93 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
93 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
94 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
94 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
95 name='post_sync_data'),
95 name='post_sync_data'),
96 ]
96 ]
97
97
@@ -1,23 +1,17 b''
1 from django.shortcuts import render
1 from django.shortcuts import render
2
2
3 from boards.views.base import BaseBoardView
3 from boards.views.base import BaseBoardView
4 from boards.models.tag import Tag
4 from boards.models.tag import Tag
5
5
6
6
7 PARAM_SECTION_TAGS = 'section_tags'
8 PARAM_TAGS = 'all_tags'
7 PARAM_TAGS = 'all_tags'
9 PARAM_QUERY = 'query'
10
8
11
9
12 class AllTagsView(BaseBoardView):
10 class AllTagsView(BaseBoardView):
13
11
14 def get(self, request, query=None):
12 def get(self, request):
15 params = dict()
13 params = dict()
16
14
17 params[PARAM_SECTION_TAGS] = Tag.objects.filter(required=True)
15 params[PARAM_TAGS] = Tag.objects.get_not_empty_tags()
18 if query != 'required':
19 params[PARAM_TAGS] = Tag.objects.get_not_empty_tags().filter(
20 required=False)
21 params[PARAM_QUERY] = query
22
16
23 return render(request, 'boards/tags.html', params)
17 return render(request, 'boards/tags.html', params)
General Comments 0
You need to be logged in to leave comments. Login now