thread.html 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  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 prefix %}<li><i class="icon-tag"></i> <a href="{{ url('forum_prefixed', forum=forum.pk, slug=forum.slug, prefix=prefix.slug) }}" class="label{% if prefix.style %} label-{{ prefix.style }}{% endif %} thread-prefix">{{ _(prefix.name) }}</a></li>{% endif %}
  20. {% if thread.moderated %}<li><i class="icon-eye-close"></i> {% trans %}Not Reviewed{% endtrans %}</li>{% endif %}
  21. <li><i class="icon-time"></i> {{ thread.last|reltimesince }}</li>
  22. <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>
  23. <li><i class="icon-comment"></i> {% if thread.replies > 0 -%}
  24. {% trans count=thread.replies, replies=thread.replies|intcomma %}One reply{% pluralize %}{{ replies }} replies{% endtrans %}
  25. {%- else -%}
  26. {% trans %}No replies{% endtrans %}
  27. {%- endif %}</li>
  28. {% if thread.closed %}<li><i class="icon-lock"></i> {% trans %}Locked{% endtrans %}</li>{% endif %}
  29. </ul>
  30. </div>
  31. </div>
  32. <div class="container container-primary">
  33. {% if message %}
  34. <div class="messages-list">
  35. {{ macros.draw_message(message) }}
  36. </div>
  37. {% endif %}
  38. {% if poll %}
  39. <div class="thread-poll-body" id="poll">
  40. {% if poll.message %}
  41. <div class="messages-list">
  42. {{ macros.draw_message(poll.message) }}
  43. </div>
  44. {% endif %}
  45. <h2>{% trans question=poll.question %}Poll: {{ question }}{% endtrans %}</h2>
  46. {% if poll_form %}
  47. <form action="{{ url('thread_poll_vote', slug=thread.slug, thread=thread.pk) }}" method="post">
  48. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  49. <input type="hidden" name="retreat" value="{{ request_path }}">
  50. {% endif %}
  51. <div class="poll-options">
  52. {% if poll_form and not poll.user_votes %}
  53. <div class="options-form">
  54. {{ form_theme.field(poll_form.options) }}
  55. <p class="poll-voting-help">{% trans choices=poll.max_choices -%}
  56. You can vote for one option.
  57. {%- pluralize -%}
  58. You can vote for {{ choices }} options.
  59. {%- endtrans %}{% if poll.public %} {% trans %}Your votes will be public.{% endtrans %}{% endif %}</p>
  60. </div>
  61. {% else %}
  62. <dl class="dl-horizontal">
  63. {% for choice in poll.choices_cache %}
  64. <dt>{{ choice.name }}</dt>
  65. <dd>
  66. <div class="progress">
  67. <div class="bar" style="width: {% if poll.votes %}{{ (choice.votes * 100 / poll.votes)|int }}{% else %}1{% endif %}%; background: #{{ color_desaturate(color_spin('049cdb', loop.index0 * 265), loop.length, loop.index/3, 20) }};"></div>
  68. </div>
  69. <p class="option-details">
  70. {% if choice.pk in poll.user_votes %}<strong>{% trans %}Your vote{% endtrans %}</strong>{% endif %}
  71. {% trans count=choice.votes, votes=choice.votes, percent=((choice.votes * 100 / poll.votes) if poll.votes else 0)|int -%}
  72. {{ votes }} vote, {{ percent }}% of all
  73. {%- pluralize -%}
  74. {{ votes }} votes, {{ percent }}% of all
  75. {%- endtrans %}
  76. </p>
  77. </dd>
  78. {% endfor %}
  79. </dl>
  80. {% endif %}
  81. </div>
  82. <div class="poll-footer">
  83. {% if poll_form %}
  84. {% if poll.user_votes and (not poll.user_votes[0] or poll.vote_changing) %}
  85. {% if poll.user_votes[0] %}
  86. <button type="submit" name="change_vote" class="btn btn-primary">{% trans %}Change Vote{% endtrans %}</button>
  87. {% else %}
  88. <button type="submit" name="show_options" class="btn btn-primary">{% trans %}Voting Options{% endtrans %}</button>
  89. {% endif %}
  90. {% else %}
  91. <button type="submit" class="btn btn-primary">{% trans %}Make Vote{% endtrans %}</button>
  92. <button type="submit" name="show_results" class="btn btn-inverse">{% trans %}Results{% endtrans %}</button>
  93. {% endif %}
  94. {% endif %}
  95. {% if poll.public or acl.threads.can_see_polls_votes(forum) %}
  96. <a href="{{ url('thread_poll_details', slug=thread.slug, thread=thread.pk) }}" class="btn">{% trans %}Participants{% endtrans %}</a>
  97. {% endif %}
  98. <p>
  99. {% if poll.public %}
  100. <strong>{% trans %}Voting is public.{% endtrans %}</strong>
  101. {% endif %}
  102. {% if thread.closed or thread.deleted %}
  103. {% trans %}Poll has been closed.{% endtrans %}
  104. {% elif thread.poll.over %}
  105. {% trans end=poll.end_date|date %}Poll ended on {{ end }}{% endtrans %}
  106. {% elif thread.poll.length %}
  107. {% trans end=poll.end_date|date %}Poll ends on {{ end }}{% endtrans %}
  108. {% else %}
  109. {% trans %}Permanent poll.{% endtrans %}
  110. {% endif %}
  111. </p>
  112. </div>
  113. {% if poll_form %}
  114. </form>
  115. {% endif %}
  116. </div>
  117. {% endif %}
  118. <div class="thread-buttons">
  119. {{ pager() }}
  120. {% if user.is_authenticated() %}
  121. {% if acl.threads.can_reply(forum, thread) %}
  122. <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>
  123. {% endif %}
  124. {% if watcher %}
  125. <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>
  126. {% if watcher.email %}
  127. <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>
  128. {% else %}
  129. <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>
  130. {% endif %}
  131. {% else %}
  132. <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>
  133. <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>
  134. {% endif %}
  135. {% if ignored_posts %}
  136. <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>
  137. {% endif %}
  138. {% endif %}
  139. </div>
  140. <div class="thread-body">
  141. {% for post in posts %}
  142. <div id="post-{{ post.pk }}" class="post-wrapper">
  143. {% if post.message %}
  144. <div class="messages-list">
  145. {{ macros.draw_message(post.message) }}
  146. </div>
  147. {% endif %}
  148. {% if post.deleted and not acl.threads.can_see_deleted_posts(forum) %}
  149. <div class="post-body post-muted">
  150. {% if post.user_id %}
  151. <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>
  152. {% else %}
  153. <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar">
  154. {% endif %}
  155. <div class="post-content">
  156. <div class="post-header">
  157. <div class="post-header-compact">
  158. {% if post.user_id %}
  159. <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 %}
  160. {% else %}
  161. <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
  162. {% endif %}
  163. <span class="separator">&ndash;</span>
  164. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  165. {% if post.edits %}
  166. <span class="separator">&ndash;</span>
  167. {% if acl.threads.can_see_changelog(user, forum, post) %}
  168. <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>
  169. {% else %}
  170. <span class="post-changelog">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</span>
  171. {% endif %}
  172. {% endif %}
  173. </div>
  174. <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>
  175. {% if not post.is_read %}
  176. <div class="post-extra">
  177. <span class="label label-warning">
  178. {% trans %}New{% endtrans %}
  179. </span>
  180. </div>
  181. {% endif %}
  182. </div>
  183. <div class="post-message">
  184. {% trans user=edit_user(post), date=post.delete_date|reltimesince|low %}{{ user }} has deleted this reply {{ date }}{% endtrans %}
  185. </div>
  186. </dv>
  187. </div>
  188. {% elif post.ignored %}
  189. <div class="post-body post-muted">
  190. <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar">
  191. <div class="post-arrow"></div>
  192. <div class="post-content">
  193. <div class="post-header">
  194. <div class="post-header-compact">
  195. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  196. </div>
  197. <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>
  198. {% if not post.is_read %}
  199. <div class="post-extra">
  200. <span class="label label-warning">
  201. {% trans %}New{% endtrans %}
  202. </span>
  203. </div>
  204. {% endif %}
  205. </div>
  206. <div class="post-message">
  207. {% trans %}This reply was posted by user that is on your ignored list.{% endtrans %}
  208. </div>
  209. </dv>
  210. </div>
  211. {% else %}
  212. <div class="post-body">
  213. {% if post.user_id %}
  214. <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>
  215. {% else %}
  216. <img src="{{ macros.avatar_guest(100) }}" alt="" class="user-avatar">
  217. {% endif %}
  218. <div class="post-arrow"></div>
  219. <div class="post-content">
  220. <div class="post-header">
  221. {% if post.user_id %}
  222. <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 %}
  223. {% else %}
  224. <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
  225. {% endif %}
  226. <span class="separator">&ndash;</span>
  227. <a href="{{ url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-date">{{ post.date|reltimesince }}</a>
  228. {% if post.edits %}
  229. <span class="separator">&ndash;</span>
  230. {% if acl.threads.can_see_changelog(user, forum, post) %}
  231. <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>
  232. {% else %}
  233. <span class="post-changelog">{% trans edits=post.edits %}One edit{% pluralize %}{{ edits }} edits{% endtrans %}</span>
  234. {% endif %}
  235. {% endif %}
  236. {% if user.is_authenticated() and posts_form %}
  237. <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>
  238. {% endif %}
  239. <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>
  240. <div class="post-extra">
  241. {% if post.protected and acl.threads.can_protect(forum) %}
  242. <span class="label label-info">
  243. {% trans %}Protected{% endtrans %}
  244. </span>
  245. {% endif %}
  246. {% if post.deleted %}
  247. <span class="label label-inverse">
  248. {% trans %}Deleted{% endtrans %}
  249. </span>
  250. {% endif %}
  251. {% if post.moderated %}
  252. <span class="label label-purple">
  253. {% trans %}Unreviewed{% endtrans %}
  254. </span>
  255. {% endif %}
  256. {% if acl.threads.can_mod_posts(forum) and post.reported %}
  257. <span class="label label-important">
  258. {% trans %}Reported{% endtrans %}
  259. </span>
  260. {% endif %}
  261. {% if not post.is_read %}
  262. <span class="label label-warning">
  263. {% trans %}New{% endtrans %}
  264. </span>
  265. {% endif %}
  266. </div>
  267. </div>
  268. <div class="post-message">
  269. <div class="markdown js-extra">
  270. <article>
  271. {{ post.post_preparsed|markdown_final|safe }}
  272. </article>
  273. </div>
  274. {% if post.has_attachments and acl.threads.can_download_attachments(user, forum, post) %}
  275. <div class="post-attachments">
  276. <h3>{% trans %}Attached files{% endtrans %}</h3>
  277. {% for row in post.attachments|batch(2) %}
  278. {% if not loop.first %}
  279. <hr>
  280. {% endif %}
  281. <div class="row-fluid">
  282. {% for attachment in row %}
  283. <div class="span6">
  284. <div class="post-attachment">
  285. <div class="attachment-image">
  286. <a href="{{ url('attachments_server', attachment=attachment.hash_id) }}">
  287. {% if attachment.is_image %}
  288. <img src="{{ url('attachments_thumbs_server', attachment=attachment.hash_id) }}" alt="">
  289. {% else %}
  290. <i class="icon-file"></i>
  291. {% endif %}
  292. </a>
  293. </div>
  294. <div class="attachment-body">
  295. <h4><a href="{{ url('attachments_server', attachment=attachment.hash_id) }}">{{ attachment.name }}</a></h4>
  296. <div class="attachment-details">
  297. {% if attachment.user_id %}
  298. <a href="{{ url('user', user=attachment.user_id, username=attachment.user_name_slug) }}">{{ attachment.user_name }}</a>,
  299. {% else %}
  300. {{ attachment.user_name }},
  301. {% endif %}
  302. {% if acl.users.can_see_users_trails() %}
  303. <abbr title="{{ attachment.agent }}">{{ attachment.ip }}</abbr>,
  304. {% endif %}
  305. {{ attachment.date|date }},
  306. {{ _(attachment.filetype.name) }}, {{ attachment.size|filesize }}
  307. </div>
  308. </div>
  309. </div>
  310. </div>
  311. {% endfor %}
  312. </div>
  313. {% endfor %}
  314. </div>
  315. {% endif %}
  316. {% if post.user.signature %}
  317. <div class="post-signature">
  318. <div class="markdown">
  319. {{ post.user.signature_preparsed|markdown_final|safe }}
  320. </div>
  321. </div>
  322. {% endif %}
  323. </div>
  324. <div class="post-footer">{% filter trim %}
  325. {% if acl.threads.can_see_post_score(forum) %}
  326. <div{% if user.is_authenticated() and user.pk != post.user_id %} class="post-rating-actions"{% endif %}>
  327. <div class="post-rating">
  328. {% if acl.threads.can_see_post_score(forum) == 1 %}
  329. <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>
  330. {% elif acl.threads.can_see_post_score(forum) == 2%}
  331. <span class="post-score post-score-upvotes{% if post.upvotes %} post-score-good{% endif %}">{{ post.upvotes }}</span>
  332. {% endif %}
  333. {% if user.is_authenticated() and user.pk != post.user_id and acl.threads.can_upvote_posts(forum) %}
  334. <form action="{{ url('post_upvote', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-upvote" method="post">
  335. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  336. <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>
  337. </form>
  338. {% else %}
  339. <span class="post-{% if post.upvotes %}like{% else %}neutral{% endif %}">{% trans %}Likes{% endtrans %}</span>
  340. {% endif %}
  341. {% if acl.threads.can_see_post_score(forum) == 2 %}
  342. </div>
  343. <div class="post-rating">
  344. <span class="post-score post-score-downvotes{% if post.downvotes %} post-score-bad{% endif %}">{{ post.downvotes }}</span>
  345. {% endif %}
  346. {% if user.is_authenticated() and user.pk != post.user_id and acl.threads.can_downvote_posts(forum) %}
  347. <form action="{{ url('post_downvote', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-downvote" method="post">
  348. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  349. <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>
  350. </form>
  351. {% elif acl.threads.can_see_post_score(forum) == 2 %}
  352. <span class="post-{% if post.downvotes %}hate{% else %}neutral{% endif %}">{% trans %}Dislikes{% endtrans %}</span>
  353. {% endif %}
  354. </div>
  355. {% if acl.threads.can_see_post_votes(forum) %}
  356. <div class="post-rating">
  357. <a href="{{ url('post_votes', thread=thread.pk, slug=thread.slug, post=post.pk) }}">{% trans %}Show Votes{% endtrans %}</a>
  358. </div>
  359. {% endif %}
  360. </div>
  361. {% endif %}
  362. {% if user.is_authenticated() %}
  363. <div class="post-actions">
  364. {% if user.pk != post.user_id and post.user_id and acl.warnings.can_warn_members() %}
  365. <form action="{{ url('post_report', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-report" method="post" autocomplete="off">
  366. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  367. <input type="hidden" name="retreat" value="{{ request_path }}">
  368. <input type="hidden" name="reason" value="{% trans message=url('thread_find', thread=thread.pk, slug=thread.slug, post=post.pk), thread=thread.name %}Your message {{ message }} in thread "{{ thread }}" was found to violate community guidelines.{% endtrans %}">
  369. <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Warn user for this post.{% endtrans %}">{% trans %}Warn{% endtrans %}</button>
  370. </form>
  371. {% endif %}
  372. {% if acl.users.can_see_users_trails() -%}
  373. <a href="{{ url('post_info', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-trail">{% trans %}Info{% endtrans %}</a>
  374. {% endif %}
  375. {% if post.reported and acl.reports.can_handle() and acl.threads.can_mod_posts(forum) %}
  376. <a href="{{ url('post_report_show', thread=thread.pk, slug=thread.slug, post=post.pk) }}">{% trans %}Show report{% endtrans %}</a>
  377. {% endif %}
  378. {% if acl.reports.can_report() %}
  379. {% if post.reported_by(user) %}
  380. <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>
  381. {% else %}
  382. <form action="{{ url('post_report', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline form-report" method="post" autocomplete="off">
  383. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  384. <button type="submit" class="btn btn-link btn-report tooltip-top" title="{% trans %}Bring this post to moderator attention.{% endtrans %}">{% trans %}Report{% endtrans %}</button>
  385. </form>
  386. {% endif %}
  387. {% endif %}
  388. {% if acl.threads.can_edit_thread(user, forum, thread, post) and thread.start_post_id == post.pk %}
  389. <a href="{{ url('thread_edit', thread=thread.pk, slug=thread.slug) }}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
  390. {% elif acl.threads.can_edit_reply(user, forum, thread, post) %}
  391. <a href="{{ url('post_edit', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
  392. {%- endif %}
  393. {% 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 %}
  394. </div>
  395. {% if post.pk == thread.start_post_id %}
  396. <div class="post-actions">
  397. {% if acl.threads.can_delete_thread(user, forum, thread, post) %}
  398. {% if post.deleted %}
  399. <form action="{{ url('thread_show', thread=thread.pk, slug=thread.slug) }}" class="form-inline" method="post">
  400. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  401. <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>
  402. </form>
  403. {% else %}
  404. <form action="{{ url('thread_hide', thread=thread.pk, slug=thread.slug) }}" class="form-inline" method="post">
  405. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  406. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Hide this thread from other users{% endtrans %}">{% trans %}Hide{% endtrans %}</button>
  407. </form>
  408. {% endif %}
  409. {% endif %}
  410. {% if acl.threads.can_delete_thread(user, forum, thread, post) == 2 %}
  411. <form action="{{ url('thread_delete', thread=thread.pk, slug=thread.slug) }}" class="form-inline prompt-delete-thread" method="post">
  412. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  413. <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this thread for good{% endtrans %}">{% trans %}Delete{% endtrans %}</button>
  414. </form>
  415. {% endif %}
  416. </div>
  417. {% elif post.pk != thread.start_post_id and acl.threads.can_delete_post(user, forum, thread, post) %}
  418. <div class="post-actions">
  419. {% if acl.threads.can_delete_post(user, forum, thread, post) %}
  420. {% if post.deleted %}
  421. <form action="{{ url('post_show', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline" method="post">
  422. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  423. <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>
  424. </form>
  425. {% else %}
  426. <form action="{{ url('post_hide', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline" method="post">
  427. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  428. <button type="submit" class="btn btn-link btn-hide tooltip-top" title="{% trans %}Hide this reply from other users{% endtrans %}">{% trans %}Hide{% endtrans %}</button>
  429. </form>
  430. {% endif %}
  431. {% endif %}
  432. {% if acl.threads.can_delete_post(user, forum, thread, post) == 2 -%}
  433. <form action="{{ url('post_delete', thread=thread.pk, slug=thread.slug, post=post.pk) }}" class="form-inline prompt-delete-post" method="post">
  434. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  435. <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this reply for good{% endtrans %}">{% trans %}Delete{% endtrans %}</button>
  436. </form>
  437. {% endif %}
  438. </div>
  439. {% endif %}
  440. {% endif %}
  441. {% endfilter %}</div>
  442. </div>
  443. </div>
  444. {% endif %}
  445. </div>
  446. {% if post.checkpoints_visible %}
  447. <div class="post-checkpoints">
  448. {% for checkpoint in post.checkpoints_visible %}
  449. <div class="post-checkpoint{% if checkpoint.deleted %} checkpoint-deleted{% endif %}">
  450. <hr>
  451. <span>
  452. {%- if checkpoint.action == 'limit' -%}
  453. <i class="icon-lock"></i> {% trans %}This thread has reached its post limit and has been closed.{% endtrans %}
  454. {%- elif checkpoint.action == 'accepted' -%}
  455. <i class="icon-ok"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} accepted this thread {{ date }}{% endtrans %}
  456. {%- elif checkpoint.action == 'closed' -%}
  457. <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} closed this thread {{ date }}{% endtrans %}
  458. {%- elif checkpoint.action == 'opened' -%}
  459. <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} opened this thread {{ date }}{% endtrans %}
  460. {%- elif checkpoint.action == 'deleted' -%}
  461. <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} deleted this thread {{ date }}{% endtrans %}
  462. {%- elif checkpoint.action == 'undeleted' -%}
  463. <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} restored this thread {{ date }}{% endtrans %}
  464. {%- elif checkpoint.action == 'moved' and acl.forums.can_see(checkpoint.old_forum_id) -%}
  465. <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 %}
  466. {%- elif checkpoint.action == 'changed_prefix' -%}
  467. <i class="icon-tag"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low, prefix=_(checkpoint.extra) %}{{ user }} changed this thread's prefix to "{{ prefix }}" {{ date }}{% endtrans %}
  468. {%- elif checkpoint.action == 'removed_prefix' -%}
  469. <i class="icon-tag"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} removed this thread's prefix {{ date }}{% endtrans %}
  470. {%- endif -%}
  471. {% if user.is_authenticated() %}
  472. {% if acl.threads.can_delete_checkpoint(forum) %}
  473. {% if checkpoint.deleted %}
  474. <form action="{{ url('post_checkpoint_show', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline">
  475. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  476. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  477. <button type="submit" class="btn btn-link btn-show">{% trans %}Restore{% endtrans %}</button>
  478. </form>
  479. {% else %}
  480. <form action="{{ url('post_checkpoint_hide', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline">
  481. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  482. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  483. <button type="submit" class="btn btn-link btn-hide">{% trans %}Hide{% endtrans %}</button>
  484. </form>
  485. {% endif %}
  486. {% endif %}
  487. {% if acl.threads.can_delete_checkpoint(forum) == 2 %}
  488. <form action="{{ url('post_checkpoint_delete', slug=thread.slug, thread=thread.pk, checkpoint=checkpoint.pk) }}" method="post" class="form-inline prompt-delete-checkpoint">
  489. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  490. <input type="hidden" name="retreat" value="{{ request_path }}#post-{{ post.pk }}">
  491. <button type="submit" class="btn btn-link btn-delete">{% trans %}Delete{% endtrans %}</button>
  492. </form>
  493. {% endif %}
  494. {% endif %}
  495. </span>
  496. </div>
  497. {% endfor %}
  498. </div>
  499. {% endif %}
  500. {% endfor %}
  501. </div>
  502. {% if user.is_authenticated() and (thread_form or posts_form) %}
  503. <div class="thread-moderation">
  504. {% if thread_form %}
  505. <form id="thread_form" class="form-inline pull-left" action="{{ request_path }}" method="POST">
  506. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  507. <input type="hidden" name="origin" value="thread_form">
  508. {{ form_theme.field(thread_form.thread_action, attrs={'class': 'span3'}) }}
  509. <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
  510. </form>
  511. {% endif %}
  512. {% if posts_form %}
  513. <form id="posts_form" class="form-inline pull-right" action="{{ request_path }}" method="POST">
  514. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  515. <input type="hidden" name="origin" value="posts_form">
  516. {{ form_theme.field(posts_form.list_action, attrs={'class': 'span3'}) }}
  517. <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
  518. </form>
  519. {% endif %}
  520. </div>
  521. {% endif %}
  522. <div class="thread-buttons">
  523. {{ pager(false) }}
  524. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  525. <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>
  526. {% elif not user.is_authenticated() and not user.is_crawler() %}
  527. <p class="lead thread-signin-message"><a href="{{ url('sign_in') }}">{% trans %}Sign in or register to reply.{% endtrans %}</a></p>
  528. {% endif %}
  529. </div>
  530. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  531. <div class="thread-quick-reply">
  532. <form action="{{ url('thread_reply', thread=thread.pk, slug=thread.slug) }}" method="post">
  533. <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
  534. <input type="hidden" name="quick_reply" value="1">
  535. <img src="{{ user.get_avatar(100) }}" alt="{% trans %}Your Avatar{% endtrans %}" class="user-avatar">
  536. {{ editor.editor(quick_reply.post, _('Post Reply'), zen=True, extra=editor_extra()) }}
  537. </form>
  538. </div>
  539. {% endif %}
  540. </div>
  541. {% endblock %}
  542. {% block stylesheets %}{{ super() }}
  543. <link href="{{ STATIC_URL }}cranefly/highlight/styles/monokai.css" rel="stylesheet">
  544. {% endblock %}
  545. {% block javascripts -%}
  546. {{ editor.zen() }}
  547. {{ super() }}
  548. <script src="{{ STATIC_URL }}cranefly/highlight/highlight.pack.js"></script>
  549. <script type="text/javascript">
  550. var l_post_reported = "{{ _('Reported!') }}";
  551. hljs.tabReplace = ' ';
  552. hljs.initHighlightingOnLoad();
  553. EnhancePostsMD();
  554. {%- if user.is_authenticated() %}
  555. $(function () {
  556. $('#thread_form').submit(function() {
  557. if ($('#id_thread_action').val() == 'hard') {
  558. var decision = confirm("{% trans %}Are you sure you want to delete this thread? This action is not reversible!{% endtrans %}");
  559. return decision;
  560. }
  561. return true;
  562. });
  563. $('#posts_form').submit(function() {
  564. if ($('.post-checkbox[]:checked').length == 0) {
  565. alert("{% trans %}You have to select at least one post.{% endtrans %}");
  566. return false;
  567. }
  568. if ($('#id_list_action').val() == 'merge') {
  569. if ($('.post-checkbox[]:checked').length < 2) {
  570. alert("{% trans %}You have to select at least two posts you want to merge.{% endtrans %}");
  571. return false;
  572. }
  573. var decision = confirm("{% trans %}Are you sure you want to merge selected posts? This action is not reversible!{% endtrans %}");
  574. return decision;
  575. }
  576. if ($('#id_list_action').val() == 'hard') {
  577. var decision = confirm("{% trans %}Are you sure you want to delete selected posts? This action is not reversible!{% endtrans %}");
  578. return decision;
  579. }
  580. return true;
  581. });
  582. $('.prompt-delete-thread').submit(function() {
  583. var decision = confirm("{% trans %}Are you sure you want to delete this thread?{% endtrans %}");
  584. return decision;
  585. });
  586. $('.prompt-delete-post').submit(function() {
  587. var decision = confirm("{% trans %}Are you sure you want to delete this post?{% endtrans %}");
  588. return decision;
  589. });
  590. $('.prompt-delete-checkpoint').submit(function() {
  591. var decision = confirm("{% trans %}Are you sure you want to delete this checkpoint?{% endtrans %}");
  592. return decision;
  593. });
  594. });
  595. {% endif %}
  596. </script>
  597. {% if user.is_authenticated() and acl.threads.can_reply(forum, thread) %}
  598. {{ editor.js() }}
  599. {% endif %}
  600. {%- endblock %}
  601. {% macro user_label(user) -%}
  602. <{% 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 %}>
  603. {%- endmacro %}
  604. {% macro pager(extra=true) %}
  605. <div class="pagination pull-left">
  606. <ul>
  607. {% if pagination['total'] > 0 %}
  608. <li class="count">{{ macros.pager_label(pagination) }}</li>
  609. {%- 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 -%}
  610. {%- 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 -%}
  611. {%- 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 -%}
  612. {%- 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 -%}
  613. {% endif %}
  614. {% if extra and user.is_authenticated() %}
  615. {% 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 %}
  616. {% 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 %}
  617. {% 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 %}
  618. {% endif %}
  619. </ul>
  620. </div>
  621. {% endmacro %}
  622. {% macro checkpoint_user(checkpoint) -%}
  623. {%- if checkpoint.user_id -%}
  624. <a href="{{ url('user', user=checkpoint.user_id, username=checkpoint.user_slug) }}">{{ checkpoint.user_name }}</a>
  625. {%- else -%}
  626. <strong>{{ checkpoint.user_name }}</strong>
  627. {%- endif -%}
  628. {%- endmacro %}
  629. {% macro checkpoint_forum(checkpoint) -%}
  630. {%- if checkpoint.old_forum_id -%}
  631. <a href="{{ url('forum', forum=checkpoint.old_forum_id, slug=checkpoint.old_forum_slug) }}">{{ checkpoint.old_forum_name }}</a>
  632. {%- else -%}
  633. <strong>{{ checkpoint.old_forum_name }}</strong>
  634. {%- endif -%}
  635. {%- endmacro %}
  636. {% macro edit_user(post) -%}
  637. {%- if post.edit_user_id -%}
  638. <a href="{{ url('user', user=post.edit_user_id, username=post.edit_user_slug) }}">{{ post.edit_user_name }}</a>
  639. {%- else -%}
  640. <strong>{{ post.edit_user_name }}</strong>
  641. {%- endif -%}
  642. {%- endmacro %}
  643. {% macro editor_extra() %}
  644. <button id="editor-preview" name="preview" type="submit" class="btn pull-right">{% trans %}Full Editor{% endtrans %}</button>
  645. {% endmacro %}