thread.html 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. {% extends "cranefly/layout.html" %}
  2. {% import "forms.html" as form_theme with context %}
  3. {% import "cranefly/editor.html" as editor with context %}
  4. {% import "cranefly/macros.html" as macros with context %}
  5. {% block title %}{{ macros.page_title(title=thread.name,parent=forum.name,page=pagination['page']) }}{% endblock %}
  6. {% block breadcrumb %}{{ super() }} <span class="divider"><i class="icon-chevron-right"></i></span></li>
  7. {{ macros.parents_list(parents) }}
  8. <li class="active">{{ thread.name }}
  9. {%- endblock %}
  10. {% block container %}
  11. <div class="page-header header-primary">
  12. <div class="container">
  13. {{ messages_list(messages) }}
  14. <ul class="breadcrumb" {{ macros.itemprop_bread() }}>
  15. {{ self.breadcrumb() }}</li>
  16. </ul>
  17. <h1>{{ thread.name }}</h1>
  18. <ul class="unstyled header-stats">
  19. {% if thread.moderated %}<li><i class="icon-eye-close"></i> {% trans %}Not Reviewed{% endtrans %}</li>{% endif %}
  20. <li><i class="icon-time"></i> {{ thread.last|reltimesince }}</li>
  21. <li><i class="icon-user"></i> {% if thread.start_poster_id %}<a href="{{ url('user', user=thread.start_poster_id, username=thread.start_poster_slug) }}">{{ thread.start_poster_name }}</a>{% else %}{{ thread.start_poster_name }}{% endif %}</li>
  22. <li><i class="icon-comment"></i> {% if thread.replies > 0 -%}
  23. {% trans count=thread.replies, replies=thread.replies|intcomma %}One reply{% pluralize %}{{ replies }} replies{% endtrans %}
  24. {%- else -%}
  25. {% trans %}No replies{% endtrans %}
  26. {%- endif %}</li>
  27. {% if thread.closed %}<li><i class="icon-lock"></i> {% trans %}Locked{% endtrans %}</li>{% endif %}
  28. </ul>
  29. </div>
  30. </div>
  31. <div class="container container-primary">
  32. {% if message %}
  33. <div class="messages-list">
  34. {{ macros.draw_message(message) }}
  35. </div>
  36. {% endif %}
  37. {% if thread.has_poll %}
  38. <div id="color_demo" style="background: #FFF; padding: 32px; overflow: auto;">
  39. <h1>Random Colors</h1>
  40. {% for i in range(12) %}
  41. <div style="background-color: #{{ color_spin('049cdb', loop.index0 * 265) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  42. {% endfor %}
  43. <hr style="clear: both; border: none;">
  44. {% for i in range(12) %}
  45. <div style="background-color: #{{ color_lighten(color_spin('049cdb', loop.index0 * 265), 12, loop.index, 90) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  46. {% endfor %}
  47. <h1>Desaturate Colors</h1>
  48. {% for i in range(32) %}
  49. <div style="background-color: #{{ color_desaturate('049cdb', 32, loop.index) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  50. {% endfor %}
  51. <h1>Lighten Colors</h1>
  52. {% for i in range(32) %}
  53. <div style="background-color: #{{ color_lighten('049cdb', 32, loop.index) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  54. {% endfor %}
  55. <hr style="clear: both; border: none;">
  56. {% for i in range(32) %}
  57. <div style="background-color: #{{ color_desaturate(color_lighten('049cdb', 32, loop.index), 32, loop.index) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  58. {% endfor %}
  59. <h1>Darken Colors</h1>
  60. {% for i in range(32) %}
  61. <div style="background-color: #{{ color_darken('049cdb', 32, loop.index) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  62. {% endfor %}
  63. <hr style="clear: both; border: none;">
  64. {% for i in range(32) %}
  65. <div style="background-color: #{{ color_desaturate(color_darken('049cdb', 32, loop.index), 32, loop.index) }}; margin: 4px; width:24px; height: 24px; border-radius: 3px; float: left;"></div>
  66. {% endfor %}
  67. </div>
  68. <div class="thread-poll">
  69. <h2>{{ thread.poll.question }}</h2>
  70. {% for choice in thread.poll.option_set.all() %}
  71. <li><span style="background-color: #{{ color_desaturate(color_lighten('cf402e', loop.length, loop.index, 80), loop.length, loop.index, 20) }}; font-weight: bold; display: inline-block; width:18px; height: 18px; border-radius: 3px;"></span> {{ choice.name }}</li>
  72. {% endfor %}
  73. {% if poll_form %}
  74. <form action="" method="post">
  75. {{ form_theme.field(poll_form.options) }}
  76. </form>
  77. {% else %}
  78. <ul>
  79. {% for choice in thread.poll.option_set.all() %}
  80. <li><div style="background: #{{ spin_color('FF0000', 240 * loop.index0) }}">{{ choice.name }}</div></li>
  81. {% endfor %}
  82. </ul>
  83. {% endif %}
  84. <div id="thread-poll-graph"></div>
  85. </div>
  86. {% endif %}
  87. <div class="thread-buttons">
  88. {{ pager() }}
  89. {% if user.is_authenticated() %}
  90. {% if acl.threads.can_reply(forum, thread) %}
  91. <a href="{{ url('thread_reply', thread=thread.pk, slug=thread.slug) }}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
  92. {% endif %}
  93. {% if watcher %}
  94. <form action="{{ url('thread_unwatch', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-icon btn-success tooltip-top" title="{% trans %}Remove thread from watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
  95. {% if watcher.email %}
  96. <form action="{{ url('thread_unwatch_email', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-icon btn-success tooltip-top" title="{% trans %}Don't e-mail me anymore if anyone replies to this thread{% endtrans %}"><i class="icon-envelope"></i></button></form>
  97. {% else %}
  98. <form action="{{ url('thread_watch_email', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-icon tooltip-top" title="{% trans %}E-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
  99. {% endif %}
  100. {% else %}
  101. <form action="{{ url('thread_watch', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-icon tooltip-top" title="{% trans %}Add thread to watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
  102. <form action="{{ url('thread_watch_email', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-icon tooltip-top" title="{% trans %}Add thread to watched list and e-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
  103. {% endif %}
  104. {% if ignored_posts %}
  105. <form action="{{ url('thread_show_hidden', thread=thread.pk, slug=thread.slug) }}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><button type="submit" class="btn"><i class="icon-eye-open"></i> {% trans %}Show Hidden Replies{% endtrans %}</button></form>
  106. {% endif %}
  107. {% endif %}
  108. </div>
  109. <div class="thread-body">
  110. {% for post in posts %}
  111. <div id="post-{{ post.pk }}" class="post-wrapper">
  112. {% if post.message %}
  113. <div class="messages-list">
  114. {{ macros.draw_message(post.message) }}
  115. </div>
  116. {% endif %}
  117. {% if post.deleted and not acl.threads.can_see_deleted_posts(forum) %}
  118. <div class="post-body post-muted">
  119. {% if post.user_id %}
  120. <a href="{{ url('user', user=post.user.pk, username=post.user.username_slug) }}"><img src="{{ post.user.get_avatar(50) }}" alt="" class="user-avatar"></a>
  121. {% else %}
  122. <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar">
  123. {% endif %}
  124. <div class="post-content">
  125. <div class="post-header">
  126. <div class="post-header-compact">
  127. {% if post.user_id %}
  128. <a href="{{ url('user', user=post.user.pk, username=post.user.username_slug) }}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
  129. {% else %}
  130. <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
  131. {% endif %}
  132. <span class="separator">&ndash;</span>
  133. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  134. {% if post.edits %}
  135. <span class="separator">&ndash;</span>
  136. {% if acl.threads.can_see_changelog(user, forum, post) %}
  137. <a href="{{ url('thread_changelog', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</a>
  138. {% else %}
  139. <span class="post-changelog">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</span>
  140. {% endif %}
  141. {% endif %}
  142. </div>
  143. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
  144. {% if not post.is_read %}
  145. <div class="post-extra">
  146. <span class="label label-warning">
  147. {% trans %}New{% endtrans %}
  148. </span>
  149. </div>
  150. {% endif %}
  151. </div>
  152. <div class="post-message">
  153. {% trans user=edit_user(post), date=post.delete_date|reltimesince|low %}{{ user }} has deleted this reply {{ date }}{% endtrans %}
  154. </div>
  155. </dv>
  156. </div>
  157. {% elif post.ignored %}
  158. <div class="post-body post-muted">
  159. <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar">
  160. <div class="post-arrow"></div>
  161. <div class="post-content">
  162. <div class="post-header">
  163. <div class="post-header-compact">
  164. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  165. </div>
  166. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
  167. {% if not post.is_read %}
  168. <div class="post-extra">
  169. <span class="label label-warning">
  170. {% trans %}New{% endtrans %}
  171. </span>
  172. </div>
  173. {% endif %}
  174. </div>
  175. <div class="post-message">
  176. {% trans %}This reply was posted by user that is on your ignored list.{% endtrans %}
  177. </div>
  178. </dv>
  179. </div>
  180. {% else %}
  181. <div class="post-body">
  182. {% if post.user_id %}
  183. <a href="{{ url('user', user=post.user.pk, username=post.user.username_slug) }}"><img src="{{ post.user.get_avatar(100) }}" alt="" class="user-avatar"></a>
  184. {% else %}
  185. <img src="{{ macros.avatar_guest(100) }}" alt="" class="user-avatar">
  186. {% endif %}
  187. <div class="post-arrow"></div>
  188. <div class="post-content">
  189. <div class="post-header">
  190. {% if post.user_id %}
  191. <a href="{{ url('user', user=post.user.pk, username=post.user.username_slug) }}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
  192. {% else %}
  193. <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
  194. {% endif %}
  195. <span class="separator">&ndash;</span>
  196. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  197. {% if post.edits %}
  198. <span class="separator">&ndash;</span>
  199. {% if acl.threads.can_see_changelog(user, forum, post) %}
  200. <a href="{{ url('thread_changelog', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</a>
  201. {% else %}
  202. <span class="post-changelog">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</span>
  203. {% endif %}
  204. {% endif %}
  205. {% if user.is_authenticated() and posts_form %}
  206. <label class="checkbox post-checkbox"><input form="posts_form" name="{{ posts_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ post.pk }}"{% if posts_form['list_items']['has_value'] and ('' ~ post.pk) in posts_form['list_items']['value'] %} checked="checked"{% endif %}></label>
  207. {% endif %}
  208. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
  209. <div class="post-extra">
  210. {% if post.protected and acl.threads.can_protect(forum) %}
  211. <span class="label label-info">
  212. {% trans %}Protected{% endtrans %}
  213. </span>
  214. {% endif %}
  215. {% if post.deleted %}
  216. <span class="label label-inverse">
  217. {% trans %}Deleted{% endtrans %}
  218. </span>
  219. {% endif %}
  220. {% if post.moderated %}
  221. <span class="label label-purple">
  222. {% trans %}Unreviewed{% endtrans %}
  223. </span>
  224. {% endif %}
  225. {% if acl.threads.can_mod_posts(forum) and post.reported %}
  226. <span class="label label-important">
  227. {% trans %}Reported{% endtrans %}
  228. </span>
  229. {% endif %}
  230. {% if not post.is_read %}
  231. <span class="label label-warning">
  232. {% trans %}New{% endtrans %}
  233. </span>
  234. {% endif %}
  235. </div>
  236. </div>
  237. <div class="post-message">
  238. <div class="markdown js-extra">
  239. <article>
  240. {{ post.post_preparsed|markdown_final|safe }}
  241. </article>
  242. </div>
  243. {% if post.user.signature %}
  244. <div class="post-signature">
  245. <div class="markdown">
  246. {{ post.user.signature_preparsed|markdown_final|safe }}
  247. </div>
  248. </div>
  249. {% endif %}
  250. </div>
  251. <div class="post-footer">{% filter trim %}
  252. {% if acl.threads.can_see_post_score(forum) %}
  253. <div{% if user.is_authenticated() and user.pk != post.user_id %} class="post-rating-actions"{% endif %}>
  254. <div class="post-rating">
  255. {% if acl.threads.can_see_post_score(forum) == 1 %}
  256. <span class="post-score post-score-total{% if (post.upvotes - post.downvotes) > 0 %} post-score-good{% elif (post.upvotes - post.downvotes) < 0 %} post-score-bad{% endif %}">{{ post.upvotes - post.downvotes }}</span>
  257. {% elif acl.threads.can_see_post_score(forum) == 2%}
  258. <span class="post-score post-score-upvotes{% if post.upvotes %} post-score-good{% endif %}">{{ post.upvotes }}</span>
  259. {% endif %}
  260. {% if user.is_authenticated() and user.pk != post.user_id and acl.threads.can_upvote_posts(forum) %}
  261. <form action="{{ url('post_upvote', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-upvote" method="post">
  262. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  263. <button type="submit" class="btn btn-link post-like"{% if post.karma_vote and post.karma_vote.score > 0 %} disabled="disabled"{% endif %}>{% trans %}Like{% endtrans %}</button>
  264. </form>
  265. {% else %}
  266. <span class="post-{% if post.upvotes %}like{% else %}neutral{% endif %}">{% trans %}Likes{% endtrans %}</span>
  267. {% endif %}
  268. {% if acl.threads.can_see_post_score(forum) == 2 %}
  269. </div>
  270. <div class="post-rating">
  271. <span class="post-score post-score-downvotes{% if post.downvotes %} post-score-bad{% endif %}">{{ post.downvotes }}</span>
  272. {% endif %}
  273. {% if user.is_authenticated() and user.pk != post.user_id and acl.threads.can_downvote_posts(forum) %}
  274. <form action="{{ url('post_downvote', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-downvote" method="post">
  275. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  276. <button type="submit" class="btn btn-link post-hate"{% if post.karma_vote and post.karma_vote.score < 0 %} disabled="disabled"{% endif %}>{% trans %}Dislike{% endtrans %}</button>
  277. </form>
  278. {% elif acl.threads.can_see_post_score(forum) == 2 %}
  279. <span class="post-{% if post.downvotes %}hate{% else %}neutral{% endif %}">{% trans %}Dislikes{% endtrans %}</span>
  280. {% endif %}
  281. </div>
  282. {% if acl.threads.can_see_post_votes(forum) %}
  283. <div class="post-rating">
  284. <a href="{{ url('post_votes', thread=thread.pk, slug=thread.slug, post=post.pk) }}">{% trans %}Show Votes{% endtrans %}</a>
  285. </div>
  286. {% endif %}
  287. </div>
  288. {% endif %}
  289. {% if user.is_authenticated() %}
  290. <div class="post-actions">
  291. {% if acl.users.can_see_users_trails() -%}
  292. <a href="{{ url('post_info', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-trail">{% trans %}Info{% endtrans %}</a>
  293. {% endif %}
  294. {% if post.reported and acl.reports.can_handle() and acl.threads.can_mod_posts(forum) %}
  295. <a href="{{ url('post_report_show', thread=thread.pk, slug=thread.slug, post=post.pk) }}">{% trans %}Show report{% endtrans %}</a>
  296. {% endif %}
  297. {% if acl.reports.can_report() %}
  298. {% if post.reported_by(user) %}
  299. <a href="{{ url('post_report', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="tooltip-top" title="{% trans %}You have already reported this post.{% endtrans %}" disabled="disabled">{% trans %}Reported{% endtrans %}</a>
  300. {% else %}
  301. <form action="{{ url('post_report', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-report" method="post" autocomplete="off">
  302. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  303. <button type="submit" class="btn btn-link btn-report tooltip-top" title="{% trans %}Bring this post to moderator attention.{% endtrans %}">{% trans %}Report{% endtrans %}</button>
  304. </form>
  305. {% endif %}
  306. {% endif %}
  307. {% if acl.threads.can_edit_thread(user, forum, thread, post) and thread.start_post_id == post.pk %}
  308. <a href="{{ url('thread_edit', thread=thread.pk, slug=thread.slug) }}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
  309. {% elif acl.threads.can_edit_reply(user, forum, thread, post) %}
  310. <a href="{{ url('post_edit', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
  311. {%- endif %}
  312. {% if acl.threads.can_reply(forum, thread) %}<a href="{{ url('thread_reply', thread=thread.pk, slug=thread.slug, quote=post.pk) }}" class="post-reply">{% trans %}Reply{% endtrans %}</a>{% endif %}
  313. </div>
  314. {% if post.pk == thread.start_post_id %}
  315. <div class="post-actions">
  316. {% if acl.threads.can_delete_thread(user, forum, thread, post) %}
  317. {% if post.deleted %}
  318. <form action="{{ url('thread_show', thread=thread.pk, slug=thread.slug) }}" class="form-inline" method="post">
  319. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  320. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Make this thread visible to other users{% endtrans %}">{% trans %}Restore{% endtrans %}</button>
  321. </form>
  322. {% else %}
  323. <form action="{{ url('thread_hide', thread=thread.pk, slug=thread.slug) }}" class="form-inline" method="post">
  324. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  325. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Hide this thread from other users{% endtrans %}">{% trans %}Hide{% endtrans %}</button>
  326. </form>
  327. {% endif %}
  328. {% endif %}
  329. {% if acl.threads.can_delete_thread(user, forum, thread, post) == 2 %}
  330. <form action="{{ url('thread_delete', thread=thread.pk, slug=thread.slug) }}" class="form-inline prompt-delete-thread" method="post">
  331. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  332. <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this thread for good{% endtrans %}">{% trans %}Delete{% endtrans %}</button>
  333. </form>
  334. {% endif %}
  335. </div>
  336. {% elif post.pk != thread.start_post_id and acl.threads.can_delete_post(user, forum, thread, post) %}
  337. <div class="post-actions">
  338. {% if acl.threads.can_delete_post(user, forum, thread, post) %}
  339. {% if post.deleted %}
  340. <form action="{{ url('post_show', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline" method="post">
  341. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  342. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Make this reply visible to other users{% endtrans %}">{% trans %}Restore{% endtrans %}</button>
  343. </form>
  344. {% else %}
  345. <form action="{{ url('post_hide', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline" method="post">
  346. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  347. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Hide this reply from other users{% endtrans %}">{% trans %}Hide{% endtrans %}</button>
  348. </form>
  349. {% endif %}
  350. {% endif %}
  351. {% if acl.threads.can_delete_post(user, forum, thread, post) == 2 -%}
  352. <form action="{{ url('post_delete', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline prompt-delete-post" method="post">
  353. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  354. <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this reply for good{% endtrans %}">{% trans %}Delete{% endtrans %}</button>
  355. </form>
  356. {% endif %}
  357. </div>
  358. {% endif %}
  359. {% endif %}
  360. {% endfilter %}</div>
  361. </div>
  362. </div>
  363. {% endif %}
  364. </div>
  365. {% if post.checkpoints_visible %}
  366. <div class="post-checkpoints">
  367. {% for checkpoint in post.checkpoints_visible %}
  368. <div class="post-checkpoint{% if checkpoint.deleted %} checkpoint-deleted{% endif %}">
  369. <hr>
  370. <span>
  371. {%- if checkpoint.action == 'limit' -%}
  372. <i class="icon-lock"></i> {% trans %}This thread has reached its post limit and has been closed.{% endtrans %}
  373. {%- elif checkpoint.action == 'accepted' -%}
  374. <i class="icon-ok"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} accepted this thread {{ date }}{% endtrans %}
  375. {%- elif checkpoint.action == 'closed' -%}
  376. <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} closed this thread {{ date }}{% endtrans %}
  377. {%- elif checkpoint.action == 'opened' -%}
  378. <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} opened this thread {{ date }}{% endtrans %}
  379. {%- elif checkpoint.action == 'deleted' -%}
  380. <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} deleted this thread {{ date }}{% endtrans %}
  381. {%- elif checkpoint.action == 'undeleted' -%}
  382. <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} restored this thread {{ date }}{% endtrans %}
  383. {%- elif checkpoint.action == 'moved' and acl.forums.can_see(checkpoint.old_forum_id) -%}
  384. <i class="icon-arrow-right"></i> {% trans user=checkpoint_user(checkpoint), forum=checkpoint_forum(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} moved this thread from {{ forum }} {{ date }}{% endtrans %}
  385. {%- endif -%}
  386. {% if user.is_authenticated() %}
  387. {% if acl.threads.can_delete_checkpoint(forum) %}
  388. {% if checkpoint.deleted %}
  389. <form action="{{ url('post_checkpoint_show', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline">
  390. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  391. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  392. <button type="submit" class="btn btn-link btn-show">{% trans %}Restore{% endtrans %}</button>
  393. </form>
  394. {% else %}
  395. <form action="{{ url('post_checkpoint_hide', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline">
  396. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  397. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  398. <button type="submit" class="btn btn-link btn-hide">{% trans %}Hide{% endtrans %}</button>
  399. </form>
  400. {% endif %}
  401. {% endif %}
  402. {% if acl.threads.can_delete_checkpoint(forum) == 2 %}
  403. <form action="{{ url('post_checkpoint_delete', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline prompt-delete-checkpoint">
  404. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  405. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  406. <button type="submit" class="btn btn-link btn-delete">{% trans %}Delete{% endtrans %}</button>
  407. </form>
  408. {% endif %}
  409. {% endif %}
  410. </span>
  411. </div>
  412. {% endfor %}
  413. </div>
  414. {% endif %}
  415. {% endfor %}
  416. </div>
  417. {% if user.is_authenticated() and (thread_form or posts_form) %}
  418. <div class="thread-moderation">
  419. {% if thread_form %}
  420. <form id="thread_form" class="form-inline pull-left" action="{{ request_path }}" method="POST">
  421. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  422. <input type="hidden" name="origin" value="thread_form">
  423. {{ form_theme.field(thread_form.thread_action, attrs={'class': 'span3'}) }}
  424. <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
  425. </form>
  426. {% endif %}
  427. {% if posts_form %}
  428. <form id="posts_form" class="form-inline pull-right" action="{{ request_path }}" method="POST">
  429. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  430. <input type="hidden" name="origin" value="posts_form">
  431. {{ form_theme.field(posts_form.list_action, attrs={'class': 'span3'}) }}
  432. <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
  433. </form>
  434. {% endif %}
  435. </div>
  436. {% endif %}
  437. <div class="thread-buttons">
  438. {{ pager(false) }}
  439. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  440. <a href="{{ url('thread_reply', thread=thread.pk, slug=thread.slug) }}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
  441. {% elif not user.is_authenticated() and not user.is_crawler() %}
  442. <p class="lead thread-signin-message"><a href="{{ url('sign_in') }}">{% trans %}Sign in or register to reply.{% endtrans %}</a></p>
  443. {% endif %}
  444. </div>
  445. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  446. <div class="thread-quick-reply">
  447. <form action="{{ url('thread_reply', thread=thread.pk, slug=thread.slug) }}" method="post">
  448. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  449. <input type="hidden" name="quick_reply" value="1">
  450. <img src="{{ user.get_avatar(100) }}" alt="{% trans %}Your Avatar{% endtrans %}" class="user-avatar">
  451. {{ editor.editor(quick_reply.post, _('Post Reply'), zen=True, extra=editor_extra()) }}
  452. </form>
  453. </div>
  454. {% endif %}
  455. </div>
  456. {% endblock %}
  457. {% block stylesheets %}{{ super() }}
  458. <link href="{{ STATIC_URL }}cranefly/highlight/styles/monokai.css" rel="stylesheet">
  459. {% endblock %}
  460. {% block javascripts -%}
  461. {{ editor.zen() }}
  462. {{ super() }}
  463. <script src="{{ STATIC_URL }}cranefly/highlight/highlight.pack.js"></script>
  464. <script type="text/javascript">
  465. var l_post_reported = "{{ _('Reported!') }}";
  466. hljs.tabReplace = ' ';
  467. hljs.initHighlightingOnLoad();
  468. EnhancePostsMD();
  469. {%- if user.is_authenticated() %}
  470. $(function () {
  471. $('#thread_form').submit(function() {
  472. if ($('#id_thread_action').val() == 'hard') {
  473. var decision = confirm("{% trans %}Are you sure you want to delete this thread? This action is not reversible!{% endtrans %}");
  474. return decision;
  475. }
  476. return true;
  477. });
  478. $('#posts_form').submit(function() {
  479. if ($('.post-checkbox[]:checked').length == 0) {
  480. alert("{% trans %}You have to select at least one post.{% endtrans %}");
  481. return false;
  482. }
  483. if ($('#id_list_action').val() == 'merge') {
  484. if ($('.post-checkbox[]:checked').length < 2) {
  485. alert("{% trans %}You have to select at least two posts you want to merge.{% endtrans %}");
  486. return false;
  487. }
  488. var decision = confirm("{% trans %}Are you sure you want to merge selected posts? This action is not reversible!{% endtrans %}");
  489. return decision;
  490. }
  491. if ($('#id_list_action').val() == 'hard') {
  492. var decision = confirm("{% trans %}Are you sure you want to delete selected posts? This action is not reversible!{% endtrans %}");
  493. return decision;
  494. }
  495. return true;
  496. });
  497. $('.prompt-delete-thread').submit(function() {
  498. var decision = confirm("{% trans %}Are you sure you want to delete this thread?{% endtrans %}");
  499. return decision;
  500. });
  501. $('.prompt-delete-post').submit(function() {
  502. var decision = confirm("{% trans %}Are you sure you want to delete this post?{% endtrans %}");
  503. return decision;
  504. });
  505. $('.prompt-delete-checkpoint').submit(function() {
  506. var decision = confirm("{% trans %}Are you sure you want to delete this checkpoint?{% endtrans %}");
  507. return decision;
  508. });
  509. });
  510. {% endif %}
  511. </script>
  512. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  513. {{ editor.js() }}
  514. {% endif %}
  515. {% if thread.has_poll %}
  516. <script type="text/javascript" src="https://www.google.com/jsapi"></script>
  517. <script type="text/javascript">
  518. google.load("visualization", "1", {packages:["corechart"]});
  519. google.setOnLoadCallback(drawChart);
  520. function drawChart() {
  521. var data = google.visualization.arrayToDataTable([
  522. ["{{ thread.poll.question }}", "{% trans %}Votes{% endtrans %}"]
  523. {% for option in thread.poll.option_set.all() %}
  524. , ["{{ option.name }}", {{ option.votes}}]
  525. {% endfor %}
  526. ]);
  527. var options = {
  528. };
  529. var chart = new google.visualization.PieChart(document.getElementById('thread-poll-graph'));
  530. chart.draw(data, options);
  531. }
  532. </script>
  533. {% endif %}
  534. {%- endblock %}
  535. {% macro user_label(user) -%}
  536. <{% if user.rank and user.rank.as_tab %}a href="{{ url('users', slug=user.rank.slug) }}"{% else %}span{% endif %} class="label post-author-label{% if user.rank and user.rank.style %} post-label-{{ user.rank.style }}{% endif %}">{{ user.get_title() }}</{% if user.rank and user.rank.as_tab%}a{% else %}span{% endif %}>
  537. {%- endmacro %}
  538. {% macro pager(extra=true) %}
  539. <div class="pagination pull-left">
  540. <ul>
  541. {% if pagination['total'] > 0 %}
  542. <li class="count">{{ macros.pager_label(pagination) }}</li>
  543. {%- if pagination['prev'] > 1 %}<li><a href="{{ url('thread', slug=thread.slug, thread=thread.id) }}" class="tooltip-top" title="{% trans %}Go to first page{% endtrans %}"><i class="icon-chevron-left"></i> {% trans %}First{% endtrans %}</a></li>{% endif -%}
  544. {%- if pagination['prev'] > 0 %}<li><a href="{%- if pagination['prev'] > 1 %}{{ url('thread', slug=thread.slug, thread=thread.id, page=pagination['prev']) }}{% else %}{{ url('thread', slug=thread.slug, thread=thread.id) }}{% endif %}" class="tooltip-top" title="{% trans %}Older Posts{% endtrans %}"><i class="icon-chevron-left"></i></a></li>{% endif -%}
  545. {%- if pagination['next'] > 0 %}<li><a href="{{ url('thread', slug=thread.slug, thread=thread.id, page=pagination['next']) }}" class="tooltip-top" title="{% trans %}Newest Posts{% endtrans %}"><i class="icon-chevron-right"></i></a></li>{% endif -%}
  546. {%- if pagination['next'] > 0 and pagination['next'] < pagination['total'] %}<li><a href="{{ url('thread', slug=thread.slug, thread=thread.id, page=pagination['total']) }}" class="tooltip-top" title="{% trans %}Go to last page{% endtrans %}">{% trans %}Last{% endtrans %} <i class="icon-chevron-right"></i></a></li>{% endif -%}
  547. {% endif %}
  548. {% if extra and user.is_authenticated() %}
  549. {% if not is_read %}<li><a href="{{ url('thread_new', slug=thread.slug, thread=thread.id) }}" class="tooltip-top" title="{% trans %}Go to first unread{% endtrans %}"><i class="icon-star"></i> {% trans %}First Unread{% endtrans %}</a></li>{% endif %}
  550. {% if thread.replies_moderated > 0 and acl.threads.can_approve(forum) %}<li><a href="{{ url('thread_moderated', slug=thread.slug, thread=thread.id) }}" class="tooltip-top" title="{% trans %}Go to first post awaiting review{% endtrans %}"><i class="icon-eye-close"></i> {% trans %}First Unreviewed{% endtrans %}</a></li>{% endif %}
  551. {% if thread.replies_reported > 0 and acl.threads.can_mod_posts(forum) %}<li><a href="{{ url('thread_reported', slug=thread.slug, thread=thread.id) }}" class="tooltip-top" title="{% trans %}Go to first reported post{% endtrans %}"><i class="icon-fire"></i> {% trans %}First Reported{% endtrans %}</a></li>{% endif %}
  552. {% endif %}
  553. </ul>
  554. </div>
  555. {% endmacro %}
  556. {% macro checkpoint_user(checkpoint) -%}
  557. {%- if checkpoint.user_id -%}
  558. <a href="{{ url('user', user=checkpoint.user_id, username=checkpoint.user_slug) }}">{{ checkpoint.user_name }}</a>
  559. {%- else -%}
  560. <strong>{{ checkpoint.user_name }}</strong>
  561. {%- endif -%}
  562. {%- endmacro %}
  563. {% macro checkpoint_forum(checkpoint) -%}
  564. {%- if checkpoint.old_forum_id -%}
  565. <a href="{{ url('forum', forum=checkpoint.old_forum_id, slug=checkpoint.old_forum_slug) }}">{{ checkpoint.old_forum_name }}</a>
  566. {%- else -%}
  567. <strong>{{ checkpoint.old_forum_name }}</strong>
  568. {%- endif -%}
  569. {%- endmacro %}
  570. {% macro edit_user(post) -%}
  571. {%- if post.edit_user_id -%}
  572. <a href="{{ url('user', user=post.edit_user_id, username=post.edit_user_slug) }}">{{ post.edit_user_name }}</a>
  573. {%- else -%}
  574. <strong>{{ post.edit_user_name }}</strong>
  575. {%- endif -%}
  576. {%- endmacro %}
  577. {% macro editor_extra() %}
  578. <button id="editor-preview" name="preview" type="submit" class="btn pull-right">{% trans %}Full Editor{% endtrans %}</button>
  579. {% endmacro %}