##// END OF EJS Templates
Updated "preview" button style
neko259 -
r1313:309c5363 default
parent child Browse files
Show More
@@ -1,551 +1,549 b''
1 * {
1 * {
2 text-decoration: none;
2 text-decoration: none;
3 font-weight: inherit;
3 font-weight: inherit;
4 }
4 }
5
5
6 b, strong {
6 b, strong {
7 font-weight: bold;
7 font-weight: bold;
8 }
8 }
9
9
10 html {
10 html {
11 background: #555;
11 background: #555;
12 color: #ffffff;
12 color: #ffffff;
13 }
13 }
14
14
15 body {
15 body {
16 margin: 0;
16 margin: 0;
17 }
17 }
18
18
19 #admin_panel {
19 #admin_panel {
20 background: #FF0000;
20 background: #FF0000;
21 color: #00FF00
21 color: #00FF00
22 }
22 }
23
23
24 .input_field_error {
24 .input_field_error {
25 color: #FF0000;
25 color: #FF0000;
26 }
26 }
27
27
28 .title {
28 .title {
29 font-weight: bold;
29 font-weight: bold;
30 color: #ffcc00;
30 color: #ffcc00;
31 }
31 }
32
32
33 .link, a {
33 .link, a {
34 color: #afdcec;
34 color: #afdcec;
35 }
35 }
36
36
37 .block {
37 .block {
38 display: inline-block;
38 display: inline-block;
39 vertical-align: top;
39 vertical-align: top;
40 }
40 }
41
41
42 .tag {
42 .tag {
43 color: #FFD37D;
43 color: #FFD37D;
44 }
44 }
45
45
46 .post_id {
46 .post_id {
47 color: #fff380;
47 color: #fff380;
48 }
48 }
49
49
50 .post, .dead_post, .archive_post, #posts-table {
50 .post, .dead_post, .archive_post, #posts-table {
51 background: #333;
51 background: #333;
52 padding: 10px;
52 padding: 10px;
53 clear: left;
53 clear: left;
54 word-wrap: break-word;
54 word-wrap: break-word;
55 border-top: 1px solid #777;
55 border-top: 1px solid #777;
56 border-bottom: 1px solid #777;
56 border-bottom: 1px solid #777;
57 }
57 }
58
58
59 .post + .post {
59 .post + .post {
60 border-top: none;
60 border-top: none;
61 }
61 }
62
62
63 .dead_post + .dead_post {
63 .dead_post + .dead_post {
64 border-top: none;
64 border-top: none;
65 }
65 }
66
66
67 .archive_post + .archive_post {
67 .archive_post + .archive_post {
68 border-top: none;
68 border-top: none;
69 }
69 }
70
70
71 .metadata {
71 .metadata {
72 padding-top: 5px;
72 padding-top: 5px;
73 margin-top: 10px;
73 margin-top: 10px;
74 border-top: solid 1px #666;
74 border-top: solid 1px #666;
75 color: #ddd;
75 color: #ddd;
76 }
76 }
77
77
78 .navigation_panel, .tag_info {
78 .navigation_panel, .tag_info {
79 background: #222;
79 background: #222;
80 margin-bottom: 5px;
80 margin-bottom: 5px;
81 margin-top: 5px;
81 margin-top: 5px;
82 padding: 10px;
82 padding: 10px;
83 border-bottom: solid 1px #888;
83 border-bottom: solid 1px #888;
84 border-top: solid 1px #888;
84 border-top: solid 1px #888;
85 color: #eee;
85 color: #eee;
86 }
86 }
87
87
88 .navigation_panel .link:first-child {
88 .navigation_panel .link:first-child {
89 border-right: 1px solid #fff;
89 border-right: 1px solid #fff;
90 font-weight: bold;
90 font-weight: bold;
91 margin-right: 1ex;
91 margin-right: 1ex;
92 padding-right: 1ex;
92 padding-right: 1ex;
93 }
93 }
94
94
95 .navigation_panel .right-link {
95 .navigation_panel .right-link {
96 border-left: 1px solid #fff;
96 border-left: 1px solid #fff;
97 border-right: none;
97 border-right: none;
98 float: right;
98 float: right;
99 margin-left: 1ex;
99 margin-left: 1ex;
100 margin-right: 0;
100 margin-right: 0;
101 padding-left: 1ex;
101 padding-left: 1ex;
102 padding-right: 0;
102 padding-right: 0;
103 }
103 }
104
104
105 .navigation_panel .link {
105 .navigation_panel .link {
106 font-weight: bold;
106 font-weight: bold;
107 }
107 }
108
108
109 .navigation_panel::after, .post::after {
109 .navigation_panel::after, .post::after {
110 clear: both;
110 clear: both;
111 content: ".";
111 content: ".";
112 display: block;
112 display: block;
113 height: 0;
113 height: 0;
114 line-height: 0;
114 line-height: 0;
115 visibility: hidden;
115 visibility: hidden;
116 }
116 }
117
117
118 .header {
118 .header {
119 border-bottom: solid 2px #ccc;
119 border-bottom: solid 2px #ccc;
120 margin-bottom: 5px;
120 margin-bottom: 5px;
121 border-top: none;
121 border-top: none;
122 margin-top: 0;
122 margin-top: 0;
123 }
123 }
124
124
125 .footer {
125 .footer {
126 border-top: solid 2px #ccc;
126 border-top: solid 2px #ccc;
127 margin-top: 5px;
127 margin-top: 5px;
128 border-bottom: none;
128 border-bottom: none;
129 margin-bottom: 0;
129 margin-bottom: 0;
130 }
130 }
131
131
132 p, .br {
132 p, .br {
133 margin-top: .5em;
133 margin-top: .5em;
134 margin-bottom: .5em;
134 margin-bottom: .5em;
135 }
135 }
136
136
137 .post-form-w {
137 .post-form-w {
138 background: #333344;
138 background: #333344;
139 border-top: solid 1px #888;
139 border-top: solid 1px #888;
140 border-bottom: solid 1px #888;
140 border-bottom: solid 1px #888;
141 color: #fff;
141 color: #fff;
142 padding: 10px;
142 padding: 10px;
143 margin-bottom: 5px;
143 margin-bottom: 5px;
144 margin-top: 5px;
144 margin-top: 5px;
145 }
145 }
146
146
147 .form-row {
147 .form-row {
148 width: 100%;
148 width: 100%;
149 display: table-row;
149 display: table-row;
150 }
150 }
151
151
152 .form-label {
152 .form-label {
153 padding: .25em 1ex .25em 0;
153 padding: .25em 1ex .25em 0;
154 vertical-align: top;
154 vertical-align: top;
155 display: table-cell;
155 display: table-cell;
156 }
156 }
157
157
158 .form-input {
158 .form-input {
159 padding: .25em 0;
159 padding: .25em 0;
160 width: 100%;
160 width: 100%;
161 display: table-cell;
161 display: table-cell;
162 }
162 }
163
163
164 .form-errors {
164 .form-errors {
165 font-weight: bolder;
165 font-weight: bolder;
166 vertical-align: middle;
166 vertical-align: middle;
167 display: table-cell;
167 display: table-cell;
168 }
168 }
169
169
170 .post-form input:not([name="image"]):not([type="checkbox"]):not([type="submit"]), .post-form textarea, .post-form select {
170 .post-form input:not([name="image"]):not([type="checkbox"]):not([type="submit"]), .post-form textarea, .post-form select {
171 background: #333;
171 background: #333;
172 color: #fff;
172 color: #fff;
173 border: solid 1px;
173 border: solid 1px;
174 padding: 0;
174 padding: 0;
175 font: medium sans-serif;
175 font: medium sans-serif;
176 width: 100%;
176 width: 100%;
177 }
177 }
178
178
179 .post-form textarea {
179 .post-form textarea {
180 resize: vertical;
180 resize: vertical;
181 }
181 }
182
182
183 .form-submit {
183 .form-submit {
184 display: table;
184 display: table;
185 margin-bottom: 1ex;
185 margin-bottom: 1ex;
186 margin-top: 1ex;
186 margin-top: 1ex;
187 }
187 }
188
188
189 .form-title {
189 .form-title {
190 font-weight: bold;
190 font-weight: bold;
191 font-size: 2ex;
191 font-size: 2ex;
192 margin-bottom: 0.5ex;
192 margin-bottom: 0.5ex;
193 }
193 }
194
194
195 input[type="submit"] {
195 input[type="submit"], button {
196 background: #222;
196 background: #222;
197 border: solid 2px #fff;
197 border: solid 2px #fff;
198 color: #fff;
198 color: #fff;
199 padding: 0.5ex;
199 padding: 0.5ex;
200 }
200 }
201
201
202 input[type="submit"]:hover {
202 input[type="submit"]:hover {
203 background: #060;
203 background: #060;
204 }
204 }
205
205
206 button:hover {
207 background: #006;
208 }
209
206 blockquote {
210 blockquote {
207 border-left: solid 2px;
211 border-left: solid 2px;
208 padding-left: 5px;
212 padding-left: 5px;
209 color: #B1FB17;
213 color: #B1FB17;
210 margin: 0;
214 margin: 0;
211 }
215 }
212
216
213 .post > .image {
217 .post > .image {
214 float: left;
218 float: left;
215 margin: 0 1ex .5ex 0;
219 margin: 0 1ex .5ex 0;
216 min-width: 1px;
220 min-width: 1px;
217 text-align: center;
221 text-align: center;
218 display: table-row;
222 display: table-row;
219 }
223 }
220
224
221 .post > .metadata {
225 .post > .metadata {
222 clear: left;
226 clear: left;
223 }
227 }
224
228
225 .get {
229 .get {
226 font-weight: bold;
230 font-weight: bold;
227 color: #d55;
231 color: #d55;
228 }
232 }
229
233
230 * {
234 * {
231 text-decoration: none;
235 text-decoration: none;
232 }
236 }
233
237
234 .dead_post > .post-info {
238 .dead_post > .post-info {
235 font-style: italic;
239 font-style: italic;
236 }
240 }
237
241
238 .archive_post > .post-info {
242 .archive_post > .post-info {
239 text-decoration: line-through;
243 text-decoration: line-through;
240 }
244 }
241
245
242 .mark_btn {
246 .mark_btn {
243 border: 1px solid;
247 border: 1px solid;
244 padding: 2px 2ex;
248 padding: 2px 2ex;
245 display: inline-block;
249 display: inline-block;
246 margin: 0 5px 4px 0;
250 margin: 0 5px 4px 0;
247 }
251 }
248
252
249 .mark_btn:hover {
253 .mark_btn:hover {
250 background: #555;
254 background: #555;
251 }
255 }
252
256
253 .quote {
257 .quote {
254 color: #92cf38;
258 color: #92cf38;
255 font-style: italic;
259 font-style: italic;
256 }
260 }
257
261
258 .multiquote {
262 .multiquote {
259 padding: 3px;
263 padding: 3px;
260 display: inline-block;
264 display: inline-block;
261 background: #222;
265 background: #222;
262 border-style: solid;
266 border-style: solid;
263 border-width: 1px 1px 1px 4px;
267 border-width: 1px 1px 1px 4px;
264 font-size: 0.9em;
268 font-size: 0.9em;
265 }
269 }
266
270
267 .spoiler {
271 .spoiler {
268 background: black;
272 background: black;
269 color: black;
273 color: black;
270 padding: 0 1ex 0 1ex;
274 padding: 0 1ex 0 1ex;
271 }
275 }
272
276
273 .spoiler:hover {
277 .spoiler:hover {
274 color: #ddd;
278 color: #ddd;
275 }
279 }
276
280
277 .comment {
281 .comment {
278 color: #eb2;
282 color: #eb2;
279 }
283 }
280
284
281 a:hover {
285 a:hover {
282 text-decoration: underline;
286 text-decoration: underline;
283 }
287 }
284
288
285 .last-replies {
289 .last-replies {
286 margin-left: 3ex;
290 margin-left: 3ex;
287 margin-right: 3ex;
291 margin-right: 3ex;
288 border-left: solid 1px #777;
292 border-left: solid 1px #777;
289 border-right: solid 1px #777;
293 border-right: solid 1px #777;
290 }
294 }
291
295
292 .last-replies > .post:first-child {
296 .last-replies > .post:first-child {
293 border-top: none;
297 border-top: none;
294 }
298 }
295
299
296 .thread {
300 .thread {
297 margin-bottom: 3ex;
301 margin-bottom: 3ex;
298 margin-top: 1ex;
302 margin-top: 1ex;
299 }
303 }
300
304
301 .post:target {
305 .post:target {
302 border: solid 2px white;
306 border: solid 2px white;
303 }
307 }
304
308
305 pre{
309 pre{
306 white-space:pre-wrap
310 white-space:pre-wrap
307 }
311 }
308
312
309 li {
313 li {
310 list-style-position: inside;
314 list-style-position: inside;
311 }
315 }
312
316
313 .fancybox-skin {
317 .fancybox-skin {
314 position: relative;
318 position: relative;
315 background-color: #fff;
319 background-color: #fff;
316 color: #ddd;
320 color: #ddd;
317 text-shadow: none;
321 text-shadow: none;
318 }
322 }
319
323
320 .fancybox-image {
324 .fancybox-image {
321 border: 1px solid black;
325 border: 1px solid black;
322 }
326 }
323
327
324 .image-mode-tab {
328 .image-mode-tab {
325 background: #444;
329 background: #444;
326 color: #eee;
330 color: #eee;
327 margin-top: 5px;
331 margin-top: 5px;
328 padding: 5px;
332 padding: 5px;
329 border-top: 1px solid #888;
333 border-top: 1px solid #888;
330 border-bottom: 1px solid #888;
334 border-bottom: 1px solid #888;
331 }
335 }
332
336
333 .image-mode-tab > label {
337 .image-mode-tab > label {
334 margin: 0 1ex;
338 margin: 0 1ex;
335 }
339 }
336
340
337 .image-mode-tab > label > input {
341 .image-mode-tab > label > input {
338 margin-right: .5ex;
342 margin-right: .5ex;
339 }
343 }
340
344
341 #posts-table {
345 #posts-table {
342 margin-top: 5px;
346 margin-top: 5px;
343 margin-bottom: 5px;
347 margin-bottom: 5px;
344 }
348 }
345
349
346 .tag_info > h2 {
350 .tag_info > h2 {
347 margin: 0;
351 margin: 0;
348 }
352 }
349
353
350 .post-info {
354 .post-info {
351 color: #ddd;
355 color: #ddd;
352 margin-bottom: 1ex;
356 margin-bottom: 1ex;
353 }
357 }
354
358
355 .moderator_info {
359 .moderator_info {
356 color: #e99d41;
360 color: #e99d41;
357 opacity: 0.4;
361 opacity: 0.4;
358 }
362 }
359
363
360 .moderator_info:hover {
364 .moderator_info:hover {
361 opacity: 1;
365 opacity: 1;
362 }
366 }
363
367
364 .refmap {
368 .refmap {
365 font-size: 0.9em;
369 font-size: 0.9em;
366 color: #ccc;
370 color: #ccc;
367 margin-top: 1em;
371 margin-top: 1em;
368 }
372 }
369
373
370 .fav {
374 .fav {
371 color: yellow;
375 color: yellow;
372 }
376 }
373
377
374 .not_fav {
378 .not_fav {
375 color: #ccc;
379 color: #ccc;
376 }
380 }
377
381
378 .role {
382 .role {
379 text-decoration: underline;
383 text-decoration: underline;
380 }
384 }
381
385
382 .form-email {
386 .form-email {
383 display: none;
387 display: none;
384 }
388 }
385
389
386 .bar-value {
390 .bar-value {
387 background: rgba(50, 55, 164, 0.45);
391 background: rgba(50, 55, 164, 0.45);
388 font-size: 0.9em;
392 font-size: 0.9em;
389 height: 1.5em;
393 height: 1.5em;
390 }
394 }
391
395
392 .bar-bg {
396 .bar-bg {
393 position: relative;
397 position: relative;
394 border-top: solid 1px #888;
398 border-top: solid 1px #888;
395 border-bottom: solid 1px #888;
399 border-bottom: solid 1px #888;
396 margin-top: 5px;
400 margin-top: 5px;
397 overflow: hidden;
401 overflow: hidden;
398 }
402 }
399
403
400 .bar-text {
404 .bar-text {
401 padding: 2px;
405 padding: 2px;
402 position: absolute;
406 position: absolute;
403 left: 0;
407 left: 0;
404 top: 0;
408 top: 0;
405 }
409 }
406
410
407 .page_link {
411 .page_link {
408 background: #444;
412 background: #444;
409 border-top: solid 1px #888;
413 border-top: solid 1px #888;
410 border-bottom: solid 1px #888;
414 border-bottom: solid 1px #888;
411 padding: 5px;
415 padding: 5px;
412 color: #eee;
416 color: #eee;
413 font-size: 2ex;
417 font-size: 2ex;
414 }
418 }
415
419
416 .skipped_replies {
420 .skipped_replies {
417 padding: 5px;
421 padding: 5px;
418 margin-left: 3ex;
422 margin-left: 3ex;
419 margin-right: 3ex;
423 margin-right: 3ex;
420 border-left: solid 1px #888;
424 border-left: solid 1px #888;
421 border-right: solid 1px #888;
425 border-right: solid 1px #888;
422 border-bottom: solid 1px #888;
426 border-bottom: solid 1px #888;
423 background: #000;
427 background: #000;
424 }
428 }
425
429
426 .current_page {
430 .current_page {
427 padding: 2px;
431 padding: 2px;
428 background-color: #afdcec;
432 background-color: #afdcec;
429 color: #000;
433 color: #000;
430 }
434 }
431
435
432 .current_mode {
436 .current_mode {
433 font-weight: bold;
437 font-weight: bold;
434 }
438 }
435
439
436 .gallery_image {
440 .gallery_image {
437 border: solid 1px;
441 border: solid 1px;
438 padding: 0.5ex;
442 padding: 0.5ex;
439 margin: 0.5ex;
443 margin: 0.5ex;
440 text-align: center;
444 text-align: center;
441 }
445 }
442
446
443 code {
447 code {
444 border: dashed 1px #ccc;
448 border: dashed 1px #ccc;
445 background: #111;
449 background: #111;
446 padding: 2px;
450 padding: 2px;
447 font-size: 1.2em;
451 font-size: 1.2em;
448 display: inline-block;
452 display: inline-block;
449 }
453 }
450
454
451 pre {
455 pre {
452 overflow: auto;
456 overflow: auto;
453 }
457 }
454
458
455 .img-full {
459 .img-full {
456 background: #222;
460 background: #222;
457 border: solid 1px white;
461 border: solid 1px white;
458 }
462 }
459
463
460 .tag_item {
464 .tag_item {
461 display: inline-block;
465 display: inline-block;
462 }
466 }
463
467
464 #id_models li {
468 #id_models li {
465 list-style: none;
469 list-style: none;
466 }
470 }
467
471
468 #id_q {
472 #id_q {
469 margin-left: 1ex;
473 margin-left: 1ex;
470 }
474 }
471
475
472 ul {
476 ul {
473 padding-left: 0px;
477 padding-left: 0px;
474 }
478 }
475
479
476 .quote-header {
480 .quote-header {
477 border-bottom: 2px solid #ddd;
481 border-bottom: 2px solid #ddd;
478 margin-bottom: 1ex;
482 margin-bottom: 1ex;
479 padding-bottom: .5ex;
483 padding-bottom: .5ex;
480 color: #ddd;
484 color: #ddd;
481 font-size: 1.2em;
485 font-size: 1.2em;
482 }
486 }
483
487
484 /* Reflink preview */
488 /* Reflink preview */
485 .post_preview {
489 .post_preview {
486 border-left: 1px solid #777;
490 border-left: 1px solid #777;
487 border-right: 1px solid #777;
491 border-right: 1px solid #777;
488 max-width: 600px;
492 max-width: 600px;
489 }
493 }
490
494
491 /* Code highlighter */
495 /* Code highlighter */
492 .hljs {
496 .hljs {
493 color: #fff;
497 color: #fff;
494 background: #000;
498 background: #000;
495 display: inline-block;
499 display: inline-block;
496 }
500 }
497
501
498 .hljs, .hljs-subst, .hljs-tag .hljs-title, .lisp .hljs-title, .clojure .hljs-built_in, .nginx .hljs-title {
502 .hljs, .hljs-subst, .hljs-tag .hljs-title, .lisp .hljs-title, .clojure .hljs-built_in, .nginx .hljs-title {
499 color: #fff;
503 color: #fff;
500 }
504 }
501
505
502 #up {
506 #up {
503 position: fixed;
507 position: fixed;
504 bottom: 5px;
508 bottom: 5px;
505 right: 5px;
509 right: 5px;
506 border: 1px solid #777;
510 border: 1px solid #777;
507 background: #000;
511 background: #000;
508 padding: 4px;
512 padding: 4px;
509 }
513 }
510
514
511 .user-cast {
515 .user-cast {
512 border: solid #ffffff 1px;
516 border: solid #ffffff 1px;
513 padding: .2ex;
517 padding: .2ex;
514 background: #152154;
518 background: #152154;
515 color: #fff;
519 color: #fff;
516 }
520 }
517
521
518 .highlight {
522 .highlight {
519 background: #222;
523 background: #222;
520 }
524 }
521
525
522 .post-button-form > button:hover {
526 .post-button-form > button:hover {
523 text-decoration: underline;
527 text-decoration: underline;
524 }
528 }
525
529
526 .tree_reply > .post {
530 .tree_reply > .post {
527 margin-top: 1ex;
531 margin-top: 1ex;
528 border-left: solid 1px #777;
532 border-left: solid 1px #777;
529 padding-right: 0;
533 padding-right: 0;
530 }
534 }
531
535
532 #preview-text {
536 #preview-text {
533 border: solid 1px white;
537 border: solid 1px white;
534 margin: 1ex 0 1ex 0;
538 margin: 1ex 0 1ex 0;
535 padding: 1ex;
539 padding: 1ex;
536 }
540 }
537
541
538 button {
539 border: 1px solid white;
540 margin-bottom: .5ex;
541 margin-top: .5ex;
542 }
543
544 .image-metadata {
542 .image-metadata {
545 font-style: italic;
543 font-style: italic;
546 font-size: 0.9em;
544 font-size: 0.9em;
547 }
545 }
548
546
549 .tripcode {
547 .tripcode {
550 color: white;
548 color: white;
551 }
549 }
@@ -1,389 +1,411 b''
1 /*
1 /*
2 @licstart The following is the entire license notice for the
2 @licstart The following is the entire license notice for the
3 JavaScript code in this page.
3 JavaScript code in this page.
4
4
5
5
6 Copyright (C) 2013-2014 neko259
6 Copyright (C) 2013-2014 neko259
7
7
8 The JavaScript code in this page is free software: you can
8 The JavaScript code in this page is free software: you can
9 redistribute it and/or modify it under the terms of the GNU
9 redistribute it and/or modify it under the terms of the GNU
10 General Public License (GNU GPL) as published by the Free Software
10 General Public License (GNU GPL) as published by the Free Software
11 Foundation, either version 3 of the License, or (at your option)
11 Foundation, either version 3 of the License, or (at your option)
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
12 any later version. The code is distributed WITHOUT ANY WARRANTY;
13 without even the implied warranty of MERCHANTABILITY or FITNESS
13 without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
15
15
16 As additional permission under GNU GPL version 3 section 7, you
16 As additional permission under GNU GPL version 3 section 7, you
17 may distribute non-source (e.g., minimized or compacted) forms of
17 may distribute non-source (e.g., minimized or compacted) forms of
18 that code without the copy of the GNU GPL normally required by
18 that code without the copy of the GNU GPL normally required by
19 section 4, provided you include this license notice and a URL
19 section 4, provided you include this license notice and a URL
20 through which recipients can access the Corresponding Source.
20 through which recipients can access the Corresponding Source.
21
21
22 @licend The above is the entire license notice
22 @licend The above is the entire license notice
23 for the JavaScript code in this page.
23 for the JavaScript code in this page.
24 */
24 */
25
25
26 var CLASS_POST = '.post'
26 var CLASS_POST = '.post'
27
27
28 var POST_ADDED = 0;
28 var POST_ADDED = 0;
29 var POST_UPDATED = 1;
29 var POST_UPDATED = 1;
30
30
31 var JS_AUTOUPDATE_PERIOD = 20000;
31 var JS_AUTOUPDATE_PERIOD = 20000;
32
32
33 var wsUser = '';
33 var wsUser = '';
34
34
35 var unreadPosts = 0;
35 var unreadPosts = 0;
36 var documentOriginalTitle = '';
36 var documentOriginalTitle = '';
37
37
38 // Thread ID does not change, can be stored one time
38 // Thread ID does not change, can be stored one time
39 var threadId = $('div.thread').children(CLASS_POST).first().attr('id');
39 var threadId = $('div.thread').children(CLASS_POST).first().attr('id');
40
40
41 /**
41 /**
42 * Connect to websocket server and subscribe to thread updates. On any update we
42 * Connect to websocket server and subscribe to thread updates. On any update we
43 * request a thread diff.
43 * request a thread diff.
44 *
44 *
45 * @returns {boolean} true if connected, false otherwise
45 * @returns {boolean} true if connected, false otherwise
46 */
46 */
47 function connectWebsocket() {
47 function connectWebsocket() {
48 var metapanel = $('.metapanel')[0];
48 var metapanel = $('.metapanel')[0];
49
49
50 var wsHost = metapanel.getAttribute('data-ws-host');
50 var wsHost = metapanel.getAttribute('data-ws-host');
51 var wsPort = metapanel.getAttribute('data-ws-port');
51 var wsPort = metapanel.getAttribute('data-ws-port');
52
52
53 if (wsHost.length > 0 && wsPort.length > 0) {
53 if (wsHost.length > 0 && wsPort.length > 0) {
54 var centrifuge = new Centrifuge({
54 var centrifuge = new Centrifuge({
55 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
55 "url": 'ws://' + wsHost + ':' + wsPort + "/connection/websocket",
56 "project": metapanel.getAttribute('data-ws-project'),
56 "project": metapanel.getAttribute('data-ws-project'),
57 "user": wsUser,
57 "user": wsUser,
58 "timestamp": metapanel.getAttribute('data-ws-token-time'),
58 "timestamp": metapanel.getAttribute('data-ws-token-time'),
59 "token": metapanel.getAttribute('data-ws-token'),
59 "token": metapanel.getAttribute('data-ws-token'),
60 "debug": false
60 "debug": false
61 });
61 });
62
62
63 centrifuge.on('error', function(error_message) {
63 centrifuge.on('error', function(error_message) {
64 console.log("Error connecting to websocket server.");
64 console.log("Error connecting to websocket server.");
65 console.log(error_message);
65 console.log(error_message);
66 console.log("Using javascript update instead.");
66 console.log("Using javascript update instead.");
67
67
68 // If websockets don't work, enable JS update instead
68 // If websockets don't work, enable JS update instead
69 enableJsUpdate()
69 enableJsUpdate()
70 });
70 });
71
71
72 centrifuge.on('connect', function() {
72 centrifuge.on('connect', function() {
73 var channelName = 'thread:' + threadId;
73 var channelName = 'thread:' + threadId;
74 centrifuge.subscribe(channelName, function(message) {
74 centrifuge.subscribe(channelName, function(message) {
75 getThreadDiff();
75 getThreadDiff();
76 });
76 });
77
77
78 // For the case we closed the browser and missed some updates
78 // For the case we closed the browser and missed some updates
79 getThreadDiff();
79 getThreadDiff();
80 $('#autoupdate').hide();
80 $('#autoupdate').hide();
81 });
81 });
82
82
83 centrifuge.connect();
83 centrifuge.connect();
84
84
85 return true;
85 return true;
86 } else {
86 } else {
87 return false;
87 return false;
88 }
88 }
89 }
89 }
90
90
91 /**
91 /**
92 * Get diff of the posts from the current thread timestamp.
92 * Get diff of the posts from the current thread timestamp.
93 * This is required if the browser was closed and some post updates were
93 * This is required if the browser was closed and some post updates were
94 * missed.
94 * missed.
95 */
95 */
96 function getThreadDiff() {
96 function getThreadDiff() {
97 var lastUpdateTime = $('.metapanel').attr('data-last-update');
97 var lastUpdateTime = $('.metapanel').attr('data-last-update');
98 var lastPostId = $('.post').last().attr('id');
98 var lastPostId = $('.post').last().attr('id');
99
99
100 var uids = '';
100 var uids = '';
101 var posts = $('.post');
101 var posts = $('.post');
102 for (var i = 0; i < posts.length; i++) {
102 for (var i = 0; i < posts.length; i++) {
103 uids += posts[i].getAttribute('data-uid') + ' ';
103 uids += posts[i].getAttribute('data-uid') + ' ';
104 }
104 }
105
105
106 var data = {
106 var data = {
107 uids: uids,
107 uids: uids,
108 thread: threadId
108 thread: threadId
109 }
109 }
110
110
111 var diffUrl = '/api/diff_thread/';
111 var diffUrl = '/api/diff_thread/';
112
112
113 $.post(diffUrl,
113 $.post(diffUrl,
114 data,
114 data,
115 function(data) {
115 function(data) {
116 var updatedPosts = data.updated;
116 var updatedPosts = data.updated;
117 var addedPostCount = 0;
117 var addedPostCount = 0;
118
118
119 for (var i = 0; i < updatedPosts.length; i++) {
119 for (var i = 0; i < updatedPosts.length; i++) {
120 var postText = updatedPosts[i];
120 var postText = updatedPosts[i];
121 var post = $(postText);
121 var post = $(postText);
122
122
123 if (updatePost(post) == POST_ADDED) {
123 if (updatePost(post) == POST_ADDED) {
124 addedPostCount++;
124 addedPostCount++;
125 }
125 }
126 }
126 }
127
127
128 var hasMetaUpdates = updatedPosts.length > 0;
128 var hasMetaUpdates = updatedPosts.length > 0;
129 if (hasMetaUpdates) {
129 if (hasMetaUpdates) {
130 updateMetadataPanel();
130 updateMetadataPanel();
131 }
131 }
132
132
133 if (addedPostCount > 0) {
133 if (addedPostCount > 0) {
134 updateBumplimitProgress(addedPostCount);
134 updateBumplimitProgress(addedPostCount);
135 }
135 }
136
136
137 if (updatedPosts.length > 0) {
137 if (updatedPosts.length > 0) {
138 showNewPostsTitle(addedPostCount);
138 showNewPostsTitle(addedPostCount);
139 }
139 }
140
140
141 // TODO Process removed posts if any
141 // TODO Process removed posts if any
142 $('.metapanel').attr('data-last-update', data.last_update);
142 $('.metapanel').attr('data-last-update', data.last_update);
143 },
143 },
144 'json'
144 'json'
145 )
145 )
146 }
146 }
147
147
148 /**
148 /**
149 * Add or update the post on html page.
149 * Add or update the post on html page.
150 */
150 */
151 function updatePost(postHtml) {
151 function updatePost(postHtml) {
152 // This needs to be set on start because the page is scrolled after posts
152 // This needs to be set on start because the page is scrolled after posts
153 // are added or updated
153 // are added or updated
154 var bottom = isPageBottom();
154 var bottom = isPageBottom();
155
155
156 var post = $(postHtml);
156 var post = $(postHtml);
157
157
158 var threadBlock = $('div.thread');
158 var threadBlock = $('div.thread');
159
159
160 var postId = post.attr('id');
160 var postId = post.attr('id');
161
161
162 // If the post already exists, replace it. Otherwise add as a new one.
162 // If the post already exists, replace it. Otherwise add as a new one.
163 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
163 var existingPosts = threadBlock.children('.post[id=' + postId + ']');
164
164
165 var type;
165 var type;
166
166
167 if (existingPosts.size() > 0) {
167 if (existingPosts.size() > 0) {
168 existingPosts.replaceWith(post);
168 replacePartial(existingPosts.first(), post);
169
169
170 type = POST_UPDATED;
170 type = POST_UPDATED;
171 } else {
171 } else {
172 post.appendTo(threadBlock);
172 post.appendTo(threadBlock);
173
173
174 if (bottom) {
174 if (bottom) {
175 scrollToBottom();
175 scrollToBottom();
176 }
176 }
177
177
178 type = POST_ADDED;
178 type = POST_ADDED;
179 }
179 }
180
180
181 processNewPost(post);
181 processNewPost(post);
182
182
183 return type;
183 return type;
184 }
184 }
185
185
186 /**
186 /**
187 * Initiate a blinking animation on a node to show it was updated.
187 * Initiate a blinking animation on a node to show it was updated.
188 */
188 */
189 function blink(node) {
189 function blink(node) {
190 var blinkCount = 2;
190 var blinkCount = 2;
191
191
192 var nodeToAnimate = node;
192 var nodeToAnimate = node;
193 for (var i = 0; i < blinkCount; i++) {
193 for (var i = 0; i < blinkCount; i++) {
194 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
194 nodeToAnimate = nodeToAnimate.fadeTo('fast', 0.5).fadeTo('fast', 1.0);
195 }
195 }
196 }
196 }
197
197
198 function isPageBottom() {
198 function isPageBottom() {
199 var scroll = $(window).scrollTop() / ($(document).height()
199 var scroll = $(window).scrollTop() / ($(document).height()
200 - $(window).height());
200 - $(window).height());
201
201
202 return scroll == 1
202 return scroll == 1
203 }
203 }
204
204
205 function enableJsUpdate() {
205 function enableJsUpdate() {
206 setInterval(getThreadDiff, JS_AUTOUPDATE_PERIOD);
206 setInterval(getThreadDiff, JS_AUTOUPDATE_PERIOD);
207 return true;
207 return true;
208 }
208 }
209
209
210 function initAutoupdate() {
210 function initAutoupdate() {
211 if (location.protocol === 'https:') {
211 if (location.protocol === 'https:') {
212 return enableJsUpdate();
212 return enableJsUpdate();
213 } else {
213 } else {
214 if (connectWebsocket()) {
214 if (connectWebsocket()) {
215 return true;
215 return true;
216 } else {
216 } else {
217 return enableJsUpdate();
217 return enableJsUpdate();
218 }
218 }
219 }
219 }
220 }
220 }
221
221
222 function getReplyCount() {
222 function getReplyCount() {
223 return $('.thread').children(CLASS_POST).length
223 return $('.thread').children(CLASS_POST).length
224 }
224 }
225
225
226 function getImageCount() {
226 function getImageCount() {
227 return $('.thread').find('img').length
227 return $('.thread').find('img').length
228 }
228 }
229
229
230 /**
230 /**
231 * Update post count, images count and last update time in the metadata
231 * Update post count, images count and last update time in the metadata
232 * panel.
232 * panel.
233 */
233 */
234 function updateMetadataPanel() {
234 function updateMetadataPanel() {
235 var replyCountField = $('#reply-count');
235 var replyCountField = $('#reply-count');
236 var imageCountField = $('#image-count');
236 var imageCountField = $('#image-count');
237
237
238 replyCountField.text(getReplyCount());
238 replyCountField.text(getReplyCount());
239 imageCountField.text(getImageCount());
239 imageCountField.text(getImageCount());
240
240
241 var lastUpdate = $('.post:last').children('.post-info').first()
241 var lastUpdate = $('.post:last').children('.post-info').first()
242 .children('.pub_time').first().html();
242 .children('.pub_time').first().html();
243 if (lastUpdate !== '') {
243 if (lastUpdate !== '') {
244 var lastUpdateField = $('#last-update');
244 var lastUpdateField = $('#last-update');
245 lastUpdateField.html(lastUpdate);
245 lastUpdateField.html(lastUpdate);
246 blink(lastUpdateField);
246 blink(lastUpdateField);
247 }
247 }
248
248
249 blink(replyCountField);
249 blink(replyCountField);
250 blink(imageCountField);
250 blink(imageCountField);
251 }
251 }
252
252
253 /**
253 /**
254 * Update bumplimit progress bar
254 * Update bumplimit progress bar
255 */
255 */
256 function updateBumplimitProgress(postDelta) {
256 function updateBumplimitProgress(postDelta) {
257 var progressBar = $('#bumplimit_progress');
257 var progressBar = $('#bumplimit_progress');
258 if (progressBar) {
258 if (progressBar) {
259 var postsToLimitElement = $('#left_to_limit');
259 var postsToLimitElement = $('#left_to_limit');
260
260
261 var oldPostsToLimit = parseInt(postsToLimitElement.text());
261 var oldPostsToLimit = parseInt(postsToLimitElement.text());
262 var postCount = getReplyCount();
262 var postCount = getReplyCount();
263 var bumplimit = postCount - postDelta + oldPostsToLimit;
263 var bumplimit = postCount - postDelta + oldPostsToLimit;
264
264
265 var newPostsToLimit = bumplimit - postCount;
265 var newPostsToLimit = bumplimit - postCount;
266 if (newPostsToLimit <= 0) {
266 if (newPostsToLimit <= 0) {
267 $('.bar-bg').remove();
267 $('.bar-bg').remove();
268 } else {
268 } else {
269 postsToLimitElement.text(newPostsToLimit);
269 postsToLimitElement.text(newPostsToLimit);
270 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
270 progressBar.width((100 - postCount / bumplimit * 100.0) + '%');
271 }
271 }
272 }
272 }
273 }
273 }
274
274
275 /**
275 /**
276 * Show 'new posts' text in the title if the document is not visible to a user
276 * Show 'new posts' text in the title if the document is not visible to a user
277 */
277 */
278 function showNewPostsTitle(newPostCount) {
278 function showNewPostsTitle(newPostCount) {
279 if (document.hidden) {
279 if (document.hidden) {
280 if (documentOriginalTitle === '') {
280 if (documentOriginalTitle === '') {
281 documentOriginalTitle = document.title;
281 documentOriginalTitle = document.title;
282 }
282 }
283 unreadPosts = unreadPosts + newPostCount;
283 unreadPosts = unreadPosts + newPostCount;
284
284
285 var newTitle = '* ';
285 var newTitle = '* ';
286 if (unreadPosts > 0) {
286 if (unreadPosts > 0) {
287 newTitle += '[' + unreadPosts + '] ';
287 newTitle += '[' + unreadPosts + '] ';
288 }
288 }
289 newTitle += documentOriginalTitle;
289 newTitle += documentOriginalTitle;
290
290
291 document.title = newTitle;
291 document.title = newTitle;
292
292
293 document.addEventListener('visibilitychange', function() {
293 document.addEventListener('visibilitychange', function() {
294 if (documentOriginalTitle !== '') {
294 if (documentOriginalTitle !== '') {
295 document.title = documentOriginalTitle;
295 document.title = documentOriginalTitle;
296 documentOriginalTitle = '';
296 documentOriginalTitle = '';
297 unreadPosts = 0;
297 unreadPosts = 0;
298 }
298 }
299
299
300 document.removeEventListener('visibilitychange', null);
300 document.removeEventListener('visibilitychange', null);
301 });
301 });
302 }
302 }
303 }
303 }
304
304
305 /**
305 /**
306 * Clear all entered values in the form fields
306 * Clear all entered values in the form fields
307 */
307 */
308 function resetForm(form) {
308 function resetForm(form) {
309 form.find('input:text, input:password, input:file, select, textarea').val('');
309 form.find('input:text, input:password, input:file, select, textarea').val('');
310 form.find('input:radio, input:checkbox')
310 form.find('input:radio, input:checkbox')
311 .removeAttr('checked').removeAttr('selected');
311 .removeAttr('checked').removeAttr('selected');
312 $('.file_wrap').find('.file-thumb').remove();
312 $('.file_wrap').find('.file-thumb').remove();
313 $('#preview-text').hide();
313 $('#preview-text').hide();
314 }
314 }
315
315
316 /**
316 /**
317 * When the form is posted, this method will be run as a callback
317 * When the form is posted, this method will be run as a callback
318 */
318 */
319 function updateOnPost(response, statusText, xhr, form) {
319 function updateOnPost(response, statusText, xhr, form) {
320 var json = $.parseJSON(response);
320 var json = $.parseJSON(response);
321 var status = json.status;
321 var status = json.status;
322
322
323 showAsErrors(form, '');
323 showAsErrors(form, '');
324
324
325 if (status === 'ok') {
325 if (status === 'ok') {
326 resetFormPosition();
326 resetFormPosition();
327 resetForm(form);
327 resetForm(form);
328 getThreadDiff();
328 getThreadDiff();
329 scrollToBottom();
329 scrollToBottom();
330 } else {
330 } else {
331 var errors = json.errors;
331 var errors = json.errors;
332 for (var i = 0; i < errors.length; i++) {
332 for (var i = 0; i < errors.length; i++) {
333 var fieldErrors = errors[i];
333 var fieldErrors = errors[i];
334
334
335 var error = fieldErrors.errors;
335 var error = fieldErrors.errors;
336
336
337 showAsErrors(form, error);
337 showAsErrors(form, error);
338 }
338 }
339 }
339 }
340 }
340 }
341
341
342 /**
342 /**
343 * Show text in the errors row of the form.
343 * Show text in the errors row of the form.
344 * @param form
344 * @param form
345 * @param text
345 * @param text
346 */
346 */
347 function showAsErrors(form, text) {
347 function showAsErrors(form, text) {
348 form.children('.form-errors').remove();
348 form.children('.form-errors').remove();
349
349
350 if (text.length > 0) {
350 if (text.length > 0) {
351 var errorList = $('<div class="form-errors">' + text + '<div>');
351 var errorList = $('<div class="form-errors">' + text + '<div>');
352 errorList.appendTo(form);
352 errorList.appendTo(form);
353 }
353 }
354 }
354 }
355
355
356 /**
356 /**
357 * Run js methods that are usually run on the document, on the new post
357 * Run js methods that are usually run on the document, on the new post
358 */
358 */
359 function processNewPost(post) {
359 function processNewPost(post) {
360 addRefLinkPreview(post[0]);
360 addRefLinkPreview(post[0]);
361 highlightCode(post);
361 highlightCode(post);
362 blink(post);
362 blink(post);
363 }
363 }
364
364
365 function replacePartial(oldNode, newNode) {
366 var oldContent = oldNode[0].outerHTML;
367 var newContent = newNode[0].outerHTML;
368
369 // TODO Handle different children sizes
370
371 if (oldContent != newContent) {
372 var children = oldNode.children();
373 if (children.length == 0) {
374 console.log(oldContent);
375 console.log(newContent)
376
377 oldNode.replaceWith(newNode);
378 } else {
379 var newChildren = newNode.children();
380 children.each(function(i) {
381 replacePartial(children.eq(i), newChildren.eq(i));
382 });
383 }
384 }
385 }
386
365 $(document).ready(function(){
387 $(document).ready(function(){
366 if (initAutoupdate()) {
388 if (initAutoupdate()) {
367 // Post form data over AJAX
389 // Post form data over AJAX
368 var threadId = $('div.thread').children('.post').first().attr('id');
390 var threadId = $('div.thread').children('.post').first().attr('id');
369
391
370 var form = $('#form');
392 var form = $('#form');
371
393
372 if (form.length > 0) {
394 if (form.length > 0) {
373 var options = {
395 var options = {
374 beforeSubmit: function(arr, $form, options) {
396 beforeSubmit: function(arr, $form, options) {
375 showAsErrors($('form'), gettext('Sending message...'));
397 showAsErrors($('form'), gettext('Sending message...'));
376 },
398 },
377 success: updateOnPost,
399 success: updateOnPost,
378 error: function() {
400 error: function() {
379 showAsErrors($('form'), gettext('Server error!'));
401 showAsErrors($('form'), gettext('Server error!'));
380 },
402 },
381 url: '/api/add_post/' + threadId + '/'
403 url: '/api/add_post/' + threadId + '/'
382 };
404 };
383
405
384 form.ajaxForm(options);
406 form.ajaxForm(options);
385
407
386 resetForm(form);
408 resetForm(form);
387 }
409 }
388 }
410 }
389 });
411 });
@@ -1,186 +1,186 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.text }}</div>
34 <div>{{ banner.text }}</div>
35 <div>{% trans 'Related message' %}: <a href="{{ banner.post.get_absolute_url }}">>>{{ banner.post.id }}</a></div>
35 <div>{% trans 'Related message' %}: <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">
40 <div class="tag_info">
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.images.first %}
43 {% with image=random_image_post.images.first %}
44 <a href="{{ random_image_post.get_absolute_url }}"><img
44 <a href="{{ random_image_post.get_absolute_url }}"><img
45 src="{{ image.image.url_200x150 }}"
45 src="{{ image.image.url_200x150 }}"
46 width="{{ image.pre_width }}"
46 width="{{ image.pre_width }}"
47 height="{{ image.pre_height }}"/></a>
47 height="{{ image.pre_height }}"/></a>
48 {% endwith %}
48 {% endwith %}
49 </div>
49 </div>
50 {% endif %}
50 {% endif %}
51 <div class="tag-text-data">
51 <div class="tag-text-data">
52 <h2>
52 <h2>
53 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
53 <form action="{% url 'tag' tag.name %}" method="post" class="post-button-form">
54 {% if is_favorite %}
54 {% if is_favorite %}
55 <button name="method" value="unsubscribe" class="fav">β˜…</button>
55 <button name="method" value="unsubscribe" class="fav">β˜…</button>
56 {% else %}
56 {% else %}
57 <button name="method" value="subscribe" class="not_fav">β˜…</button>
57 <button name="method" value="subscribe" class="not_fav">β˜…</button>
58 {% endif %}
58 {% endif %}
59 </form>
59 </form>
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_hidden %}
61 {% if is_hidden %}
62 <button name="method" value="unhide" class="fav">H</button>
62 <button name="method" value="unhide" class="fav">H</button>
63 {% else %}
63 {% else %}
64 <button name="method" value="hide" class="not_fav">H</button>
64 <button name="method" value="hide" class="not_fav">H</button>
65 {% endif %}
65 {% endif %}
66 </form>
66 </form>
67 {{ tag.get_view|safe }}
67 {{ tag.get_view|safe }}
68 {% if moderator %}
68 {% if moderator %}
69 <span class="moderator_info">| <a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></span>
69 <span class="moderator_info">| <a href="{% url 'admin:boards_tag_change' tag.id %}">{% trans 'Edit tag' %}</a></span>
70 {% endif %}
70 {% endif %}
71 </h2>
71 </h2>
72 {% if tag.get_description %}
72 {% if tag.get_description %}
73 <p>{{ tag.get_description|safe }}</p>
73 <p>{{ tag.get_description|safe }}</p>
74 {% endif %}
74 {% endif %}
75 <p>{% blocktrans with active_thread_count=tag.get_active_thread_count thread_count=tag.get_thread_count post_count=tag.get_post_count %}This tag has {{ thread_count }} threads ({{ active_thread_count}} active) and {{ post_count }} posts.{% endblocktrans %}</p>
75 <p>{% blocktrans with active_thread_count=tag.get_active_thread_count thread_count=tag.get_thread_count post_count=tag.get_post_count %}This tag has {{ thread_count }} threads ({{ active_thread_count}} active) and {{ post_count }} posts.{% endblocktrans %}</p>
76 {% if related_tags %}
76 {% if related_tags %}
77 <p>{% trans 'Related tags:' %}
77 <p>{% trans 'Related tags:' %}
78 {% for rel_tag in related_tags %}
78 {% for rel_tag in related_tags %}
79 {{ rel_tag.get_view|safe }}{% if not forloop.last %}, {% else %}.{% endif %}
79 {{ rel_tag.get_view|safe }}{% if not forloop.last %}, {% else %}.{% endif %}
80 {% endfor %}
80 {% endfor %}
81 </p>
81 </p>
82 {% endif %}
82 {% endif %}
83 </div>
83 </div>
84 </div>
84 </div>
85 {% endif %}
85 {% endif %}
86
86
87 {% if threads %}
87 {% if threads %}
88 {% if prev_page_link %}
88 {% if prev_page_link %}
89 <div class="page_link">
89 <div class="page_link">
90 <a href="{{ prev_page_link }}">{% trans "Previous page" %}</a>
90 <a href="{{ prev_page_link }}">{% trans "Previous page" %}</a>
91 </div>
91 </div>
92 {% endif %}
92 {% endif %}
93
93
94 {% for thread in threads %}
94 {% for thread in threads %}
95 <div class="thread">
95 <div class="thread">
96 {% post_view thread.get_opening_post moderator=moderator is_opening=True thread=thread truncated=True need_open_link=True %}
96 {% post_view thread.get_opening_post moderator=moderator is_opening=True thread=thread truncated=True need_open_link=True %}
97 {% if not thread.archived %}
97 {% if not thread.archived %}
98 {% with last_replies=thread.get_last_replies %}
98 {% with last_replies=thread.get_last_replies %}
99 {% if last_replies %}
99 {% if last_replies %}
100 {% with skipped_replies_count=thread.get_skipped_replies_count %}
100 {% with skipped_replies_count=thread.get_skipped_replies_count %}
101 {% if skipped_replies_count %}
101 {% if skipped_replies_count %}
102 <div class="skipped_replies">
102 <div class="skipped_replies">
103 <a href="{% url 'thread' thread.get_opening_post_id %}">
103 <a href="{% url 'thread' thread.get_opening_post_id %}">
104 {% blocktrans with count=skipped_replies_count %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
104 {% blocktrans with count=skipped_replies_count %}Skipped {{ count }} replies. Open thread to see all replies.{% endblocktrans %}
105 </a>
105 </a>
106 </div>
106 </div>
107 {% endif %}
107 {% endif %}
108 {% endwith %}
108 {% endwith %}
109 <div class="last-replies">
109 <div class="last-replies">
110 {% for post in last_replies %}
110 {% for post in last_replies %}
111 {% post_view post is_opening=False moderator=moderator truncated=True %}
111 {% post_view post is_opening=False moderator=moderator truncated=True %}
112 {% endfor %}
112 {% endfor %}
113 </div>
113 </div>
114 {% endif %}
114 {% endif %}
115 {% endwith %}
115 {% endwith %}
116 {% endif %}
116 {% endif %}
117 </div>
117 </div>
118 {% endfor %}
118 {% endfor %}
119
119
120 {% if next_page_link %}
120 {% if next_page_link %}
121 <div class="page_link">
121 <div class="page_link">
122 <a href="{{ next_page_link }}">{% trans "Next page" %}</a>
122 <a href="{{ next_page_link }}">{% trans "Next page" %}</a>
123 </div>
123 </div>
124 {% endif %}
124 {% endif %}
125 {% else %}
125 {% else %}
126 <div class="post">
126 <div class="post">
127 {% trans 'No threads exist. Create the first one!' %}</div>
127 {% trans 'No threads exist. Create the first one!' %}</div>
128 {% endif %}
128 {% endif %}
129
129
130 <div class="post-form-w">
130 <div class="post-form-w">
131 <script src="{% static 'js/panel.js' %}"></script>
131 <script src="{% static 'js/panel.js' %}"></script>
132 <div class="post-form">
132 <div class="post-form">
133 <div class="form-title">{% trans "Create new thread" %}</div>
133 <div class="form-title">{% trans "Create new thread" %}</div>
134 <div class="swappable-form-full">
134 <div class="swappable-form-full">
135 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
135 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
136 {{ form.as_div }}
136 {{ form.as_div }}
137 <div class="form-submit">
137 <div class="form-submit">
138 <input type="submit" value="{% trans "Post" %}"/>
138 <input type="submit" value="{% trans "Post" %}"/>
139 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
139 </div>
140 </div>
140 </form>
141 </form>
141 </div>
142 </div>
142 <div>
143 <div>
143 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
144 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}
144 </div>
145 </div>
145 <div><button id="preview-button">{% trans 'Preview' %}</button></div>
146 <div id="preview-text"></div>
146 <div id="preview-text"></div>
147 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
147 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Text syntax' %}</a></div>
148 <div><a href="{% url "tags" "required" %}">{% trans 'Tags' %}</a></div>
148 <div><a href="{% url "tags" "required" %}">{% trans 'Tags' %}</a></div>
149 </div>
149 </div>
150 </div>
150 </div>
151
151
152 <script src="{% static 'js/form.js' %}"></script>
152 <script src="{% static 'js/form.js' %}"></script>
153 <script src="{% static 'js/thread_create.js' %}"></script>
153 <script src="{% static 'js/thread_create.js' %}"></script>
154
154
155 {% endblock %}
155 {% endblock %}
156
156
157 {% block metapanel %}
157 {% block metapanel %}
158
158
159 <span class="metapanel">
159 <span class="metapanel">
160 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
160 <b><a href="{% url "authors" %}">{{ site_name }}</a> {{ version }}</b>
161 {% trans "Pages:" %}
161 {% trans "Pages:" %}
162 [
162 [
163 {% with dividers=paginator.get_dividers %}
163 {% with dividers=paginator.get_dividers %}
164 {% for page in paginator.get_divided_range %}
164 {% for page in paginator.get_divided_range %}
165 {% if page in dividers %}
165 {% if page in dividers %}
166 …,
166 …,
167 {% endif %}
167 {% endif %}
168 <a
168 <a
169 {% ifequal page current_page.number %}
169 {% ifequal page current_page.number %}
170 class="current_page"
170 class="current_page"
171 {% endifequal %}
171 {% endifequal %}
172 href="
172 href="
173 {% if tag %}
173 {% if tag %}
174 {% url "tag" tag_name=tag.name %}?page={{ page }}
174 {% url "tag" tag_name=tag.name %}?page={{ page }}
175 {% else %}
175 {% else %}
176 {% url "index" %}?page={{ page }}
176 {% url "index" %}?page={{ page }}
177 {% endif %}
177 {% endif %}
178 ">{{ page }}</a>
178 ">{{ page }}</a>
179 {% if not forloop.last %},{% endif %}
179 {% if not forloop.last %},{% endif %}
180 {% endfor %}
180 {% endfor %}
181 {% endwith %}
181 {% endwith %}
182 ]
182 ]
183 [<a href="rss/">RSS</a>]
183 [<a href="rss/">RSS</a>]
184 </span>
184 </span>
185
185
186 {% endblock %}
186 {% endblock %}
@@ -1,57 +1,57 b''
1 {% extends "boards/thread.html" %}
1 {% extends "boards/thread.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5 {% load board %}
5 {% load board %}
6 {% load tz %}
6 {% load tz %}
7
7
8 {% block thread_content %}
8 {% block thread_content %}
9 {% get_current_language as LANGUAGE_CODE %}
9 {% get_current_language as LANGUAGE_CODE %}
10 {% get_current_timezone as TIME_ZONE %}
10 {% get_current_timezone as TIME_ZONE %}
11
11
12 {% if bumpable and thread.has_post_limit %}
12 {% if bumpable and thread.has_post_limit %}
13 <div class="bar-bg">
13 <div class="bar-bg">
14 <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress">
14 <div class="bar-value" style="width:{{ bumplimit_progress }}%" id="bumplimit_progress">
15 </div>
15 </div>
16 <div class="bar-text">
16 <div class="bar-text">
17 <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %}
17 <span id="left_to_limit">{{ posts_left }}</span> {% trans 'posts to bumplimit' %}
18 </div>
18 </div>
19 </div>
19 </div>
20 {% endif %}
20 {% endif %}
21
21
22 <div class="thread">
22 <div class="thread">
23 {% for post in thread.get_replies %}
23 {% for post in thread.get_replies %}
24 {% post_view post moderator=moderator reply_link=True %}
24 {% post_view post moderator=moderator reply_link=True %}
25 {% endfor %}
25 {% endfor %}
26 </div>
26 </div>
27
27
28 {% if not thread.archived %}
28 {% if not thread.archived %}
29 <div class="post-form-w">
29 <div class="post-form-w">
30 <script src="{% static 'js/panel.js' %}"></script>
30 <script src="{% static 'js/panel.js' %}"></script>
31 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}<span class="reply-to-message"> {% trans "to message " %} #<span id="reply-to-message-id"></span></span></div>
31 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post.id }}<span class="reply-to-message"> {% trans "to message " %} #<span id="reply-to-message-id"></span></span></div>
32 <div class="post-form" id="compact-form">
32 <div class="post-form" id="compact-form">
33 <div class="swappable-form-full">
33 <div class="swappable-form-full">
34 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
34 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
35 <div class="compact-form-text"></div>
35 <div class="compact-form-text"></div>
36 {{ form.as_div }}
36 {{ form.as_div }}
37 <div class="form-submit">
37 <div class="form-submit">
38 <input type="submit" value="{% trans "Post" %}"/>
38 <input type="submit" value="{% trans "Post" %}"/>
39 <button id="preview-button" onclick="return false;">{% trans 'Preview' %}</button>
39 </div>
40 </div>
40 </form>
41 </form>
41 </div>
42 </div>
42 <div><button id="preview-button">{% trans 'Preview' %}</button></div>
43 <div id="preview-text"></div>
43 <div id="preview-text"></div>
44 <div><a href="{% url "staticpage" name="help" %}">
44 <div><a href="{% url "staticpage" name="help" %}">
45 {% trans 'Text syntax' %}</a></div>
45 {% trans 'Text syntax' %}</a></div>
46 <div><a id="form-close-button" href="#" onClick="resetFormPosition(); return false;">{% trans 'Close form' %}</a></div>
46 <div><a id="form-close-button" href="#" onClick="resetFormPosition(); return false;">{% trans 'Close form' %}</a></div>
47 </div>
47 </div>
48 </div>
48 </div>
49
49
50 <script src="{% static 'js/jquery.form.min.js' %}"></script>
50 <script src="{% static 'js/jquery.form.min.js' %}"></script>
51 {% endif %}
51 {% endif %}
52
52
53 <script src="{% static 'js/form.js' %}"></script>
53 <script src="{% static 'js/form.js' %}"></script>
54 <script src="{% static 'js/thread.js' %}"></script>
54 <script src="{% static 'js/thread.js' %}"></script>
55 <script src="{% static 'js/thread_update.js' %}"></script>
55 <script src="{% static 'js/thread_update.js' %}"></script>
56 <script src="{% static 'js/3party/centrifuge.js' %}"></script>
56 <script src="{% static 'js/3party/centrifuge.js' %}"></script>
57 {% endblock %}
57 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now