· 6 years ago · Nov 24, 2019, 05:30 PM
1// ==UserScript==
2// @name JVChat Premium
3// @description Outil de discussion instantanée pour les forums de Jeuxvideo.com
4// @author Blaff
5// @namespace JVChatPremium
6// @version 0.1.52
7// @match http://*.jeuxvideo.com/forums/42-*
8// @match https://*.jeuxvideo.com/forums/42-*
9// @match http://*.jeuxvideo.com/forums/1-*
10// @match https://*.jeuxvideo.com/forums/1-*
11// @grant none
12// ==/UserScript==
13
14
15/*
16API : les développeurs peuvent créer des "plugins" pour JVChat à l'aide d'un système d'évènements.
17Cela permet par exemple à un deuxième userscript de modifier les messages au moment où ils sont
18ajoutés par JVChat, afin que chacun puisse personnaliser son affichage et ajouter de nouvelles
19fonctionnalités.
20
21Pour cela, il suffit d'écouter l'évènement "jvchat:newmessage". Celui-ci est émis chaque fois
22qu'un novueau message est ajouté, il contient l'identifiant dudit message à récupérer dans le DOM
23via le data-attribut "jvchat-id".
24
25Il existe aussi l'évènement "jvchat:activation" qui est émis une seule fois : à l'initialisation
26lorsque le topic pass en mode "JVChat" après appui sur le bouton.
27
28Exemple pour cacher les messages qui contiennent certains mot-clefs:
29
30 // my_plugin.user.js
31 let keywords = ["foobar", "barbaz"]
32
33 addEventListener("jvchat:newmessage", function(event) {
34 // L'id du message est stocké dans event.detail.id
35 let message = document.querySelector(`.jvchat-message[jvchat-id="${event.detail.id}"]`)
36 let text = message.querySelector(".txt-msg").textContent;
37 for (let keyword of keywords) {
38 if (text.includes(keyword)) {
39 message.style.display = "none";
40 return;
41 }
42 }
43 });
44
45*/
46
47
48/*
49TODO:
50- Smooth transition on append messages (slide-in plutôt que jump)
51- Détection captcha
52- Bouton actualiser les messages (+ afficher le delai courrant d'actualisation)
53- Notification avec @pseudo
54- Blacklist
55- Pouvoir voir les anciens messages
56- La leftbar ne se rétrécie pas si le titre du topic n'a pas d'espaces
57*/
58
59let CSS = `<style type="text/css" id="jvchat-css">
60#forum-right-col,
61#jv-footer,
62#middle,
63#zone-sponso,
64#header-top,
65#full-site,
66header.jv-header-menu,
67.titre-head-bloc,
68.bloc-pre-pagi-forum,
69.bloc-message-forum,
70.bloc-message-forum-anchor,
71.bloc-pagi-default,
72.bloc-outils-top,
73.bloc-outils-bottom,
74.option-previsu,
75.sondage-fofo,
76.nu-context-menu,
77.message-lock-topic,
78.form-post-message > .row > div:nth-child(2),
79.conteneur-messages-pagi > a:last-of-type,
80#bloc-meta-titre-jeu,
81#page-messages-forum > .container-content > .row:nth-child(1),
82.gameHeaderBanner,
83.gameHeaderSubNav,
84.bloc-sondage::before
85{
86 display: none!important;
87}
88
89html,
90body,
91#content,
92#content-context,
93#page-messages-forum,
94#page-messages-forum > .container-content,
95#jvchat-main,
96#content-forum,
97#forum-main-col,
98#forum-main-col > .conteneur-messages-pagi
99{
100 height: 100%;
101 width: 100%;
102}
103
104.jvchat-hide {
105 display: none!important;
106}
107
108.jvchat-hide-visibility {
109 visibility: hidden;
110}
111
112body {
113 overflow-y: unset;
114}
115
116.jvchat-disabled-form {
117 opacity: 0.5;
118 cursor: not-allowed;
119 pointer-events: none;
120}
121
122#bloc-formulaire-forum > .form-post-message > .row {
123 margin: 0;
124}
125
126.jv-editor > .conteneur-editor > .text-editor {
127 border: 0;
128 background: none;
129 display: flex!important;
130}
131
132#jvchat-alerts {
133 position: absolute;
134 z-index: 3;
135 right: 1rem;
136 left: 0;
137 overflow-y: hidden;
138}
139
140#jvchat-alerts .alert {
141 margin: 1rem 2rem;
142 border-radius: 0.5rem;
143}
144
145#content-context {
146 display: flex;
147}
148
149#jvchat-leftbar {
150 max-width: 15rem;
151 flex-grow: 100000;
152 flex-shrink: 100;
153 position: relative;
154}
155
156#jvchat-leftbar-button {
157 display: flex;
158 position: absolute;
159 right: 0;
160 top: 0;
161}
162
163#jvchat-leftbar-button span {
164 font-size: 1.2rem;
165 color: white;
166 padding: 0 1rem 0 0rem;
167 max-width: 100%;
168 cursor: pointer;
169 opacity: 0.3;
170}
171
172#jvchat-leftbar-button span:hover {
173 opacity: 1;
174}
175
176#page-messages-forum {
177 flex-basis: 35rem;
178 flex-grow: 100;
179 overflow-x: auto;
180 position: relative;
181 min-width: 13rem;
182}
183
184#jvchat-right-padding {
185 flex-shrink:1000;
186 flex-grow:0;
187}
188
189#forum-main-col > .conteneur-messages-pagi {
190 display: flex;
191 flex-direction: column;
192}
193
194#page-messages-forum > .container-content {
195 padding: 0;
196 max-width: unset;
197 min-width: unset;
198 min-height: unset;
199 max-height: unset;
200}
201
202.form-post-message {
203 margin: 0;
204}
205
206#message_topic {
207 resize: none;
208 min-width: unset;
209}
210
211.jvchat-edition-textarea {
212 resize: none;
213 width: 100%;
214 max-height: 6.5rem;
215 min-height: 3.5rem;
216}
217
218.jvchat-reduced #message_topic {
219 padding: 0.3rem;
220 height: 1.7rem;
221 max-height: 6.5rem;
222 overflow: auto;
223}
224
225.jvchat-reduced .jv-editor .conteneur-editor > * {
226 display: none;
227}
228
229#jvchat-buttons-main button {
230 padding: 0;
231 width: 2rem;
232}
233
234#jvchat-buttons-main button::before {
235 font-size: 1.4rem;
236}
237
238#jvchat-buttons-main button.icon-reply::before {
239 font-size: 1rem;
240}
241
242.jvchat-buttons {
243 display: flex;
244 flex-direction: column;
245}
246
247.jvchat-buttons button {
248 border: 0.0625rem solid #BEBECC;
249 border-left-width: 0;
250 height: 100%;
251 background: white;
252 color: gray;
253}
254
255.jvchat-buttons .jvchat-button-solo {
256 border-radius: 0 0.3rem 0.3rem 0;
257}
258
259.jvchat-buttons .jvchat-button-top {
260 border-radius: 0 0.3rem 0 0;
261}
262
263.jvchat-buttons .jvchat-button-bottom {
264 border-radius: 0 0 0.3rem 0;
265 border-top: 0!important;
266}
267
268.jvchat-textarea {
269 border-radius: 0.3rem 0 0 0.3rem!important;
270 border: 0.0625rem solid #BEBECC!important;
271 border-right-width: 0!important;
272}
273
274.jvchat-buttons button:hover {
275 background: lightgray;
276 color: black;
277}
278
279.jvchat-buttons button:focus {
280 border: dotted 1px!important;
281 color: black;
282 border: blue;
283}
284
285#content {
286 background-image: none;
287 margin-top: 0;
288}
289
290#content-forum {
291 margin: 0;
292}
293
294#forum-main-col {
295 display: block;
296 padding: 0;
297 max-width: unset;
298}
299
300#jvchat-leftbar > .panel {
301 margin: 0;
302 padding: 0 0.5rem;
303}
304
305#jvchat-leftbar #jvchat-profil .titre-info-fofo,
306#jvchat-leftbar #jvchat-configuration .titre-info-fofo {
307 margin-top: 0.5rem;
308}
309
310#jvchat-configuration-intro {
311 color: grey;
312 font-size: 0.84rem;
313}
314
315#jvchat-leftbar .titre-info-fofo {
316 margin-top: 1rem;
317}
318
319.jvchat-config-option {
320 margin-top: 2rem;
321}
322
323.jvchat-config-option p {
324 font-size:0.83rem;
325}
326
327.jvchat-config-option > label {
328 margin-bottom: 0.15rem;
329}
330
331.jvchat-range-option {
332 display: flex;
333
334}
335
336.jvchat-range-option > span {
337 white-space: nowrap;
338 margin: 0px 10px;
339}
340
341.jvchat-range-option > input {
342 width: 65%;
343}
344
345.jvchat-message {
346 display: flex;
347 margin-bottom: 0.35rem;
348}
349
350.jvchat-bloc-message {
351 animation-duration:0.5s;
352 animation-name: slidein;
353}
354
355@keyframes slidein {
356 from {
357 opacity: 0;
358 }
359
360 to {
361 opacity: 1;
362 }
363}
364
365.jvchat-toolbar {
366 margin: 0 0 .3rem 0;
367}
368
369.jvchat-author {
370 margin: 0;
371 display: inline-block;
372}
373
374.jvchat-tooltip {
375 display: flex;
376 float: right;
377 color: gray;
378}
379
380.jvchat-picto {
381 margin-right: 0.3rem;
382 visibility: hidden;
383}
384
385.jvchat-bloc-message:hover .jvchat-picto {
386 visibility: visible;
387 cursor: pointer;
388 opacity: 0.25;
389}
390
391.jvchat-picto:hover {
392 opacity: 1!important;
393}
394
395.jvchat-edition {
396 display: flex;
397}
398
399.jvchat-edition-check {
400 color: darkgreen!important;
401}
402
403.jvchat-edition-cancel {
404 color: darkred!important;
405}
406
407.jvchat-edition-textarea {
408 width: 100%;
409}
410
411hr.jvchat-ruler:first-of-type {
412 margin-top: auto;
413}
414
415.jvchat-ruler {
416 margin: 0rem 0rem .35rem 0rem;
417 border-style: solid;
418 border-width: 0.0625rem;
419 border-block-end-color: #ddd;
420}
421
422#jvchat-ruler-new {
423 border-bottom: 1px outset gray;
424}
425
426.jvchat-bloc-author-content {
427 overflow: hidden;
428 width: 100%;
429 margin-left: .875rem;
430}
431
432.jvchat-content > .txt-msg > p:last-of-type {
433 margin-bottom: 0;
434}
435
436.jvchat-content > .txt-msg p {
437 margin-bottom: 0.2rem;
438}
439
440.jvchat-content > .txt-msg .blockquote-jv {
441 margin: 0.2rem 0;
442 padding: 0rem 0.3rem 0 0.3rem;
443}
444
445.jvchat-content > .txt-msg > .blockquote-jv > .blockquote-jv:not([data-visible="1"]) {
446 padding: 0.7rem 0;
447}
448
449.jvchat-rounded {
450 overflow: hidden;
451 border-radius: 50%;
452 background-size: cover;
453 background-repeat: no-repeat;
454 background-position: center center;
455}
456
457.jvchat-bloc-avatar {
458 min-width: 40px;
459 min-height: 40px;
460 width: 40px;
461 height: 40px;
462 box-shadow: -3px 3px 7px grey;
463}
464
465#jvchat-user-avatar-link {
466 width: 60%;
467 min-width: 3rem;
468 min-height: 3rem;
469 margin: auto;
470}
471
472.jvchat-user-avatar {
473 width: 100%;
474 padding-top: 100%;
475}
476
477.jvchat-content .img-shack {
478 height: 39px;
479 width: 52px;
480 display: inline-block;
481 vertical-align: bottom;
482 margin-bottom:0.27rem;
483 overflow: hidden;
484}
485
486.jvchat-content .img-stickers {
487 max-height: 39px;
488 min-height: 39px;
489 width: auto;
490 display: inline-block;
491 vertical-align: bottom;
492 margin-bottom:0.1rem;
493}
494
495#jvchat-main .bloc-spoil-jv .open-spoil {
496 position: unset;
497 display: none;
498}
499
500.new-stickers {
501 background-color: unset;
502}
503
504#jvchat-user-mp {
505 font-size: 1.3rem;
506 margin: auto;
507}
508
509#jvchat-user-notif {
510 font-size: 1.7rem;
511 margin: auto;
512}
513
514#jvchat-user-pseudo {
515 margin: 0.5rem;
516 text-align: center;
517 /* overflow-x: hidden; */
518}
519
520#jvchat-user-info {
521 display: flex;
522}
523
524#jvchat-user-info .jv-header-menu {
525 position: unset;
526 display: flex;
527 justify-content: center;
528 flex-direction: column;
529 margin: auto;
530}
531
532#jvchat-topic-link {
533 color: white;
534}
535
536#jvchat-topic-info {
537 display: flex;
538 flex-direction: column;
539}
540
541#jvchat-topic-nb-connected {
542 color: lightgray;
543}
544
545#jvchat-topic-nb-messages {
546 color: lightgray;
547}
548
549#bloc-formulaire-forum .jv-editor > .conteneur-editor {
550 margin: 0;
551 border: 0;
552 padding: 0.5rem;
553 line-height: normal;
554}
555
556#jvchat-main {
557 overflow-y: auto;
558 padding: 0.35rem 0.875rem;
559 display: flex;
560 flex-direction: column;
561}
562
563#jvchat-leftbar > .panel-jv-forum {
564 height: 100%;
565 overflow-y: auto;
566}
567
568#jvchat-leftbar.jvchat-leftbar-reduced {
569 flex-grow: 0;
570}
571
572#jvchat-leftbar.jvchat-leftbar-reduced > .panel > .panel-body {
573 display: none;
574}
575
576#jvchat-leftbar.jvchat-leftbar-reduced #jvchat-leftbar-button {
577 position: relative;
578}
579
580#jvchat-leftbar.jvchat-leftbar-reduced span {
581 padding: 0;
582}
583
584#jvchat-leftbar > .panel {
585 position: relative;
586}
587
588.disabled-content {
589 opacity: 0.3;
590 cursor: not-allowed;
591 pointer-events: none;
592}
593
594#jvchat-sondage-bloc {
595 background: unset;
596 padding: 0;
597}
598
599#jvchat-sondage-bloc .pourcent {
600 background: unset;
601 width: 5rem;
602}
603
604#jvchat-sondage-bloc .back-barre {
605 width: 5rem;
606}
607
608#jvchat-sondage-bloc .tab-choix {
609 margin-bottom: 1rem;
610}
611
612#jvchat-sondage-choix.notanswered .result-pourcent {
613 display: none;
614}
615
616#jvchat-sondage-choix.notanswered .reponse {
617 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAA5SURBVAiZbY7BDQAgDAKPTqaTOxp+rDaNvAhcAvLAACyLo0jDlF9YiCxk+0N+FJ1iWbrr5UH0AGADblEVRpZSAyQAAAAASUVORK5CYII=') no-repeat left 0.35rem;
618 padding-left: 0.7rem;
619}
620
621#jvchat-sondage-choix.notanswered .reponse > div {
622 cursor: pointer;
623}
624
625#jvchat-turbo {
626 display: inline-block;
627 cursor: pointer;
628 margin-top: 0.3rem;
629 -webkit-tap-highlight-color: transparent;
630 position: relative;
631}
632
633#jvchat-turbo i {
634 position: relative;
635 display: inline-block;
636 margin-right: .5rem;
637 width: 46px;
638 height: 26px;
639 background-color: #e6e6e6;
640 border-radius: 23px;
641 vertical-align: text-bottom;
642 transition: all 0.3s linear;
643}
644
645#jvchat-turbo i::before {
646 content: "";
647 position: absolute;
648 left: 0;
649 width: 42px;
650 height: 22px;
651 background-color: #fff;
652 border-radius: 11px;
653 transform: translate3d(2px, 2px, 0) scale3d(1, 1, 1);
654 transition: all 0.25s linear;
655}
656
657#jvchat-turbo i::after {
658 content: "";
659 position: absolute;
660 left: 0;
661 width: 22px;
662 height: 22px;
663 background-color: #fff;
664 border-radius: 11px;
665 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.24);
666 transform: translate3d(2px, 2px, 0);
667 transition: all 0.2s ease-in-out;
668}
669
670#jvchat-turbo:active i::after {
671 width: 28px;
672 transform: translate3d(2px, 2px, 0);
673}
674
675#jvchat-turbo:active input:checked + i::after {
676 transform: translate3d(16px, 2px, 0);
677}
678
679#jvchat-turbo input {
680 display: none;
681}
682
683#jvchat-turbo input:checked + i {
684 background-color: #4BD763;
685}
686
687#jvchat-turbo input:checked + i::before {
688 transform: translate3d(18px, 2px, 0) scale3d(0, 0, 0);
689}
690
691#jvchat-turbo input:checked + i::after {
692 transform: translate3d(22px, 2px, 0);
693}
694
695#jvchat-turbo-span {
696 position: absolute;
697 margin-top: 4px;
698}
699
700#jvchat-main.jvchat-hide-mosaics .jvchat-mosaic-root::before {
701 content: "Mosaïque Cachée ¯\\\\_(ツ)_/¯";
702 color:black;
703 text-align:center;
704 font-size:10px;
705 display:block;
706 height:55px;
707 width:55px;
708 background: white;
709 border: solid #f00;
710}
711
712#jvchat-main.jvchat-hide-mosaics .jvchat-mosaic-root {
713 pointer-events: none;
714}
715
716
717#jvchat-main.jvchat-hide-mosaics .jvchat-mosaic {
718 display: none;
719}
720
721#jvchat-turbo-delay-range,
722#jvchat-max-width-range,
723#jvchat-hide-mosaic-checkbox,
724#jvchat-hide-mosaic-span,
725#jvchat-night-mode-checkbox,
726#jvchat-night-mode-span,
727#jvchat-load-images-checkbox,
728#jvchat-load-images-span,
729#jvchat-play-sound-checkbox,
730#jvchat-play-sound-span {
731 cursor: pointer;
732}
733
734#content.jvchat-night-mode #jvchat-leftbar > .panel {
735 background-color: #2F3136!important;
736}
737
738#content.jvchat-night-mode {
739 color: #dcddde!important;
740 scrollbar-color: #191A1C #2F3136!important;
741}
742
743#content.jvchat-night-mode .jvchat-ruler {
744 border-color: #2e3035!important;
745 border-top: 1px solid transparent !important;
746}
747
748#content.jvchat-night-mode .conteneur-editor,
749#content.jvchat-night-mode .bloc-editor-forum,
750#content.jvchat-night-mode .jvchat-bloc-message,
751#content.jvchat-night-mode .conteneur-messages-pagi {
752 background-color: #36393F!important;
753}
754
755#content.jvchat-night-mode #message_topic,
756#content.jvchat-night-mode .btn-group {
757 background: #484C52!important;
758}
759
760#content.jvchat-night-mode .jvchat-bloc-avatar {
761 box-shadow: -3px 3px 7px black!important;
762}
763
764#content.jvchat-night-mode #jvchat-leftbar > .panel {
765 background-color: #2F3136!important;
766}
767
768#content.jvchat-night-mode .jvchat-edition-textarea {
769 background-color: #2a2a2a!important;
770}
771
772#content.jvchat-night-mode .jvchat-buttons button {
773 background: #484c52!important;
774}
775
776#content.jvchat-night-mode .text-enrichi-forum blockquote.blockquote-jv {
777 border-left-color: #484C52!important;
778}
779
780#content.jvchat-night-mode .text-enrichi-forum > blockquote.blockquote-jv > blockquote:not([data-visible="1"])::after {
781 background-color: #484c52!important;
782 border-color: #737373!important;
783 color: #737373!important;
784}
785
786</style>`;
787
788let PANEL = `
789<div id='jvchat-leftbar'>
790 <div class='panel panel-jv-forum'>
791 <div id="jvchat-leftbar-button">
792 <div id="jvchat-leftbar-config">
793 <span id="jvchat-leftbar-config-open" class="nav-icon-config" title="Afficher les paramètres"></span>
794 <span id="jvchat-leftbar-config-close" class="nav-icon-close jvchat-hide" title="Fermer les paramètres"></span>
795 </div>
796 <div id="jvchar-leftbar-size">
797 <span id="jvchat-leftbar-reduce" class="icon-arrow-left" title="Masquer la sidebar"></span>
798 <span id="jvchat-leftbar-extend" class="icon-arrow-right jvchat-hide" title="Afficher la sidebar"></span>
799 </div>
800 </div>
801 <div class='panel-body'>
802 <div id='jvchat-info'>
803 <div id='jvchat-profil' class='jvchat-hide'>
804 <h4 class='titre-info-fofo'>Profil</h4>
805 <h4 id='jvchat-user-pseudo'></h4>
806 <div id='jvchat-user-info'>
807 <a title="Ouvrir le profil" id="jvchat-user-avatar-link" target="_blank"><div id='jvchat-user-avatar' class='jvchat-rounded jvchat-user-avatar'></div></a>
808 <div class='jv-header-menu'>
809 <a target="_blank" href="http://www.jeuxvideo.com/messages-prives/boite-reception.php" title="Ouvrir la boîte de réception" id="jvchat-user-mp-link"><span id="jvchat-user-mp" class="jv-account-number-mp" data-val="0"></span></a>
810 <a target="_blank" title="Ouvrir les notifications" href="http://www.jeuxvideo.com/messages-prives/boite-reception.php" id="jvchat-user-notif-link"><span id="jvchat-user-notif" class="jv-account-number-notif" data-val="0"></span></a>
811 </div>
812 </div>
813 </div>
814 <div id='jvchat-topic'>
815 <h4 class='titre-info-fofo'>Topic</h4>
816 <div id="jvchat-topic-info">
817 <div><strong><a title="Ouvrir le topic" id="jvchat-topic-title"></a></strong></div>
818 <span id="jvchat-topic-nb-connected"></span>
819 <span id="jvchat-topic-nb-messages"></span>
820 <label id="jvchat-turbo" title="Actualise la liste des messages plus rapidement">
821 <input id="jvchat-turbo-checkbox" type="checkbox">
822 <i></i>
823 <span id="jvchat-turbo-span">Mode Turbo</span>
824 </label>
825 </div>
826 </div>
827 <div id='jvchat-forum'>
828 <h4 class='titre-info-fofo'>Forum</h4>
829 <div id="jvchat-forum-info">
830 <div><strong><a title="Ouvrir le forum" id="jvchat-forum-title"></a></strong></div>
831 </div>
832 </div>
833 <div id='jvchat-sondage' class='jvchat-hide'>
834 <h4 class='titre-info-fofo'>Sondage</h4>
835 <div id="jvchat-sondage-bloc" class="bloc-sondage">
836 <label><span id="jvchat-sondage-intitule"></span></label>
837 <table class="tab-choix"><tbody id="jvchat-sondage-choix" class="notanswered"></tbody></table>
838 <span id="jvchat-sondage-votes"></span>
839 </div>
840 </div>
841 </div>
842 <div id='jvchat-config' class='jvchat-hide'>
843 <div id='jvchat-configuration'>
844 <h4 class='titre-info-fofo'>Configuration</h4>
845 <p id='jvchat-configuration-intro'><i>Les paramètres sont automatiquement sauvegardés et mis à jour lorsque vous les modifiez.</i></p>
846 <div class="jvchat-config-option" id="jvchat-play-sound">
847 <label>
848 <input id="jvchat-play-sound-checkbox" type="checkbox">
849 <span id="jvchat-play-sound-span">Alerte sonore</span>
850 </label>
851 <p>Joue un son de notification lorsqu'un nouveau message est posté et que vous êtes sur un onglet différent.</p>
852 </div>
853 <div class="jvchat-config-option" id="jvchat-night-mode">
854 <label>
855 <input id="jvchat-night-mode-checkbox" type="checkbox">
856 <span id="jvchat-night-mode-span">Thème sombre</span>
857 </label>
858 <p>Active un mode nuit pour protéger vos petits yeux fatigués le soir.</p>
859 </div>
860 <div class="jvchat-config-option" id="jvchat-load-imagesc">
861 <label>
862 <input id="jvchat-load-images-checkbox" type="checkbox">
863 <span id="jvchat-load-images-span">Charger les images</span>
864 </label>
865 <p>Remplace les miniatures NoelShack avec l'image source complète afin de laisser apparaître la transparence (cela sollicite davantage votre connexion Internet).</p>
866 </div>
867 <div class="jvchat-config-option" id="jvchat-hide-mosaic">
868 <label>
869 <input id="jvchat-hide-mosaic-checkbox" type="checkbox">
870 <span id="jvchat-hide-mosaic-span">Masquer les mosaïques</span>
871 </label>
872 <p>Cache automatiquement les mosaïques d'images NoelShack pour réduire le flooding.</p>
873 </div>
874 <div class="jvchat-config-option" id="jvchat-turbo-delay">
875 <label>
876 <span>Délai Turbo</span>
877 </label>
878 <div class='jvchat-range-option'>
879 <input id="jvchat-turbo-delay-range" type="range" min="0" max="1000" step="50">
880 <span id="jvchat-turbo-delay-span">? ms</span>
881 </div>
882 <p>Ajuste le délai d'actualisation des messages en mode turbo (celui-ci permet de mettre à jour les messages plus rapidement, mais est déconseillé si vous avez une connexion instable).</p>
883 </div>
884 <div class="jvchat-config-option" id="jvchat-max-width">
885 <label>
886 <span>Largeur des messages</span>
887 </label>
888 <div class='jvchat-range-option'>
889 <input id="jvchat-max-width-range" type="range" min="0" max="100" step="1">
890 <span id="jvchat-max-width-span">? %</span>
891 </div>
892 <p>Configure l'espace utilisé horizontalement par les messages (une valeur réduite facilite la lecture sur les écrans larges).</p>
893 </div>
894 </div>
895 </div>
896 </div>
897 </div>
898</div>
899`;
900
901 let deletionHash = document.getElementById("ajax_hash_moderation_forum").value
902
903function getForm(doc) {
904 return doc.getElementsByClassName('form-post-message')[0];
905}
906
907function getHash(doc) {
908 let hash = doc.querySelector("#ajax_hash_liste_messages")
909 if (!hash) {
910 return undefined;
911 }
912 return hash.getAttribute("value");
913}
914
915let freshHash = getHash(document);
916let freshForm = getForm(document);
917let firstMessageId = undefined;
918let firstMessageDate = undefined;
919let allMessagesId = {};
920let userConnected = undefined;
921let updateIntervals = [2, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 30, 30, 30, 30, 30, 30, 30, 30, 60];
922let transisitions = [0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 19, 19, 19, 19, 19, 19, 19, 19, 31];
923let updateIntervalIdx = 0;
924let updateIntervalMax = updateIntervals.length - 1;
925let isLocked = false;
926let isError = false;
927let isReduced = true;
928let nbNewMessage = 0;
929let favicon = makeFavicon();
930let currentUser = {notif: undefined, mp: undefined, author: undefined, avatar: undefined};
931let currentTopicTitle = undefined;
932let turboActivated = false;
933let sondageChoices = undefined;
934let urlToFetch = undefined;
935let urlToCheckEdit = undefined;
936let currentFetchedPage = 1;
937let currentTimeoutId = -1;
938let shouldCheckEdited = false;
939let checkEditInterval = 30000;
940let postingMessage = false;
941let fetchingMessages = false;
942let leavingTopic = false;
943let storageKey = "jvchat-premium-configuration";
944let ringBell = undefined;
945let configuration = {
946 default_reduced: false,
947 turbo_delay: 500,
948 max_width: 100,
949 play_sound: false,
950 night_mode: false,
951 load_images: false,
952 hide_mosaic: false,
953 sound: "data:audio/mp3;base64, SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjI3LjEwMgAAAAAAAAAAAAAA//uQwAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAVAAAj6gAXFxcXIiIiIiIuLi4uLjo6Ojo6RUVFRVFRUVFRXV1dXV1oaGhoaHR0dHR/f39/f4uLi4uLl5eXl5eioqKirq6urq66urq6usXFxcXF0dHR0d3d3d3d6Ojo6Oj09PT09P////8AAAAATGF2YzU4LjUxAAAAAAAAAAAAAAAAJAYeAAAAAAAAI+ptpORkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//uQxAADk4YMnkEhl4L4QRnAkKWBAABvophhAsi/Z+qFd2/d6uJ0lh9XV7KPPMdJgaUaIgujxzFGPE2ktRjxMTdXafzC28Vcbwo49HSYm3ib//mKurj+JgaIQcgyDMRDNi9L0vfOvRuBajLZ43Tc3OpfNxlcpVn6zZnYGX17G2cbSHJsbni9huBKuNCwvyZzbROL6bBCmMSiP5MXwbM1+PvnK2dVn6zf7crHG5/f1on7+GLo95cEwwKGORk76jMgZR0gwgc35/kBJJRgjfGcBGBAjaY/LgmbxIEFRWTz65JBdui5ORgmSZOc/7Xd7nyMVituHKOKAYd/NcnrKFBiewUYXUFBinxRqR3qMKMdQUMYvs6tHvTBM3BG3y4Az8GFwTJ+u3/hBFv/qEme5IECCBACCIxepOI24UoSRC4/CEFDorbpAFAQJDfRpMeF6RrMo9pAupKGT678mgVJ/ygADLcECbamKEkCMA4G266kS6ogAAE6IOYiTB3hct+2Zn5mf37DhZ3bfsbXvn9nPxhyEQwPiPGsPKHktr41h5CYLHeO//uSxBiAWpYI6qMlhgsfQJ8UkydJz/FiwzXksn2WZt2wbiOT473mjZm+2vP7TBGSCwzGsMDBYrOCZ2OQvzy9/jh1eJZmeUHAmRTRu86vudv9swiWfsQn/sLDNf7FV8evkgwq/Pbe7b8z18Xxr7HB4sWcwYCOT7wLGV71HxzBujMIjM/M3KUWLFhgYGC/5bfOBIMHCoYcsocRMUJBgTDBxYsu/NFk9RxxhfHczMxDEc/Xzx2JZ+Zv0IIIRREywsymjLMljdU/60XWzDLlSC14oaEi6FAycKiUdQhsTk4sJl5Km0TcSUPFjtQSreVAGPChZAFsiLMOhR8RaqPIqT6SJEKcWCxAXJ1hpM4QJKtJE54NLEQy2nWLIi9U2uUtm5Mi8ZyGzxAQDsT725QkyqhRsng0rNGJ9w0gc+goygow8MQNwgSzklPWsIzKZRlNCRLE4VdFnEotKEiq7i0idygay2ER4WJ3NFSIujLui6pu3G0fal9afC2ZoUUKjIWYLoRzdUAAAdtpSljUoFR5tpa6VJceiiaHDKyryQtY1RaBIqHKCP/7ksQQgdjCDPikmTNDCcEfFpKQAbMWTEgjwookDhlpkMDi0ThgQQoUYMvTxCPIpgE8QtE+iKLJFCaiS1VcPj7oIJ1mKzmPH00MlFEbM0bI7PKWKxNGYJ56kmuwC4mXmpBsPHBE/TZKZgoda0PsIiRuyBhhD0MN9lhsgGl+F5oGnFyLHqRdYhkJh0hm1iCrUgZu7XP1B9HTSYJ8wII2TmTBoiHjR5VyN57mBimSWQ8YQCp74PyStZBpfQiPUwwo6J29FKqU5tm51Ml50i0jbJAqtNDvaWenZaLiyjVFVm4ymRLzQxQYhqDaqMqsVbiojXw5QqNIrg0JaYabfFVZCUQKnzkqiTMMGS1uJywzXkqjbe2Xb7/JFjEpL8rJAmhXQoQsnBah1z8ONl7KYomR0StnWab0jE1XhhRG66EiDQems0rU+WQkicIzbs1AUmyClUCGCbRAcWGpIiQqwzofM0sTsnjaSMrFlzTK6jiOKzxWxcbRpa5glRW0Zqmi6gBBDBEACALWUugs4tZMZIP8t+jGcU5EGdz1uIbn9Zh2zVgWEYb/+5LEEoAZei0VGbqAAy4iZKs7oAD4BmU5AbSaCkossWMiAGpiYCivAOCqbppug0DDoJAABgGEgEOTfZrLWJiFgwt7Aw2DQsrqv03d1EmTAjgPUFOBtRva5vtgMAACQDI4kBcZEzjaVfX06eHphaOLGZl4nBH5sXNuvUqv1LescZFzcnDE3LiEc8n+y6PrQTqq7VLqTpIkXJ9Avl83PZgThomlapdr6ft/9f7+tW//5mm7JsgjNkC4X3ZMzAAAAWAbmrqUSQAAMVRlNvVeMfhNPPjuMQluMzHVNFVoNDkZMSTSMBQXLhiQNGGQ3mU4lGAA0g4XDAcDTI4TjiCTXC29d8FGlNhGQIQoEFv2p2kTIoLYcFnAcTdqXkJYrJ3Nr/GhVFgqsW+AqwFXnOtaVONCuUD+khdnV6hYi5CYQyJOABicvrN3VRIiud/LF9W9VzDL+vqyafdL+fu1nj//j/+QB0cJXvmcipYZeFqOHN83j9LAvP7r//8ccsq3fv1b/2fgHBqPb//7qgAAAJBWQAAAADDJAdOccBowvjtzJ2QSML4X//uSxA0AGHTtFzntAAL5J+S3O1AAI5dhYzFfBjMEoF8KgBg4MMw6AxDAyA/MJQFkyHgazC0D4MRAKswIBCgMHUBFYYFLyp4qxxsKjELWfjSBcjM2GS26FprSHdvAiaPSLkqCxUWyTn3sxEBodWeOHGMsuujCLFNlrKZiu9/rOi5lrW7Pf3h39d/+7//7++c/3s1jvWu9uS3veb/LdYk+01yt1xNZEA0srFD4o/RSMTqzqn/+Q+Gb5HmneeUe/OgAAACwRggShMAAAAEAGNrBG1LlmNJYn755GQCQnXzmGC4dCoEmOYSo4mCQkm7SmBUGh4swwAwcXRi0XZouO4GCAYF9wFgARgGlD0BkwBGw8GJgPBfAw2DwMsDYAYSByAgCbOGRhzrhjELogYHBYIgGi6CMrnSBHzQDC4PAwOAQ48dYYjXfZE0WmziDwbXEDiUBKYzfr/5XIAQRgbHCWTr//8nEEDAgBUEEC1///8uFw0J8vn2Jsrmjf6/3wQghAAc1zBymsrBAAhYOnDowmajnJNAJXOSyc+coDERfPcFAmEp6gP/7ksQSgBnxJTT5zQADCJ3iw7/QAGgYfG+lOYsQQjHpksZBwhMUCExpA8DM8lcBGT6xmdlY4CBVYX2aVD0ASOTs5ZaUDB61JngKhoeHRKYEZSVOeKjDDsjCGQMVdd/Y3PSmB5VJtygVCAaKCp0lsPBLSEU61/WebEmzb/Fc0rTRMcLNENSJV7zdZNqf3zPXHGfrf3a0Aw9IgYFDDqsLWcL/43VsOzy5///vV3/pqbeXZJALQJVXluPP/+/Z5/yRYKgFZgMQFSYIsESmF7D1ZhTYWGYuyxYmKBhV5giwHOYFkA/goA0MB4AnDAXQDswOkA0AgEQYACA+mAXARZgRQASYBUBlmSA5n0hzmQIlmGQKmMAGmDwMqNICwSAAsBCUiGzZUvVyxi3X1HYym8YHg0VjOYdAWmbAUxWlkuf7v1cpbRdyrVfkFSMpGmEwHl2W9lt7f2P1g6Xb//+OOqtncGpWu9R/yrzv7z5//////vXcMqa1YoyQO6V/IPT+/5yr/7dyAEOGQxkBUzVMo9K5gxZkF2NAyJAjMCwUIDByBvkYmMD/+5LEEAAWsLUULv+CQ3qq6XW8vj7iYmQRn4ogkiiMZGTxga1Ixm+VH4i+HBQ1C3DaqGMehIxyNQEuGHUbT6URgmpbp5mZLZVOSR9l9A4ogABg4EtdcGXQdW13vf1e5y/T361NK11w67T9drzmFTv3LPKnf5vP+ct3aXIJXstY1DoXYoeTLtY8Ecag+evA7depy32yo0NisJLa5gsRUasPb/Fxf0NdBMjFMVQAKQJkUksbEuXnBRCMEAIZbbAoMQFjwOW7BwcYkEEwCWzUnDEMNbU0gld8LjEHOm18oDBIZhkmiiZYJomlAYEARpL/pwQ3L4hRV7copIMXRLWttff+N28IbcuAgIYbkhxKJAln0+1b1dtwXQ0lMNsCDj+piO6oHAy5HkaW67gJrr4TAaKXfZ0YBxsPG4gLJo2KWN3YnIog5BBBD0cK4SxJmW3MinRh/mWuDIXZc1coGp0p3ZIAUgxEWZbah7coIqvneRMZv9X3im6f3+M3pKxwjkdF/IWq0+q4TJK/tErVADlC2K3ggCkwexEjEKCdMrlb0yJgXzBD//uSxAwDF4FDKE9p6UsXKWKF/lE6B5MQQpA0qBFDrVwswNikEhZjBosQNDAAfY0R43a4iLAQWY4WQiAgsBAJI7McCMSlMcwOOUDBEVGYhRcjHPt6ynFGguLc9o+3CteK1k4Tr8kABUaI+mlfNNTqlucpWWErqMV3un1s1bVbAVzedMQBSAQi7xF5mnexdQmFli4jZr7Y3WuN1i41i+oBfkKfS7vXVvWtf/////////atcQlc5A0XJLtAAwAXEQBYAQIUwRENfMJ2BvzMkCgMxi0HLMGGBFjCvxag1hQCfAaVMzlsxAOwUHioAzH4KEJHMIoczWPU1Ep1xighBwNlCE8wknT2o0Gi8jSyZ1Xmlr4s1IQs/7hLzVNL3yyyLpwyTWkdIYOeBiUgyhZKTmCB0gIeqGbZmRMi8ZEqSKkkltZF3VompFRaQYCNVot1IPrZFmWyK2oVEOWtFrKky+rWvS0k6lKrV6nWjUyaJ1AqgKOI34wQdW8lev0QH6PyXkUh4ABQAELABpgCICKYDQNTmAJBBhiRqWAYaSDuGBlANxhMY//7ksQRgxgJAxJP7mnC+h3iCf29KBya04E2mwHhMSkSg5QIBTKhIqD51jSf2PKDqdO2IhNWlgSK5jiMa1MGCAaIXKCZ00aBhAFvJDLAR4Flkt1pJu6zhDgQ3BQJWYgI7TqJTCBAZpFM0M2OIjOjEWaKRc+dMWMkmqL6Q+AspMFKWnZ93tdFVq2sss+tHKW+jSuFzF6V2EjsKExCpZMNxz5PuAiZDNNiEKihvEECT1upMDrEGEQAABiEAkAICuYLsHkmFfgdJjNIqaYwsBAmBMgahgkJoGaSkGimoqhpQQY6aGBBIXFDDC8RDBFIGtmBMBPNExgNVIydIwxkAOcf0BjFndzSxG1CAfNLtuFpXSah9vzjeYdIb0BtR9JnzBrNwUUebNvrOF/Wc5zTyvYu3mswawCiFHuW+4WL/FPjecf0z//8YgDk0BxYFAY0VLLNNK0ix41GBUUSdm1A6sI3gUNJoSDw4a0JzrvvfY+/edrvtQQ5C237UsAQFxhfD8GOGFaYwjkZh8humBoDAYBThJpjDAntjAAeClRfFPomLIhGnAD/+5LEGIIR5V8ab2lJQimXI2ntrSjzimptsZ1R1UEIRuaFYnjUiQ4LJZCghwvyzt98qCIKZCIkG5A5MC8DSXLIrKYQliQs73NbPqTMa4F2Xtdb0/t9dD/kPXyb5h81qLRTmZbTX3c9G2yYbRSsXYGbCdCWgQDJEkUXeAABIBA8Kpahg7hLGWkWQZZIIBglAAGDAtSYD4b5wKMZMeo1IowMLECh4GKhINq2Lo6Ax5+JMvADAkp5dvkrx3XMiCWP9JrTMrQ4nANCAs4TiHmHDyCK0t22xjT/VXrz8VN/EnDOupZ7RMOkaFw4HNlRAbL2xrh31zqGXl8qV3i7f//+xREAIYC4FpgnA+GPicAZ2BExn/96GUkPwYXoU5jiTLm2KEeYh4FA8GgADAIAgEAMLTAHSdiNLkUljPSQBY1VfhX5kj+D0u9jZ26E0/u6OIuRBU9nxGbjqNIH1mOk3pyofR5LpZEXy3qInnZbt9KVJC1VV8dW6tSK/lKf6OWaktS9un1Omej9Mmn5eg7NzmIbnzXxyn5X9/b1qB8fFzokA1E/8j80//uSxFIDVSzjDA9pa4qhFqHN7bEpNu3lv/0gQgwDgDzApAaMFQGExczSTM8ENNT9lk1RAezDpAJMVBDk3OwBQ82MiFjJRYLAa7zOQAvMaABhBdDb0Q4hxkdmXtZBQtKpmN682IenWxUDayn8HdU4/PoozEkK5sxBbqnZ27tsn/3MvXstud2Ts8vhEc8JbZLEEO9Vfdb3hOted5oZ0Yv9H9dx398lx3b+bz4b+r6xIVKArPymZ/3J0v6Pd8I5/wN6tqfagAEAEjAFRgAhFmDYl6YIo1ZmSVYmQ6KuYFACRhiBdG3yEccYQSGGNKwq3hNBCsPpl4JqngksBtOp41KhZx2McK2HWcVodMxIeJhySqS8T0MA6xyDFHzIsLo0739X0MH3dVP8p2P5yGPtELNuz9ixz8V592fnk9scnZa+ti+rbezfkEce0380P8J/Wl+nAh/eL3Om8yJJf/96DfY1/ntiYCYAAOBBBQS5jEFnmYOFQaYzgBpmhgGEAD+YPiLRo9jGBZcyPTePRmIQDTVGQz1OKLVa2LuqgRe+28jSzBFmq//7ksRvg1Pcuw4vZQmKdxChgeyZOUvpr3H/sRr+9avTcxw/z/G7BaN4gcljCFoqjbj/WmNoFndqEZ1eUwfb/VPpO9kThpyDLLBUUd1yiRb1NwL7LUurG6E/7vanMq2lNjcfp+UIUZJ9r/+39Mf73fKITr1AAaAQYAAD5gHgxGHgWQZH4uRmezjGTYKQYNoPZgQKHGVsLcc6OYWAAAY0OVXNOaVvBUgvmEBX8oVFWd1Lr6GBBYZS6VwCWEJ4oE54eidU+raI7A16k5FhgkIX6kmOKv9Jf+2hbkdCXW8zxNLET8VdfNQtP3w3K2vHUT3w336cfqn19RtHMRU8Xr93z9rHxSU9tzP/U/0lfX58tXU1FM0X+/flWWaYPQMMoAwBQkAFUqG5gDAWGCea4YLgG5lmpumYMD2YJYDhgvlUGjwDIdpGYs1AbWmskTFEwFLRoEuKexJRKhUANcnhYjIIjYW0C5YjRMhCQVHVnNC0NHBADcwOQWiIMMciQa0r0nUbPcd60tUj1r8RF7f6d10+9fDfxrt2/UVzccV///9y8+3V/zf/+5LEl4IVOeUML2kJQpWs4intISiz8/TrWQPF0sINKowOZDRZ9KxaLudffCsg9ZacCbg2pipKlH4aAQMR8qAyHA7TMqkxMocTEwhggDD7ACNsAIswYgAAUDWkuW9SqBQEYKACGgVmSl+oFdtJVj0O5PSBgI2vQRLqVwYU04RhYPbMeIh4Sa5DCsYSS1ULjrt4dYrMdeGLeZlBftSL8qQM18g35z87f/IyQ9i8jOPefD4a8Y6+WUyMtpy825eJmr5QukXGqK0P3WUpFhFxk45l3oyYic9cfyztw0q2IqS+gpPtwEACJhMkHmLgDYZUSjxljg4GDMAoYQpN5m1BxkLhoYrfUCeNMpRU3wA4FQi9aYS40MXnQSmhuNV00ODy1dhYfBdnXwa17cGoNCMlb4pJkRG2G0NXc8Tz7/fVAspL6IjfehUzff3sNJemy/3Td/0p8NR4UuBz3UGjzXLa/Cel+k9FprVpavspVQvrB7FF+7/Xru0/zbc/iL9qVRAaCnMAANTAEQDMF4HozHXZjJQDSCApzACPxMC0QU/XDWKECy+Y//uSxLYCFOnNCg8gdMp3k+HZ7KUpbDMSwOHeNfQdYO0xu7Q568+YGNgl0XzmlCEcKzY0TjBxC00OsjMcSOtAnFjyWFSKfWLaFuadot6iZSMla/l6V4Sa+nv4pKr4xnm3afMNNxOu68dykmc/zdRVw7/dXW22lQkDNrh5+butfmEj9qqa+mpYT3rjn/T16W+u+L2h5y2EWZwQ2Bt/KszlJwGgOmFMK+YnYUpj0pPmRcD6GBJGCIUeZb4NYCBOSYLbQSp0WzeIiA5TWGgCIhLHhRLh9/nhEgCoenc0E0gNNt20hBkQl6LE6LzQqUSWHnqCkiVgigOtFi1gcjCyAmd672PWTSDXjSwjzs+sZmZB/yC+jZLCp6SEkSQkOczJORT+wvH/dlNYq6s5shYlAzkGNTyUREJaKUBGAox960rVLow2pVrQVetAulVwCYAIIARMEcDIxfD2jM/DVNKiU0zgRBwMGIYcBT5vTgVGCeBEYCYDJgIgLkwCJMBEBhhAkc5ZnGAJt23TZClnLIw7gCQzkT9UchtNd7Kam5hnLcpyOauYUf/7ksTZghVV9QovZQlKurMh5eSOmNHlW1c9+rFLS0TU+ZT9avfsSRNlG3xJVuop3dtdlske9SyUy9z3JGWci9THPKSkpVKaXrfTbzjNLdMqdQ1INDfDUGxuX2jla5T59nzZJmdmYoxBsJOPvFV4vWY6CkNZ4deRBymeS9VEKJMrJPfPsGsq8S1E1HP3zvOt/rtaTJgBgGGAABWCQgDA5SIMD8VIywnbjMzDwMDgHMwmh5jTxDyKGZqH4QBus4IpD1HJAByEaBMreJ20a7DssjLAGJv1S4T3u9hD2VeORON41cd6XusEwbmwmS1KQaVB/00sVdpl96Z0k57Vcu2EDkbbSOQad6eptBOIIeWzbKCb3O0/Kt4w1v2t8N/p0WdLIxWs31O8jMzX1o/JJGdeTvf60s265THrkpFpPRw/5M7kbpVmthF32oxqu2/qyryZQl/TvHVzzSLgG8AQB5gcAVGKiOgZOgchmctXGXUG4YN4M5hKGsGLqIwZxiYOAPOXnSlGhY4PLgOWwhtZQztQqpIswMWtvBu5rbJZVKBOouC4CyD/+5LE8wNa5gcCL2TNyw8/oIHtGTlDLoOzxrPZxATjDTBDGmj0GCIELDmMtnskY+9Yqi6kKp58W41Zva0lxl2YNiyaUmRxkshX4+8fB9XlwiajbeTZWtftGrNySddWiESR7rnQplcwNtc6HsfwmZUz2nM6jsQWlGFrjI7WKaDB5GKI9PfD+PGZy1cRJKsPlrRgBADmAaAsYEQKJhqlNmQUIGZUbTZljBtmBmAwYHpaBlcBbHUWmfOAoE1pDmSCkZQ7Sn29ctjzXEY5G72Y0RkmLblAmA0pzpZAEOfEHjY+nWdtagkujPqXulpt6am3ZPnaY2/cIopyS/xFCq6m8y2wuG6zLh6Pt5zkojEGJtF5NuWon9Kzx7EdFzDkDUTJqu6lwtuoupnq/PfIq3jHTf7m/vG6i/bHhr3Ma5d3q6b67lPzpD5JxScGut9iILwco0lqGEAGMgwBQwCQUzCIMzMJUPMzClfzKHC3MGwGAwdxBDOgAfOUIBytaKm0RBxURCEd4TF4XLIix5r9tu6AfOpC/osYBzs1ZPSQiHeyefEAJxKB//uSxOwDWL4DBC9pCYsBvyCB7RkpNjgWIhjiXPKNxE0FoMFggb7RQSfRIRwRPY95ma73bLaHkykULSov9FrxM9BOolmtpa0ln3klQ5tzCWRTordrjTms3mM6opJjJjbLdSDGfwfb/Hy3K3C/UQe7FalDTldCJzNef6lpbPtQ8zrP3bctnc0DqMZkzFUxwAgACQBoQB8YcAlZjhhNGPwxUZI4TBgsAEGEOLSZdQR5kIdPiXV2teFrszG5MERpmYVC3O07LoKJV37v34zK2tcub3EI3HLGGPJA1mOtfE3aHEV5A8XR1FpPNw7wje9924svlrhH5W53NTtb403b5JHcNK2X8NB27EFpXjZzD67xq3P3d3XeS0osxHJfRLsXZSBrlTuX/b5tDmxnrdQMcvdVuyWjkTnWvXKNaUX0Xlod0mu9jcyX9LgzO2PByKFJVQJACzwgANGQNjB4IwMT0LQy400jKACWME8AsRFdmD4HCJlGMomoEEP2gkGSVSMqa80pvnKS6vRdnQcbZdCHqahrP7Nbq1s5HNTurYY/wS6J6iIurP/7ksTvA1keBQRPaMnLB8AghewZOTHvZpaTHuiTP+mnmsROK2To2qrdLjWhrX5RvG009VWZBbdGV2VLY/a0ZNwpe6iPUhRrgZqR/swg1kKiHJS6NF5Ocy2aCxefCtnJZmaWOQsCbavJw5EK7F7SEl6UtD09D0FySMlSr8a0uUU5/j5hsmputye9BkbN1tWC0hcQMAwxtYgw3J00F6MDcCYYh6YmvCbgjSYjginkJANDsMIGuyPASKUXNRuKwdTHO2le3x7Q4tG6jNJBa9HbBhzz6vqlr0s2TxW+7xjdO4UumTNtQPTP9f7Rtf/Wc0zq18596/OfD1n5pjf+NRc4zjFcbiZ1m2Mw9TZxiF6XxL8XtvN4Ftazm9vf/frS1sUrjWK0+bY3Xfvv2xHpj7197zS2sbpee/1qNq2bZzjOa5z81zNuX2vquMfesbpe/trGqZpjH3uWAAQAUJMQAMBsWgwFqMzB9CpM4dgcwGhbTNCBgM7dY8z0QNTZHT7BUixtgoCmouAUYFAKRgFgkgAAAwDgEUwzANAcO7iEwCq2xRphqHb/+5LE8ANZagcCL2TJyx5A4Qq68AAeWrgECDBsRQRFlWmMhqPipymMrcKySaexxFHmJy6WQVYfh3HKj8Ds6dVgTNHXdeIySliMCNe+blbXqd/KVw3mi8y+dR96ZqUCzETltPekMMPC0WF00m5G8qsjp5dIKZ+4/J4hhPMbxk9uZlkvh6/jLtS6T9noZlleNzM1apGt+7CwkdfONPpLpNT0rivtF6d5JRejlihnmuTMIf3OWsl7KKKapZHQ3IBmnFlUchyHaOIzN+Syuo2SUVYPlNqCn+n4xG78SrR1lD/QTSyWlcKHJychjdSVSWMwDAM3EY7Rf/////4vzXlEEQJGHKsO7LsZ6U2J2PwPQf/////wNDUARKBH5g6tXeyKSKCcnRpY3DcYAAEAAAMEoLwyQhqjAOAaMLkNqt00SR7TGnEwMCcLkwGAN/0YLQF4kEeYBQBxgMgDf5zDxADC4wy5TXmbBm6JJimNECMEY0V/+ZUKbI8RFS75hwiwRgQhhQ3//mSGBgiSmIDAYQ8RaowYaYQy///4FAgIFCFcICDBAACE//uSxO0AK+Iu+xnsAAT7PuBXPaAAsrSBICGWxf///q8USLIIaMqLIIUF1n1hhHpwYQrd////69i6hehbyJiOCcatiVjSXVaU3Fpsebiy2x/////+jW3RSxAe2JliKcPPIim67osRh10V2u7ALDWcx1hv///////DiG7T48oOzeXsjTHhtmap3fdFMdYWZaysLddlhtaIrlpqFlMSp//////////3Hh1Qdf8HMPUvasytPttG5svXpBLO1LJlr//////7WYlRuzEotEYCfqZiTvX4k5UPRJynekxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7ksQ5A8AAAaQcAAAgAAA0gAAABKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="
954};
955
956function saveConfig() {
957 let config = JSON.stringify(configuration);
958 localStorage.setItem(storageKey, config);
959}
960
961function loadConfig() {
962 let config = JSON.parse(localStorage.getItem(storageKey) || "{}");
963 for (let key in config) {
964 if (config.hasOwnProperty(key) && configuration.hasOwnProperty(key)) {
965 configuration[key] = config[key];
966 }
967 }
968}
969
970function getTopicLocked(elem) {
971 let lock = elem.getElementsByClassName("message-lock-topic")[0];
972 if (lock === undefined) {
973 return lock;
974 }
975 let reason = lock.getElementsByTagName("span")[0].textContent.trim();
976 return `Le topic a été vérouillé pour la raison suivante : "${reason}"`;
977}
978
979function getTopicError(elem) {
980 let error = elem.getElementsByClassName("img-erreur")[0];
981 if (error === undefined) {
982 return error;
983 }
984 return `Le topic présente une erreur: ${error.getAttribute("alt")}`;
985}
986
987function parseSondage(elem) {
988 let blocSondage = elem.getElementsByClassName("bloc-sondage")[0];
989 if (!blocSondage) {
990 return null;
991 }
992 let intitule = blocSondage.getElementsByClassName("intitule-sondage")[0].innerHTML;
993 let answered = !!(blocSondage.getElementsByClassName("result-pourcent")[0]);
994
995 let choix = blocSondage.getElementsByClassName("tab-choix")[0].getElementsByTagName("tr");
996 let results = [];
997
998 if (answered) {
999 for (let ch of choix) {
1000 let pourcent = parseInt(ch.getElementsByClassName("pourcent")[0].innerHTML.trim().split(" ")[0]);
1001 let response = ch.getElementsByClassName("reponse")[0].innerHTML.trim();
1002 results.push({response: response, pourcent: pourcent});
1003 }
1004 } else {
1005 for (let ch of choix) {
1006 let btnResponse = ch.getElementsByClassName("btn-sondage-reponse")[0];
1007 let response = btnResponse.innerHTML.trim();
1008 let sondageId = btnResponse.getAttribute("data-id-sondage");
1009 let responseId = btnResponse.getAttribute("data-id-reponse");
1010 results.push({response: response, sondageId: sondageId, responseId:responseId});
1011 }
1012 }
1013
1014 let votes = parseInt(blocSondage.getElementsByClassName("pied-result")[0].innerHTML.trim().split(" ")[0]);
1015 return {answered:answered, intitule: intitule, results:results, votes:votes};
1016}
1017
1018function tryCatch(func) {
1019 function wrapped(optArg) {
1020 try {
1021 func(optArg);
1022 } catch(err) {
1023 let message = `Une erreur est survenue dans JVChat Premium: '${err.message}' (line ${err.lineNumber})`;
1024 console.error(message);
1025 try {
1026 addAlertbox("danger", message);
1027 } catch(e) {
1028 alert(message);
1029 }
1030 }
1031 }
1032 return wrapped;
1033}
1034
1035function toggleTextarea() {
1036 isReduced = !isReduced;
1037 configuration["default_reduced"] = isReduced;
1038 saveConfig();
1039
1040 let isDown = isScrollDown();
1041 document.getElementById("bloc-formulaire-forum").getElementsByClassName("jv-editor-toolbar")[0].classList.toggle("jvchat-hide");
1042 document.getElementById("jvchat-enlarge").classList.toggle("jvchat-hide");
1043 document.getElementById("jvchat-reduce").classList.toggle("jvchat-hide");
1044 document.getElementById("jvchat-post").classList.toggle("jvchat-hide");
1045 document.getElementById("bloc-formulaire-forum").classList.toggle("jvchat-reduced");
1046
1047 setTextareaHeight();
1048
1049 if (isDown) {
1050 setScrollDown();
1051 }
1052}
1053
1054function parseURL(url) {
1055 let regex = /^(.*?)(\/\d+-\d+-\d+-)(\d+)(-\d+-\d+-\d+-)(.*?)(\.htm)(.*)$/i;
1056 let [_, domain, ids, page, nums, title, htm, anchor] = url.match(regex);
1057 return {domain: domain, ids: ids, page: page, nums: nums, title: title, htm: htm, anchor: anchor};
1058}
1059
1060function buildURL(dict) {
1061 return `${dict.domain}${dict.ids}${dict.page}${dict.nums}${dict.title}${dict.htm}${dict.anchor}`;
1062}
1063
1064function getForum(document) {
1065 let ariane = document.getElementsByClassName("bloc-fil-ariane-crumb-forum")[0];
1066 let links = ariane.getElementsByTagName("a");
1067 let title = "";
1068 let forumLink = "";
1069
1070 for (let i = links.length - 1; i >= 0; i--) {
1071 forumLink = links[i];
1072 title = forumLink.innerHTML.trim();
1073 if (title.startsWith("Forum ")) {
1074 break;
1075 }
1076 }
1077
1078 return {href: forumLink.getAttribute("href"), title: title.replace("Forum ", "")};
1079}
1080
1081function getLastPage(document) {
1082 let blocPages = document.getElementsByClassName("bloc-liste-num-page")[0];
1083 let spans = blocPages.getElementsByTagName("span");
1084 let lastPage = 1;
1085 for (let span of spans) {
1086 let page = parseInt(span.textContent.trim());
1087 if (!isNaN(page) && page > lastPage) {
1088 lastPage = page;
1089 }
1090 }
1091 return lastPage;
1092}
1093
1094function parseMessage(elem) {
1095 let conteneurs = elem.getElementsByClassName("conteneur-message");
1096 let conteneur = conteneurs[conteneurs.length - 1];
1097 let blacklisted = conteneurs[0].classList.contains("conteneur-message-blacklist");
1098 let author = conteneur.getElementsByClassName("bloc-pseudo-msg")[0].textContent.trim();
1099 let avatar = conteneur.getElementsByClassName("user-avatar-msg")[0];
1100 if (avatar !== undefined) {
1101 avatar = avatar.getAttribute("data-srcset");
1102 }
1103 let date = conteneur.getElementsByClassName("bloc-date-msg")[0].textContent.trim();
1104 let content = conteneur.getElementsByClassName("text-enrichi-forum")[0];
1105 let id = parseInt(elem.getAttribute("data-id"));
1106 let edited = elem.getElementsByClassName("info-edition-msg")[0];
1107 if (edited !== undefined) {
1108 let msgEdited = edited.textContent.trim();
1109 edited = msgEdited.match(/Message édité le .*? à (.*?) par/i)[1];
1110 }
1111 return {author: author, dateString: date, date: parseDate(date), avatar: avatar, edited: edited,
1112 id: id, content: content, blacklisted: blacklisted};
1113}
1114
1115function parseUserInfo(elem) {
1116 let accountMp = elem.getElementsByClassName("jv-nav-account-mp")[0];
1117 if (accountMp === undefined) {
1118 return {author: undefined, avatar: undefined, mp: undefined, notif: undefined};
1119 }
1120 let numberMp = accountMp.getElementsByClassName("jv-account-number-mp")[0];
1121 let accountNotif = elem.getElementsByClassName("jv-nav-account-notif")[0];
1122 let numberNotif = accountNotif.getElementsByClassName("jv-account-number-notif")[0];
1123 let accountUser = elem.getElementsByClassName("jv-nav-account-user")[0];
1124 let avatarBox = accountUser.getElementsByClassName("account-avatar-box")[0];
1125 let authorBox = accountUser.getElementsByClassName("account-pseudo")[0];
1126 let mp = parseInt(numberMp.getAttribute("data-val"));
1127 let notif = parseInt(numberNotif.getAttribute("data-val"));
1128 let avatar = avatarBox.style["background-image"].slice(5, -2).replace("/avatar-md/", "/avatar/");
1129 let author = authorBox.textContent.trim();
1130 return {author: author, avatar: avatar, mp: mp, notif: notif};
1131}
1132
1133function parseTopicInfo(elem) {
1134 let title = elem.querySelector("#bloc-title-forum").textContent.trim();
1135 let connected = parseInt(elem.getElementsByClassName("nb-connect-fofo")[0].textContent.trim());
1136 let lastPage = getLastPage(elem);
1137 let pageActive = elem.getElementsByClassName("page-active")[0];
1138 let page = 1;
1139 if (pageActive !== undefined) {
1140 page = parseInt(pageActive.textContent.trim());
1141 }
1142 return {title: title, connected: connected, lastPage: lastPage, page: page};
1143}
1144
1145function fixMessage(elem) {
1146 let jvcares = Array.from(elem.getElementsByClassName("JvCare"));
1147 for (let jvcare of jvcares) {
1148 let a = document.createElement("a");
1149 a.setAttribute("target", "_blank");
1150 a.setAttribute("href", jvCake(jvcare.getAttribute("class")));
1151 a.innerHTML = jvcare.innerHTML;
1152 jvcare.outerHTML = a.outerHTML;
1153 }
1154}
1155
1156function jvCake(cls) {
1157 let base16 = '0A12B34C56D78E9F', lien = '', s = cls.split(' ')[1];
1158 for (let i = 0; i < s.length; i += 2) {
1159 lien += String.fromCharCode(base16.indexOf(s.charAt(i)) * 16 + base16.indexOf(s.charAt(i + 1)));
1160 }
1161 return lien;
1162}
1163
1164function detectMosaic(elem) {
1165 let imagesShack = elem.getElementsByClassName("img-shack");
1166 if (imagesShack.length < 4) {
1167 return;
1168 }
1169 let mosaics = {};
1170 let regex = /^.+\/[0-9]+-[0-9]{1,2}-([a-z0-9]+)\.\w+$/i;
1171 for (let image of imagesShack) {
1172 let match = image.src.match(regex);
1173 if (!match) {
1174 continue;
1175 }
1176 [_, identifier] = match;
1177 if (mosaics.hasOwnProperty(identifier)) {
1178 mosaics[identifier].push(image);
1179 } else {
1180 mosaics[identifier] = [image]
1181 }
1182 }
1183 for (let identifier in mosaics) {
1184 let images = mosaics[identifier];
1185 if (images.length < 4) {
1186 continue;
1187 }
1188 images[0].parentNode.classList.add("jvchat-mosaic-root");
1189 images[0].classList.add("jvchat-mosaic");
1190 for (let image of images.slice(1)) {
1191 image.parentNode.classList.add("jvchat-mosaic");
1192 }
1193 }
1194}
1195
1196function improveImages(elem) {
1197 let imagesShack = elem.getElementsByClassName("img-shack");
1198 for (let image of imagesShack) {
1199 let src = image.src;
1200 let parent = image.parentNode;
1201 let extension = parent.href.split(".").pop();
1202 let direct = src.replace(/(.*?)\/minis\/(.*)\.\w+/i, "$1/fichiers/$2." + extension);
1203 image.setAttribute("data-src-mini", src);
1204 image.setAttribute("data-src-direct", direct);
1205 image.classList.add("jvchat-loadable-image");
1206 parent.href = direct;
1207 if (extension.toUpperCase() === "GIF") {
1208 image.src = direct;
1209 image.classList.remove("jvchat-loadable-image");
1210 } else if (configuration["load_images"]) {
1211 image.src = direct;
1212 }
1213 src = image.src;
1214 image.setAttribute("onerror", `this.onerror=null;this.src=this.getAttribute("data-src-direct");this.classList.remove("jvchat-loadable-image");`);
1215 }
1216}
1217
1218function clearPage(document) {
1219 let buttons = `
1220 <div id="jvchat-buttons-main" class='jvchat-buttons'>
1221 <button id='jvchat-post' tabindex="4" type="button" class='jvchat-hide jvchat-button-top icon-reply' title="Envoyer le message"></button>
1222 <button id='jvchat-reduce' tabindex="5" type="button" class='jvchat-hide jvchat-button-bottom icon-arrow-down-entypo' title="Réduire la zone de texte"></button>
1223 <button id='jvchat-enlarge' tabindex="4" type="button" class='jvchat-button-solo icon-arrow-up-entypo' title="Agrandir la zone de texte"></button>
1224 <div>`;
1225
1226 document.head.insertAdjacentHTML("beforeend", CSS);
1227
1228 let previsu = document.getElementById("bloc-formulaire-forum").getElementsByClassName("previsu-editor")[0];
1229 if (previsu) {
1230 previsu.parentElement.removeChild(previsu);
1231 }
1232
1233 let messageTopic = document.getElementById("message_topic");
1234 if (messageTopic) {
1235 messageTopic.classList.add("jvchat-textarea");
1236 messageTopic.setAttribute("placeholder", "Hop hop hop, le message ne va pas s'écrire tout seul !");
1237 messageTopic.insertAdjacentHTML("afterend", buttons);
1238 messageTopic.addEventListener("keydown", tryCatch(postMessageIfEnter));
1239 document.getElementById("jvchat-post").addEventListener("click", tryCatch(postMessage));
1240 document.getElementById("jvchat-enlarge").addEventListener("click", tryCatch(toggleTextarea));
1241 document.getElementById("jvchat-reduce").addEventListener("click", tryCatch(toggleTextarea));
1242 }
1243 document.getElementsByClassName("conteneur-messages-pagi")[0].insertAdjacentHTML("afterbegin", "<div id='jvchat-main'><hr class='jvchat-ruler'></div>");
1244 document.getElementById("page-messages-forum").insertAdjacentHTML("afterbegin", "<div id='jvchat-alerts'><div id='jvchat-fixed-alert' class='jvchat-hide'><div class='alert-row'></div></div></div>");
1245
1246 document.getElementById("content-context").insertAdjacentHTML("afterbegin", PANEL);
1247 document.getElementById("content-context").insertAdjacentHTML("beforeend", "<div id='jvchat-right-padding'></div>");
1248
1249 document.getElementById("content").classList.add("jvchat-root");
1250 document.getElementById("bloc-formulaire-forum").classList.add("jvchat-reduced");
1251 document.getElementById("bloc-formulaire-forum").classList.add("jvchat-hide");
1252
1253 let toolbar = document.getElementById("bloc-formulaire-forum").getElementsByClassName("jv-editor-toolbar")[0];
1254 if (toolbar) {
1255 toolbar.classList.add("jvchat-hide");
1256 }
1257
1258 document.getElementById("jvchat-main").addEventListener("click", tryCatch(dontScrollOnExpand));
1259
1260 document.getElementById("jvchat-alerts").addEventListener("click", tryCatch(closeAlert));
1261
1262 document.getElementById("jvchat-leftbar-reduce").addEventListener("click", tryCatch(toggleSidebar));
1263 document.getElementById("jvchat-leftbar-extend").addEventListener("click", tryCatch(toggleSidebar));
1264 document.getElementById("jvchat-leftbar-config-open").addEventListener("click", tryCatch(toggleConfig));
1265 document.getElementById("jvchat-leftbar-config-close").addEventListener("click", tryCatch(toggleConfig));
1266
1267 document.getElementById("jvchat-turbo-checkbox").addEventListener("change", tryCatch(toggleTurbo));
1268
1269 document.getElementById("jvchat-play-sound-checkbox").checked = configuration["play_sound"];
1270 document.getElementById("jvchat-play-sound-checkbox").addEventListener("change", tryCatch(togglePlaySoundOption));
1271
1272 document.getElementById("jvchat-night-mode-checkbox").checked = configuration["night_mode"];
1273 document.getElementById("jvchat-night-mode-checkbox").addEventListener("change", tryCatch(toggleNightModeOption));
1274 if (configuration["night_mode"]) {
1275 document.getElementById("content").classList.add("jvchat-night-mode");
1276 }
1277
1278 document.getElementById("jvchat-hide-mosaic-checkbox").checked = configuration["hide_mosaic"];
1279 document.getElementById("jvchat-hide-mosaic-checkbox").addEventListener("change", tryCatch(toggleHideMosaicOption));
1280 if (configuration["hide_mosaic"]) {
1281 document.getElementById("jvchat-main").classList.add("jvchat-hide-mosaics");
1282 }
1283
1284 document.getElementById("jvchat-load-images-checkbox").checked = configuration["load_images"];
1285 document.getElementById("jvchat-load-images-checkbox").addEventListener("change", tryCatch(toggleLoadImagesOption));
1286
1287 document.getElementById("jvchat-turbo-delay-range").value = configuration["turbo_delay"];
1288 document.getElementById("jvchat-turbo-delay-span").innerHTML = `${configuration["turbo_delay"]} ms`;
1289 document.getElementById("jvchat-turbo-delay-range").addEventListener("input", tryCatch(changeTurboDelayOption));
1290
1291 document.getElementById("jvchat-max-width-range").value = configuration["max_width"];
1292 document.getElementById("jvchat-max-width-span").innerHTML = `${configuration["max_width"]} %`;
1293 document.getElementById("jvchat-max-width-range").addEventListener("input", tryCatch(changeMaxWidthOption));
1294 adjustMaxWidth(configuration["max_width"]);
1295
1296 let favs = Array.from(document.querySelectorAll("link[rel='icon'], link[rel='shortcut icon']"));
1297 for (let fav of favs) {
1298 fav.parentElement.removeChild(fav);
1299 }
1300 setFavicon("");
1301
1302 document.addEventListener("visibilitychange", function() {
1303 let hidden = document.hidden;
1304 if (hidden) {
1305 let newHr = document.getElementById("jvchat-ruler-new");
1306 if (newHr) {
1307 newHr.removeAttribute("id");
1308 }
1309 nbNewMessage = 0;
1310 } else if (!isError && !isLocked) {
1311 setFavicon("");
1312 }
1313 });
1314}
1315
1316function toggleSidebar(event) {
1317 let isDown = isScrollDown();
1318 document.getElementById("jvchat-leftbar-extend").classList.toggle("jvchat-hide");
1319 document.getElementById("jvchat-leftbar-reduce").classList.toggle("jvchat-hide");
1320 document.getElementById("jvchat-leftbar-config").classList.toggle("jvchat-hide");
1321 document.getElementById("jvchat-leftbar").classList.toggle("jvchat-leftbar-reduced");
1322 if (isDown) {
1323 setScrollDown();
1324 }
1325}
1326
1327function toggleConfig(event) {
1328 document.getElementById("jvchat-leftbar-config-open").classList.toggle("jvchat-hide");
1329 document.getElementById("jvchat-leftbar-config-close").classList.toggle("jvchat-hide");
1330 document.getElementById("jvchat-info").classList.toggle("jvchat-hide");
1331 document.getElementById("jvchat-config").classList.toggle("jvchat-hide");
1332}
1333
1334function toggleTurbo(event) {
1335 let checked = document.getElementById("jvchat-turbo-checkbox").checked;
1336 updateIntervalIdx = 0;
1337 if (!checked) {
1338 turboActivated = false;
1339 } else {
1340 turboActivated = true;
1341 // If waiting for next update, restart it immedtialty, otherwise just wait for the HTTP request to end
1342 if (!fetchingMessages) {
1343 clearTimeout(currentTimeoutId);
1344 updateMessages(currentFetchedPage, true);
1345 }
1346 }
1347}
1348
1349function togglePlaySoundOption(event) {
1350 let checked = document.getElementById("jvchat-play-sound-checkbox").checked;
1351 configuration["play_sound"] = checked;
1352 saveConfig();
1353}
1354
1355function toggleNightModeOption(event) {
1356 let checked = document.getElementById("jvchat-night-mode-checkbox").checked;
1357 configuration["night_mode"] = checked;
1358 saveConfig();
1359 document.getElementById("content").classList.toggle("jvchat-night-mode");
1360}
1361
1362function toggleHideMosaicOption(event) {
1363 let checked = document.getElementById("jvchat-hide-mosaic-checkbox").checked;
1364 configuration["hide_mosaic"] = checked;
1365 saveConfig();
1366 let isDown = isScrollDown();
1367 document.getElementById("jvchat-main").classList.toggle("jvchat-hide-mosaics");
1368 if (isDown) {
1369 setScrollDown();
1370 }
1371}
1372
1373function toggleLoadImagesOption(event) {
1374 let checked = document.getElementById("jvchat-load-images-checkbox").checked;
1375 configuration["load_images"] = checked;
1376 saveConfig();
1377 for (let image of document.getElementsByClassName("jvchat-loadable-image")) {
1378 image.src = image.getAttribute(checked ? "data-src-direct" : "data-src-mini");
1379 }
1380}
1381
1382function changeTurboDelayOption(event) {
1383 let ms = document.getElementById("jvchat-turbo-delay-range").value;
1384 document.getElementById("jvchat-turbo-delay-span").innerHTML = `${ms} ms`;
1385 configuration["turbo_delay"] = parseInt(ms);
1386 saveConfig();
1387}
1388
1389function changeMaxWidthOption(event) {
1390 let maxWidth = parseInt(document.getElementById("jvchat-max-width-range").value);
1391 document.getElementById("jvchat-max-width-span").innerHTML = `${maxWidth} %`;
1392 configuration["max_width"] = maxWidth;
1393 saveConfig();
1394 adjustMaxWidth(maxWidth);
1395}
1396
1397function adjustMaxWidth(maxWidth) {
1398 document.getElementById("page-messages-forum").style["flex-grow"] = maxWidth;
1399 document.getElementById("jvchat-right-padding").style["flex-grow"] = 100 - maxWidth;
1400}
1401
1402function closeAlert(event) {
1403 let target = event.target;
1404 if (!target) {
1405 return;
1406 }
1407 if (target.classList.contains("jvchat-alert-close")) {
1408 let parent = target.parentElement;
1409 parent.parentElement.removeChild(parent);
1410 }
1411}
1412
1413function postMessage() {
1414 if (freshForm === undefined) {
1415 addAlertbox("danger", "Impossible de poster le message, aucun formulaire trouvé");
1416 return;
1417 }
1418
1419 let textarea = document.getElementById("message_topic");
1420
1421 let formData = serializeForm(freshForm);
1422 formData["message_topic"] = textarea.value;
1423 let formulaire = document.getElementById("bloc-formulaire-forum");
1424
1425 formulaire.classList.add("jvchat-disabled-form");
1426 textarea.setAttribute("disabled", "true");
1427
1428 function onSuccess(res) {
1429 formulaire.classList.remove("jvchat-disabled-form");
1430 textarea.removeAttribute("disabled");
1431 let alert = parsePage(res).alert;
1432 if (!alert) {
1433 textarea.value = "";
1434 }
1435 setTextareaHeight();
1436 setScrollDown();
1437 postingMessage = false;
1438 }
1439
1440 function onError(err) {
1441 addAlertbox("danger", err);
1442 formulaire.classList.remove("jvchat-disabled-form");
1443 textarea.removeAttribute("disabled");
1444 postingMessage = false;
1445 }
1446
1447 function onTimeout(err) {
1448 addAlertbox("warning", err);
1449 formulaire.classList.remove("jvchat-disabled-form");
1450 textarea.removeAttribute("disabled");
1451 postingMessage = false;
1452 }
1453
1454 let timeout = 20000;
1455 if (turboActivated) {
1456 timeout = 5000;
1457 }
1458
1459 postingMessage = true;
1460 request("POST", document.URL, onSuccess, onError, onTimeout, makeFormData(formData), false, timeout);
1461}
1462
1463function editMessage(bloc) {
1464 let textarea = bloc.getElementsByClassName("jvchat-edition-textarea")[0];
1465
1466 let blocEdition = bloc.getElementsByClassName("jvchat-edition")[0];
1467 let formData = JSON.parse(blocEdition.getAttribute("data-form"));
1468 formData["message_topic"] = textarea.value;
1469 formData["id_message"] = bloc.getAttribute("jvchat-id");
1470 formData["ajax_hash"] = freshHash;
1471 formData["action"] = "post";
1472 let edition = bloc.getElementsByClassName("jvchat-edition")[0];
1473
1474 edition.classList.add("jvchat-disabled-form");
1475 textarea.setAttribute("disabled", "true");
1476
1477 function onSuccess(res) {
1478 edition.classList.remove("jvchat-disabled-form");
1479 if (res['reset_form']) {
1480 let reset = document.createElement("html");
1481 reset.innerHTML = res["hidden_reset"];
1482 let resetData = serializeForm(reset);
1483 for (let key in resetData) {
1484 formData[key] = resetData[key];
1485 }
1486 blocEdition.setAttribute("data-form", JSON.stringify(formData));
1487 }
1488
1489 textarea.removeAttribute("disabled");
1490 if (res.erreur.length > 0) {
1491 for (let err of res.erreur) {
1492 addAlertbox("danger", err);
1493 }
1494 return;
1495 }
1496 let dom = document.createElement("html");
1497 dom.innerHTML = res["html"];
1498 let message = getMessages(dom)[0];
1499 addMessages([message], true);
1500 }
1501
1502 function onError(err) {
1503 addAlertbox("danger", err);
1504 edition.classList.remove("jvchat-disabled-form");
1505 textarea.removeAttribute("disabled");
1506 }
1507
1508 function onTimeout(err) {
1509 addAlertbox("warning", err);
1510 edition.classList.remove("jvchat-disabled-form");
1511 textarea.removeAttribute("disabled");
1512 }
1513
1514 let url = "http://www.jeuxvideo.com/forums/ajax_edit_message.php";
1515
1516 request("POST", url, onSuccess, onError, onTimeout, makeFormData(formData), true, 20000);
1517}
1518
1519function requestEdit(bloc) {
1520 if (!bloc.getElementsByClassName("jvchat-edition")[0].classList.contains("jvchat-hide")) {
1521 return;
1522 }
1523
1524 let contentClasses = bloc.getElementsByClassName("jvchat-content")[0].classList;
1525 contentClasses.add("disabled-content");
1526
1527 function onSuccess(res) {
1528 contentClasses.remove("disabled-content");
1529 if (res.erreur.length > 0) {
1530 for (let err of res.erreur) {
1531 addAlertbox("danger", err);
1532 }
1533 return;
1534 }
1535 let dom = document.createElement("html");
1536 dom.innerHTML = res["html"];
1537 let textarea = dom.getElementsByTagName("textarea")[0]
1538 let txt = textarea.value;
1539 textarea.parentElement.removeChild(textarea);
1540 let form = dom.getElementsByTagName("form")[0];
1541 let formData = serializeForm(form);
1542 let editionBloc = bloc.getElementsByClassName("jvchat-edition")[0];
1543 editionBloc.setAttribute("data-form", JSON.stringify(formData));
1544 let height = computeHeight(countLines(txt));
1545 let isDown = isScrollDown();
1546 bloc.getElementsByClassName("jvchat-edition-textarea")[0].value = txt;
1547 bloc.getElementsByClassName("jvchat-edition-textarea")[0].style["height"] = `${height}rem`;
1548 bloc.getElementsByClassName("jvchat-content")[0].classList.add("jvchat-hide");
1549 editionBloc.classList.remove("jvchat-hide");
1550 if (isDown) {
1551 setScrollDown();
1552 }
1553 }
1554
1555 function onError(err) {
1556 addAlertbox("danger", err);
1557 contentClasses.remove("disabled-content");
1558 }
1559
1560 function onTimeout(err) {
1561 addAlertbox("warning", err);
1562 contentClasses.remove("disabled-content");
1563 }
1564
1565 let id = bloc.getAttribute("jvchat-id");
1566 let url = `http://www.jeuxvideo.com/forums/ajax_edit_message.php?id_message=${id}&ajax_hash=${freshHash}&action=get`;
1567 request("GET", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1568}
1569
1570function requestDelete(bloc) {
1571
1572 if (!bloc.getElementsByClassName("jvchat-edition")[0].classList.contains("jvchat-hide")) {
1573 return;
1574 }
1575
1576 let contentClasses = bloc.getElementsByClassName("jvchat-content")[0].classList;
1577 contentClasses.add("disabled-content");
1578
1579 function onSuccess(res) {
1580 contentClasses.remove("disabled-content");
1581 if (res.erreur.length > 0) {
1582 for (let err of res.erreur) {
1583 addAlertbox("danger", err);
1584 }
1585 return;
1586 }
1587 let dom = document.createElement("html");
1588 dom.innerHTML = res["html"];
1589 let textarea = dom.getElementsByTagName("textarea")[0]
1590 let txt = textarea.value;
1591 textarea.parentElement.removeChild(textarea);
1592 let form = dom.getElementsByTagName("form")[0];
1593 let formData = serializeForm(form);
1594 let editionBloc = bloc.getElementsByClassName("jvchat-edition")[0];
1595 editionBloc.setAttribute("data-form", JSON.stringify(formData));
1596 let height = computeHeight(countLines(txt));
1597 let isDown = isScrollDown();
1598 bloc.getElementsByClassName("jvchat-edition-textarea")[0].value = txt;
1599 bloc.getElementsByClassName("jvchat-edition-textarea")[0].style["height"] = `${height}rem`;
1600 bloc.getElementsByClassName("jvchat-content")[0].classList.add("jvchat-hide");
1601 editionBloc.classList.remove("jvchat-hide");
1602 if (isDown) {
1603 setScrollDown();
1604 }
1605 }
1606
1607 function onError(err) {
1608 addAlertbox("danger", err);
1609 contentClasses.remove("disabled-content");
1610 }
1611
1612 function onTimeout(err) {
1613 addAlertbox("warning", err);
1614 contentClasses.remove("disabled-content");
1615 }
1616
1617 let id = bloc.getAttribute("jvchat-id");
1618 let url = `http://www.jeuxvideo.com/forums/modal_del_message.php?type=delete&ajax_hash=${deletionHash}&tab_message[]=${id}`;
1619 request("POST", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1620}
1621
1622function countLines(text) {
1623 return text.split(/\r|\r\n|\n/).length;
1624}
1625
1626function computeHeight(lines) {
1627 return 1 * lines + 0.6;
1628}
1629
1630function setTextareaHeight(plusOne) {
1631 let textarea = document.getElementById("message_topic");
1632 if (!isReduced) {
1633 textarea.style["height"] = "";
1634 return;
1635 }
1636 plusOne = !!plusOne;
1637 let lines = countLines(textarea.value);
1638
1639 if (!plusOne && lines === 1) {
1640 textarea.style["height"] = "";
1641 return;
1642 }
1643
1644 if (plusOne) {
1645 lines += 1;
1646 }
1647
1648 let height = computeHeight(lines);
1649 textarea.style["height"] = `${height}rem`;
1650}
1651
1652function postMessageIfEnter(event) {
1653 if (isReduced && (event.which == 13 || event.keyCode == 13)) {
1654 if (event.shiftKey) {
1655 let isDown = isScrollDown();
1656 setTextareaHeight(true);
1657 if (isDown) {
1658 setScrollDown();
1659 }
1660 } else {
1661 event.preventDefault();
1662 postMessage();
1663 }
1664 }
1665}
1666
1667function serializeForm(form) {
1668 // Useless actually, just use new FormData(form)
1669 let dict = {};
1670
1671 for (let select of form.getElementsByTagName("select")) {
1672 dict[select.name] = select.querySelector("option[selected]").value;
1673 }
1674
1675 for (let input of form.getElementsByTagName("input")) {
1676 dict[input.name] = input.value;
1677 }
1678
1679 for (let textarea of form.getElementsByTagName("textarea")) {
1680 dict[textarea.name] = textarea.value;
1681 }
1682
1683 return dict;
1684}
1685
1686function makeFormData(dict) {
1687 var formData = new FormData();
1688 for (let key in dict) {
1689 formData.append(key, dict[key]);
1690 }
1691 return formData;
1692}
1693
1694function getMessages(document) {
1695 let blocMessages = document.getElementsByClassName("bloc-message-forum");
1696 let messages = [];
1697 for (let bloc of blocMessages) {
1698 messages.push(parseMessage(bloc));
1699 }
1700 return messages;
1701}
1702
1703function formatDate(date) {
1704 let now = new Date();
1705 let day = date.getDate();
1706 let month = date.getMonth();
1707 let year = date.getFullYear();
1708 if (now.getDate() === day && now.getMonth() === month && now.getFullYear() === year) {
1709 return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}`;
1710 } else {
1711 return `${day.toString().padStart(2, "0")}/${(month + 1).toString().padStart(2, "0")}/${year}`;
1712 }
1713}
1714
1715function makeMessage(message) {
1716 let content = message.content;
1717 fixMessage(content);
1718 detectMosaic(content);
1719 improveImages(content);
1720 let id = message.id;
1721 let avatar = message.avatar;
1722 let toQuoteDate = message.dateString;
1723 let titleDate = message.dateString;
1724 let textDate = formatDate(message.date);
1725 if (message.edited !== undefined) {
1726 textDate += "*";
1727 titleDate += ` (édité à ${message.edited})`;
1728 }
1729 let exists = avatar !== undefined;
1730 let author = exists ? message.author : `<i>${message.author}</i>`;
1731 let authorHref = exists ? `href="http://www.jeuxvideo.com/profil/${author.toLowerCase()}?mode=infos"` : "";
1732 let authorTitle = exists ? `title="Ouvrir le profil de ${author}"` : "";
1733 let authorAvatarHidden = exists ? "": "class='jvchat-hide-visibility'";
1734 let editionSpan = '<span class="jvchat-edit jvchat-picto picto-msg-crayon" title="Modifier"></span>';
1735 let deletionSpan = '<span class="jvchat-delete jvchat-picto picto-msg-croix" title="Supprimer"></span>';
1736 let deletion = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : deletionSpan;
1737 let edition = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : editionSpan;
1738 let html =
1739 `<div class="jvchat-bloc-message">
1740 <div class="jvchat-message" jvchat-id=${id}>
1741 <div>
1742 <a ${authorAvatarHidden} ${authorHref} target="_blank" ${authorTitle}>
1743 <div class="jvchat-bloc-avatar jvchat-rounded" style="background-image: url(${avatar})"></div>
1744 </a>
1745 </div>
1746 <div class="jvchat-bloc-author-content">
1747 <div class="jvchat-toolbar">
1748 <h5 class="jvchat-author">${author}</h5>
1749 <div class="jvchat-tooltip">
1750 ${deletion}
1751 ${edition}
1752 <span class="jvchat-picto jvchat-quote picto-msg-quote" title="Citer"></span>
1753 <small class="jvchat-date" to-quote="${toQuoteDate}" title="${titleDate}">${textDate}</small>
1754 </div>
1755 </div>
1756 <div class="jvchat-content">${content.outerHTML}</div>
1757 <div class="jvchat-edition jvchat-hide">
1758 <textarea class="jvchat-edition-textarea jvchat-textarea"></textarea>
1759 <div class="jvchat-buttons">
1760 <button tabindex="0" type="button" class='jvchat-edition-check icon-check-jv jvchat-button-top' title="Valider la modification"></button>
1761 <button tabindex="0" type="button" class='jvchat-edition-cancel icon-cancel-circle jvchat-button-bottom' title="Annuler la modification"></button>
1762 </div>
1763 </div>
1764 </div>
1765 </div>
1766 <hr class="jvchat-ruler">
1767 </div>`;
1768 return html;
1769}
1770
1771function parseDate(string) {
1772 let [date, time] = string.toLowerCase().split("à");
1773 let [day, month, year] = date.trim().split(" ");
1774 let [hour, minute, second] = time.trim().split(":");
1775 let monthIndex = ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"].indexOf(month.trim().toLowerCase());
1776 return new Date(parseInt(year), monthIndex, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second));
1777}
1778
1779function addMessages(messages, editing) {
1780 editing = !!editing;
1781 let main = document.getElementById("jvchat-main");
1782 let hasNewMessages = false;
1783 let init = true;
1784 let toInsert = "";
1785 let newMessagesIds = [];
1786 for (let message of messages) {
1787 let date = message.date;
1788 let id = message.id;
1789
1790 if (init === true && !editing) {
1791 init = false;
1792 let now = new Date();
1793 let delta = now - date;
1794 if (delta > 5 * 60 * 1000 + checkEditInterval) {
1795 shouldCheckEdited = false;
1796 } else {
1797 shouldCheckEdited = true;
1798 }
1799 }
1800
1801 if (message.blacklisted) {
1802 continue;
1803 }
1804
1805 if (firstMessageId === undefined) {
1806 firstMessageId = id;
1807 firstMessageDate = date;
1808 }
1809 let referenced = allMessagesId.hasOwnProperty(id);
1810 let edited = message.edited;
1811
1812 // Attention à 2 choses: le changement d'heure et le fait qu'un message suivant un autre peut avoir un id inférieur au précédent
1813 if ((id < firstMessageId && date < firstMessageDate) || (referenced && allMessagesId[id] === edited)) {
1814 continue;
1815 }
1816
1817 let newBloc = makeMessage(message);
1818 allMessagesId[id] = edited;
1819
1820 if (referenced) {
1821 let selector = `.jvchat-message[jvchat-id="${id}"]`;
1822 let oldBloc = main.querySelector(selector).closest(".jvchat-bloc-message");
1823 let isDown = isScrollDown();
1824 oldBloc.outerHTML = newBloc;
1825 if (isDown) {
1826 setScrollDown();
1827 }
1828 continue;
1829 }
1830
1831 hasNewMessages = true;
1832 if (nbNewMessage === 0 && document.hidden) {
1833 let hrs = document.getElementsByClassName("jvchat-ruler");
1834 let lastHr = hrs[hrs.length - 1];
1835 lastHr.setAttribute("id", "jvchat-ruler-new");
1836 }
1837
1838 toInsert += newBloc;
1839 newMessagesIds.push(id);
1840 nbNewMessage++;
1841 }
1842
1843 if (toInsert !== "") {
1844 let isDown = isScrollDown();
1845 main.insertAdjacentHTML("beforeend", toInsert);
1846 if (isDown) {
1847 setScrollDown();
1848 }
1849 }
1850
1851 if (editing) {
1852 return;
1853 }
1854
1855 if (isScrollDown()) {
1856 let blocMessages = main.getElementsByClassName("jvchat-bloc-message");
1857 let nb = blocMessages.length;
1858 if (nb > 100) {
1859 for (let i = 0; i < nb - 100; i++) {
1860 main.removeChild(blocMessages[0]);
1861 }
1862 setScrollDown();
1863 }
1864 }
1865
1866 if (hasNewMessages) {
1867 if (!turboActivated) {
1868 decreaseUpdateInterval();
1869 }
1870 if (document.hidden) {
1871 setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage);
1872 if (configuration["play_sound"]) {
1873 ringBell.pause();
1874 ringBell.currentTime = 0;
1875 ringBell.play();
1876 }
1877 }
1878 for (let newMessageId of newMessagesIds) {
1879 let event = new CustomEvent('jvchat:newmessage', { 'detail': { id: newMessageId } });
1880 dispatchEvent(event);
1881 }
1882 } else {
1883 if (!turboActivated) {
1884 increaseUpdateInterval();
1885 }
1886 }
1887}
1888
1889function submitSondageAnswer(event) {
1890 let target = event.target;
1891 if (!target) {
1892 return;
1893 }
1894 if (target.classList.contains("click-sondage")) {
1895 let reponseNum = parseInt(target.getAttribute("sondage-reponse-num"));
1896 let sondageId = sondageChoices[reponseNum]["sondageId"];
1897 let reponseId = sondageChoices[reponseNum]["responseId"];
1898 let topicId = urlToFetch["ids"].split("-")[2];
1899 let url = `http://www.jeuxvideo.com/forums/ajax_topic_sondage_vote.php?id_topic=${topicId}&id_sondage_reponse=${reponseId}&id_sondage=${sondageId}&ajax_hash=${freshHash}`;
1900
1901 function onSuccess(res) {
1902 if (res.erreur.length > 0) {
1903 for (let err of res.erreur) {
1904 addAlertbox("danger", err);
1905 }
1906 return;
1907 }
1908 let dom = document.createElement("html");
1909 dom.innerHTML = res["html"];
1910
1911 let sondage = parseSondage(dom);
1912 if (!sondage) {
1913 addAlertbox("warning", "Erreur lors de la récupération du sondage");
1914 return;
1915 }
1916
1917 setSondage(sondage);
1918 }
1919
1920 function onError(err) {
1921 addAlertbox("danger", err);
1922 }
1923
1924 function onTimeout(err) {
1925 addAlertbox("warning", err);
1926 }
1927
1928 request("POST", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1929 }
1930}
1931
1932function setSondage(sondage) {
1933 let choix = document.getElementById("jvchat-sondage-choix");
1934
1935 if (sondage["answered"]) {
1936 choix.removeEventListener("click", submitSondageAnswer);
1937 choix.classList.remove("notanswered");
1938 } else {
1939 if (!sondageChoices) {
1940 sondageChoices = sondage["results"];
1941 }
1942 choix.addEventListener("click", submitSondageAnswer);
1943 choix.classList.add("notanswered");
1944 }
1945
1946 if (!choix.firstChild) {
1947 document.getElementById("jvchat-sondage-intitule").innerHTML = sondage["intitule"];
1948 let results = sondage["results"];
1949 for (let i = 0; i < results.length; i++) {
1950 let res = results[i];
1951 let tr = `<tr><td class="result-pourcent"><div class="pourcent">${res["pourcent"]} %</div><div class="back-barre"><span style="width: ${res["pourcent"]}%;"></span></div></td><td class="reponse"><div class="click-sondage" sondage-reponse-num="${i}">${res["response"]}</div></td></tr>`;
1952 choix.insertAdjacentHTML("beforeend", tr);
1953 }
1954 } else {
1955 let trs = choix.getElementsByClassName("result-pourcent");
1956 for (let i = 0; i < trs.length; i++) {
1957 let res = sondage["results"][i];
1958 let tr = trs[i];
1959 tr.getElementsByClassName("pourcent")[0].innerHTML = `${res["pourcent"]} %`;
1960 tr.getElementsByTagName("span")[0].style["width"] = `${res["pourcent"]}%`;
1961 }
1962 }
1963
1964 document.getElementById("jvchat-sondage-votes").innerHTML = `(${sondage["votes"]} votes)`;
1965}
1966
1967function setUser(document, user) {
1968 let isConnected = (user.author !== undefined);
1969
1970 if (isConnected) {
1971 if (user.author !== currentUser.author) {
1972 let pseudo = document.getElementById("jvchat-user-pseudo");
1973 pseudo.innerHTML = user.author;
1974 let avatarLink = document.getElementById("jvchat-user-avatar-link");
1975 let notifLink = document.getElementById("jvchat-user-notif-link");
1976 avatarLink.setAttribute("href", `http://www.jeuxvideo.com/profil/${user.author.toLowerCase()}?mode=infos`);
1977 notifLink.setAttribute("href", `http://www.jeuxvideo.com/profil/${user.author.toLowerCase()}?mode=abonnements`);
1978 }
1979
1980 if (user.avatar !== currentUser.avatar) {
1981 let avatar = document.getElementById("jvchat-user-avatar");
1982 avatar.style["background-image"] = `url("${user.avatar}")`;
1983 }
1984
1985 if (user.mp !== currentUser.mp) {
1986 let mp = document.getElementById("jvchat-user-mp");
1987 mp.setAttribute("data-val", user.mp);
1988 if (user.mp > 0) {
1989 mp.classList.add("has-notif");
1990 } else {
1991 mp.classList.remove("has-notif");
1992 }
1993 }
1994
1995 if (user.notif !== currentUser.notif) {
1996 let notif = document.getElementById("jvchat-user-notif");
1997 notif.setAttribute("data-val", user.notif);
1998 if (user.notif > 0) {
1999 notif.classList.add("has-notif");
2000 } else {
2001 notif.classList.remove("has-notif");
2002 }
2003 }
2004 }
2005
2006 if ((userConnected === undefined && isConnected) || (userConnected !== undefined && isConnected !== userConnected)) {
2007 document.getElementById("jvchat-profil").classList.toggle("jvchat-hide");
2008 let isDown = isScrollDown();
2009 document.getElementById("bloc-formulaire-forum").classList.toggle("jvchat-hide");
2010 if (isDown) {
2011 setScrollDown();
2012 }
2013 }
2014
2015 if (userConnected !== undefined) {
2016 if (isConnected && !userConnected) {
2017 addAlertbox("success", "Vous êtes désormais connecté");
2018 } else if (!isConnected && userConnected) {
2019 addAlertbox("warning", "Vous avez été déconnecté");
2020 }
2021 }
2022
2023 userConnected = isConnected;
2024 currentUser = user;
2025}
2026
2027function setTopicTitle(document, topicTitle) {
2028 if (topicTitle !== currentTopicTitle) {
2029 currentTopicTitle = topicTitle;
2030 document.getElementById("jvchat-topic-title").innerHTML = topicTitle;
2031 }
2032}
2033
2034function setTopicNbConnected(document, nbConnected) {
2035 let txt = `${nbConnected} connectés`;
2036 if (!(nbConnected > 1)) {
2037 if (nbConnected === undefined) {
2038 txt = "? connectés";
2039 } else {
2040 txt = txt.slice(0, -1);
2041 }
2042 }
2043 document.getElementById("jvchat-topic-nb-connected").innerHTML = txt;
2044}
2045
2046function setTopicNbMessages(document, nbMessages) {
2047 let txt = `${nbMessages} messages`;
2048 if (!(nbMessages > 1)) {
2049 if (nbMessages === undefined) {
2050 txt = "? messages";
2051 } else {
2052 txt = txt.slice(0, -1);
2053 }
2054 }
2055 document.getElementById("jvchat-topic-nb-messages").innerHTML = txt;
2056}
2057
2058function triggerJVChat() {
2059 // TamperMonkey / Chrome bug: https://github.com/Tampermonkey/tampermonkey/issues/705#issuecomment-493895776
2060 if (window) {
2061 if (window.clearTimeout) {
2062 window.clearTimeout = window.clearTimeout.bind(window);
2063 }
2064 if (window.clearInterval) {
2065 window.clearInterval = window.clearInterval.bind(window);
2066 }
2067 if (window.setTimeout) {
2068 window.setTimeout = window.setTimeout.bind(window);
2069 }
2070 if (window.setInterval) {
2071 window.setInterval = window.setInterval.bind(window);
2072 }
2073 window.onbeforeunload = function(event) {
2074 leavingTopic = true;
2075 }
2076 }
2077
2078 let topicUrl = document.URL;
2079 let topic = parseTopicInfo(document);
2080 let user = parseUserInfo(document);
2081 let sondage = parseSondage(document);
2082
2083 urlToFetch = parseURL(topicUrl);
2084 urlToFetch.page = 1;
2085 urlToFetch.anchor = "";
2086
2087 urlToCheckEdit = parseURL(topicUrl);
2088 urlToCheckEdit.page = 1;
2089 urlToCheckEdit.anchor = "";
2090
2091 loadConfig();
2092 ringBell = new Audio(configuration["sound"]);
2093 clearPage(document);
2094
2095 setUser(document, user);
2096 setTopicTitle(document, topic.title);
2097 setTopicNbMessages(document, undefined);
2098 setTopicNbConnected(document, topic.connected);
2099
2100 if (sondage) {
2101 document.getElementById("jvchat-sondage").classList.remove("jvchat-hide")
2102 setSondage(sondage);
2103 }
2104
2105 document.getElementById("jvchat-topic-title").setAttribute("href", buildURL(urlToFetch));
2106
2107 let forum = getForum(document);
2108 let forumSide = document.getElementById("jvchat-forum-title");
2109 forumSide.setAttribute("href", forum.href);
2110 forumSide.innerHTML = forum.title;
2111
2112 let defaultReduced = configuration["default_reduced"];
2113 let messageTopic = document.getElementById("message_topic");
2114
2115 if (defaultReduced === false || (messageTopic && messageTopic.value !== "")) {
2116 toggleTextarea();
2117 }
2118
2119 let event = new CustomEvent('jvchat:activation');
2120 dispatchEvent(event);
2121
2122 let page = topic.lastPage > 1 ? topic.lastPage - 1 : topic.lastPage;
2123 updateMessages(page, true);
2124
2125 setInterval(checkEdited, checkEditInterval);
2126}
2127
2128
2129function updateMessages(page, goToLast) {
2130 if (postingMessage && turboActivated) {
2131 // Postpone message fetching, posting the message is priorized
2132 fetchingMessages = false;
2133 currentTimeoutId = setTimeout(tryCatch(function() {
2134 updateMessages(page, goToLast);
2135 }), 100);
2136 return;
2137 }
2138
2139 function scheduleNextUpdate(interval, p, goLast) {
2140 fetchingMessages = false;
2141 currentTimeoutId = setTimeout(tryCatch(function() {
2142 updateMessages(p, goLast);
2143 }), interval);
2144 };
2145
2146 function onSuccess(res) {
2147 let parsed = parsePage(res);
2148 let lastPage = parsed.lastPage;
2149 let currPage = parsed.page;
2150 let int = turboActivated ? configuration["turbo_delay"] : updateIntervals[updateIntervalIdx] * 1000;
2151
2152 if (page < lastPage && goToLast) {
2153 updateMessages(page + 1, true);
2154 } else if (currPage < page || parsed.nbMessagesPage === 0) { // Bug des messages supprimés
2155 scheduleNextUpdate(int, page - 1, false);
2156 } else if (page > lastPage) {
2157 updateMessages(lastPage, true);
2158 } else {
2159 scheduleNextUpdate(int, page, true);
2160 }
2161 }
2162
2163 function onError(err) {
2164 if (!isError) {
2165 isError = true;
2166 setFixedAlert("danger", err);
2167 }
2168 scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 60000, page, true);
2169 }
2170
2171 function onTimeout(err) {
2172 addAlertbox("warning", err);
2173 scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 10000, page, true);
2174 }
2175
2176 let timeout = 10000;
2177 if (turboActivated) {
2178 timeout = 5000;
2179 }
2180
2181 fetchingMessages = true;
2182 currentFetchedPage = page;
2183 urlToFetch.page = page;
2184 let urlLastPage = buildURL(urlToFetch);
2185 request("GET", urlLastPage, onSuccess, onError, onTimeout, undefined, false, timeout);
2186}
2187
2188function checkEdited() {
2189 if (!shouldCheckEdited || currentFetchedPage === 1 || isError) {
2190 return;
2191 }
2192
2193 urlToCheckEdit.page = currentFetchedPage - 1;
2194 let urlPrevLastPage = buildURL(urlToCheckEdit);
2195
2196 function onSuccess(res) {
2197 let newMessages = [];
2198 let edited = res.getElementsByClassName("info-edition-msg");
2199 for (let msg of edited) {
2200 let bloc = msg.closest(".bloc-message-forum");
2201 newMessages.push(parseMessage(bloc));
2202 }
2203 addMessages(newMessages, true);
2204 }
2205
2206 function onError() {}
2207
2208 function onTimeout() {}
2209
2210 request("GET", urlPrevLastPage, onSuccess, onError, onTimeout, undefined, false, 20000);
2211}
2212
2213function parseAlerts(res) {
2214 let alerts = [];
2215 let alertsDiv = res.getElementsByClassName("alert");
2216 for (let a of alertsDiv) {
2217 let type = "danger";
2218 if (a.classList.contains("alert-warning")) {
2219 type = "warning";
2220 } else if (a.classList.contains("alert-success")) {
2221 type = "success";
2222 }
2223 let message = a.getElementsByClassName("alert-row")[0].textContent.trim();
2224 alerts.push({type: type, message: message});
2225 }
2226 return alerts;
2227}
2228
2229function increaseUpdateInterval() {
2230 if (updateIntervalIdx < updateIntervalMax) {
2231 updateIntervalIdx++;
2232 }
2233}
2234
2235function decreaseUpdateInterval() {
2236 updateIntervalIdx = transisitions[updateIntervalIdx];
2237}
2238
2239function parsePage(res) {
2240 let error = getTopicError(res);
2241 if (error !== undefined) {
2242 if (!isError) {
2243 updateIntervalIdx = updateIntervalMax;
2244 isError = true;
2245 setFixedAlert("danger", error);
2246 }
2247 return {lastPage: undefined, page: undefined, alert: true, nbMessagesPage: 0}
2248 }
2249
2250 if (isError) {
2251 isError = false;
2252 updateIntervalIdx = 0;
2253 removeFixedAlert("Le topic ne retourne plus d'erreur");
2254 }
2255
2256 let form = getForm(res);
2257 if (form !== undefined) {
2258 freshForm = form;
2259 }
2260
2261 let hash = getHash(res);
2262 if (hash !== undefined) {
2263 freshHash = hash;
2264 }
2265
2266 let messages = getMessages(res);
2267 addMessages(messages);
2268 let user = parseUserInfo(res);
2269 setUser(document, user);
2270 let topic = parseTopicInfo(res);
2271 let nbMessages = (topic.lastPage - 1) * 20;
2272 if (topic.page == topic.lastPage) {
2273 nbMessages += messages.length;
2274 }
2275 setTopicNbMessages(document, nbMessages);
2276 setTopicNbConnected(document, topic.connected);
2277 let alerts = parseAlerts(res);
2278 for (let alert of alerts) {
2279 addAlertbox(alert.type, alert.message);
2280 }
2281 let locked = getTopicLocked(res);
2282 let isLocked_ = (locked !== undefined);
2283
2284 if (isLocked_ && !isLocked) {
2285 updateInterval = updateIntervalMax;
2286 setFixedAlert("warning", locked);
2287 } else if (!isLocked_ && isLocked) {
2288 updateInterval = 0;
2289 removeFixedAlert("Le topic a été dévérouillé");
2290 }
2291 isLocked = isLocked_;
2292
2293 let sondage = parseSondage(res);
2294 if (sondage) {
2295 setSondage(sondage);
2296 }
2297
2298 return {page: topic.page, lastPage: topic.lastPage,
2299 nbMessagesPage: messages.length, alert: isLocked_ || (alerts.length > 0)};
2300}
2301
2302function addAlertbox(type, message) {
2303 // type: success / warning / danger
2304 let alert = `<div class="alert alert-${type}">
2305 <button class="close jvchat-alert-close" aria-hidden="true" data-dismiss="alert" type="button">×</button>
2306 <div class="alert-row">${message}</div>
2307 </div>`;
2308 document.getElementById("jvchat-fixed-alert").insertAdjacentHTML("afterend", alert);
2309}
2310
2311function setFixedAlert(type, message) {
2312 setFavicon("⨯");
2313 document.getElementById("jvchat-fixed-alert").getElementsByClassName("alert-row")[0].innerHTML = message;
2314 document.getElementById("jvchat-fixed-alert").setAttribute("class", `alert alert-${type}`);
2315}
2316
2317function removeFixedAlert(message) {
2318 document.getElementById("jvchat-fixed-alert").classList.add("jvchat-hide");
2319 if (message !== undefined) {
2320 addAlertbox("success", message);
2321 }
2322 if (document.hidden && nbNewMessage > 0) {
2323 setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage);
2324 } else {
2325 setFavicon("");
2326 }
2327}
2328
2329function makeJVChatButton() {
2330 let cls = 'btn-jvchat';
2331 let text = 'JVChat';
2332 let btn = `<button class="btn btn-actu-new-list-forum ${cls}">${text}</button>`;
2333 return btn;
2334}
2335
2336function addJVChatButton(document) {
2337 let css = `<style type="text/css">
2338 #forum-main-col .bloc-pre-pagi-forum {
2339 display: flex;
2340 }
2341
2342 #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right {
2343 position: relative;
2344 right: unset;
2345 left: unset;
2346 top: unset;
2347 bottom: unset;
2348 overflow: hidden;
2349 display: flex;
2350 flex-wrap: wrap;
2351 justify-content: flex-end;
2352 margin-top: auto;
2353 flex: 1;
2354 }
2355
2356 #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right button {
2357 float: right;
2358 min-width: 5.25rem;
2359 margin-left: 0.3125rem;
2360 }
2361 </style>`
2362 document.head.insertAdjacentHTML("beforeend", css);
2363 let blocPreRight = document.getElementsByClassName("bloc-pre-right");
2364 let jvchatButton = makeJVChatButton();
2365 for (let bloc of blocPreRight) {
2366 bloc.insertAdjacentHTML('afterbegin', jvchatButton);
2367 }
2368}
2369
2370function bindJVChatButton(document) {
2371 let buttons = document.getElementsByClassName('btn-jvchat');
2372 for (let btn of buttons) {
2373 btn.addEventListener('click', tryCatch(triggerJVChat));
2374 }
2375}
2376
2377function request(mode, url, callbackSuccess, callbackError, callbackTimeout, data, json, timeout) {
2378 json = !!json;
2379 let xhr = new XMLHttpRequest();
2380 xhr.timeout = timeout;
2381
2382 xhr.ontimeout = tryCatch(function() {
2383 callbackTimeout(`La délai d'attente de la requête a expiré`);
2384 });
2385
2386 xhr.onerror = tryCatch(function() {
2387 callbackError(`La requête a échoué (${xhr.status}): ${xhr.statusText}`);
2388 });
2389
2390 xhr.onabort = tryCatch(function() {
2391 if (!leavingTopic) {
2392 callbackTimeout(`La requête a été interrompue pour une raison inconnue`);
2393 }
2394 });
2395
2396 xhr.onload = tryCatch(function() {
2397 if (xhr.status !== 200) {
2398 callbackError(`La requête a retourné une erreur (${xhr.status}): ${xhr.statusText}`);
2399 return;
2400 }
2401 callbackSuccess(xhr.response);
2402 });
2403
2404 if (data === undefined) {
2405 data = null;
2406 }
2407
2408 if (json) {
2409 xhr.responseType = "json";
2410 } else {
2411 xhr.responseType = "document";
2412 }
2413
2414 xhr.open(mode, url, true);
2415 xhr.setRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate");
2416 xhr.send(data);
2417};
2418
2419// On copie/colle le code de TopicLive et on se sent développeur :)
2420function makeFavicon() {
2421 let canvas = document.createElement("canvas");
2422 canvas.width = 16;
2423 canvas.height = 16;
2424 let context = canvas.getContext('2d');
2425 let image = new Image();
2426 image.src = 'data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABMLAAATCwAAAAAAAAAAAABkRgT/ZEYE/2RGBP9kRgT/ZEYE/2RGBf9lRgD/YEcV/zJW7v8tV///Llf+/y5X//8uV///Llf//y5X//8uV///ZEYE/2RGBP9kRgT/ZEYE/2RGBP9kRgX/ZUYA/2BHFf8yVu7/LVf//y5X/v8uV///Llf//y5X//8uV///Llf//2RGBP9kRgT/ZEYE/2VHBf9lRwX/ZEYF/2VGAP9gRxX/Mlbu/y1X//8uV/7/Llf//y5X//8uV///Llf//y5X//9kRgT/ZEcF/2ZIB/9iQwH/YkMB/2ZJCP9lRgD/YEcV/zJW7v8tV///L1f+/y1W//8tVv//L1j//y5X//8uV///ZUcE/2NFBP9ZOQD/bE8R/2xPEf9ZOQD/ZEQA/2FIFv8xVu7/Llj//yxV/v8uV///Llf//ytV//8vWP//Llf//2NFA/9kRgj/xLif/+7r5P/u6+T/w7if/2VGBP9fRhT/M1fv/yxW//8uV/7/1d3//9Xd//8uV///LVb//y9Y//9ZOQD/wLOZ/9/Yy/91WiD/dVog/97Yy//CtZj/VzsF/zFW8f8tV///L1f+/9Lb///S2///L1f//y5X//8rVf//bFAR/+nk2v91Wib/WzsA/1s7AP90Wif/7OfZ/2dQIv8wU+v/1d7//9Pb/v8tVv//LVb//9Pc///S2///Llf//2xQEf/p5Nr/dVom/1s7AP9bOwD/dFon/+zn2f9nUCL/MFPr/9Xe///T2/7/LVb//y1W///T3P//0tv//y5X//9ZOQD/wLOZ/9/Yy/91WiD/dVog/97Yy//CtZj/VzsF/zFW8f8tV///L1f+/9Lb///S2///L1f//y5X//8rVf//Y0UD/2RGCP/EuJ//7uvk/+7r5P/DuJ//ZUYE/19GFP8zV+//LFb//y5X/v/V3f//1d3//y5X//8tVv//L1j//2VHBP9jRQT/WTkA/2xPEf9sTxH/WTkA/2REAP9hSBb/MVbu/y5Y//8sVf7/Llf//y5X//8rVf//L1j//y5X//9kRgT/ZEcF/2ZIB/9iQwH/YkMB/2ZJCP9lRgD/YEcV/zJW7v8tV///L1f+/y1W//8tVv//L1j//y5X//8uV///ZEYE/2RGBP9kRgT/ZUcF/2VHBf9kRgX/ZUYA/2BHFf8yVu7/LVf//y5X/v8uV///Llf//y5X//8uV///Llf//2RGBP9kRgT/ZEYE/2RGBP9kRgT/ZEYF/2VGAP9gRxX/Mlbu/y1X//8uV/7/Llf//y5X//8uV///Llf//y5X//9kRgT/ZEYE/2RGBP9kRgT/ZEYE/2RGBf9lRgD/YEcV/zJW7v8tV///Llf+/y5X//8uV///Llf//y5X//8uV///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==';
2427 return {canvas: canvas, context: context, image: image};
2428};
2429
2430function clearFavicon() {
2431 favicon.context.clearRect(0, 0, favicon.canvas.width, favicon.canvas.height);
2432 favicon.context.drawImage(favicon.image, 0, 0);
2433};
2434
2435function fillFavicon(txt) {
2436 clearFavicon();
2437
2438 if (txt !== '') {
2439 let context = favicon.context;
2440 context.fillStyle = 'DodgerBlue';
2441 context.fillRect(0, 0, context.measureText(txt).width + 3, 11);
2442 context.fillStyle = 'white';
2443 context.font = 'bold 10px Verdana';
2444 context.textBaseline = 'bottom';
2445 context.fillText(txt, 1, 11);
2446 }
2447};
2448
2449function setFavicon(txt) {
2450 let fav = document.getElementById("jvchat-favicon");
2451 if (fav) {
2452 fav.parentElement.removeChild(fav);
2453 }
2454 fillFavicon(txt);
2455 let url = favicon.canvas.toDataURL('image/png');
2456 let icon = `<link id="jvchat-favicon" rel="shortcut icon" type="image/png" href="${url}">`;
2457 document.head.insertAdjacentHTML("beforeend", icon);
2458}
2459
2460function reverseMessage(node, isInit, isUl) {
2461 let quote = "";
2462 let prevIsP = false;
2463
2464 for (let child of node.childNodes) {
2465 let name = child.nodeName;
2466
2467 switch (name) {
2468 case "P": {
2469 quote += reverseMessage(child) + "\n\n";
2470 break;
2471 }
2472 case "STRONG": {
2473 quote += "'''" + reverseMessage(child) + "'''";
2474 break;
2475 }
2476 case "EM": {
2477 quote += "''" + reverseMessage(child) + "''";
2478 break;
2479 }
2480 case "BR": {
2481 break;
2482 }
2483 case "UL": {
2484 quote += reverseMessage(child, false, true) + "\n\n";
2485 break;
2486 }
2487 case "OL": {
2488 quote += reverseMessage(child, false, false) + "\n\n";
2489 break;
2490 }
2491 case "LI": {
2492 if (isUl === true) {
2493 quote += "* " + reverseMessage(child) + "\n";
2494 } else {
2495 quote += "# " + reverseMessage(child) + "\n";
2496 }
2497 break;
2498 }
2499 case "DIV": {
2500 let classList = child.classList;
2501 if (classList.contains("bloc-spoil-jv")) {
2502 quote += "<spoil>" + reverseMessage(child) + "</spoil>\n\n"
2503 } else if (classList.contains("contenu-spoil")) {
2504 quote += reverseMessage(child);
2505 }
2506 break;
2507 }
2508 case "SPAN": {
2509 let classList = child.classList;
2510 if (classList.contains("bloc-spoil-jv")) {
2511 quote += "<spoil>" + reverseMessage(child) + "</spoil>";
2512 } else if (classList.contains("contenu-spoil")) {
2513 quote += reverseMessage(child);
2514 }
2515 break;
2516 }
2517 case "LABEL": {
2518 break;
2519 }
2520 case "INPUT": {
2521 break;
2522 }
2523 case "IMG": {
2524 quote += child.alt;
2525 break;
2526 }
2527 case "A": {
2528 if (child.title) {
2529 quote += child.href;
2530 } else {
2531 quote += reverseMessage(child);
2532 }
2533 break;
2534 }
2535 case "PRE": {
2536 quote += reverseMessage(child) + "\n\n";
2537 break;
2538 }
2539 case "CODE": {
2540 quote += "<code>" + child.textContent + "</code>";
2541 break;
2542 }
2543 case "BLOCKQUOTE": {
2544 if (prevIsP) {
2545 quote = quote.trimEnd() + "\n" + reverseMessage(child).replace(/^/gm, '> ') + "\n\n";
2546 } else {
2547 quote += reverseMessage(child).replace(/^/gm, '> ') + "\n\n";
2548 }
2549
2550 break;
2551 }
2552 case "#text": {
2553 // The "isInit" check is to prevent the empty text surroudning message
2554 // However, it may happen that the root node contains valid text child, so it need to be added somehow
2555 // For some reason, an "new line" may be missing in this case, so just add it
2556 if (!isInit || child.textContent.trim() !== "") {
2557 quote += child.textContent;
2558 if (isInit && !quote.endsWith("\n")) {
2559 quote += "\n";
2560 }
2561 }
2562 break;
2563 }
2564 default: {
2565 break;
2566 }
2567 }
2568
2569 if (name == "P") {
2570 prevIsP = true;
2571 } else {
2572 prevIsP = false;
2573 }
2574 }
2575
2576 quote = quote.replace(/(\n){3,}/g, '\n\n').trim();
2577
2578 if (isInit) {
2579 quote = quote.replace(/^/gm, '> ');
2580 }
2581
2582 return quote;
2583}
2584
2585function reverseQuote(blocMessage) {
2586 let author = blocMessage.getElementsByClassName("jvchat-author")[0].textContent.trim();
2587 let date = blocMessage.getElementsByClassName("jvchat-date")[0].getAttribute("to-quote");
2588 let header = `> Le ${date} ${author} a écrit :\n`;
2589 let quoted = reverseMessage(blocMessage.getElementsByClassName("txt-msg")[0], true);
2590 return header + quoted + '\n\n';
2591}
2592
2593function insertAtCursor(input, textToInsert) {
2594 const value = input.value;
2595 const start = input.selectionStart;
2596 const end = input.selectionEnd;
2597 input.value = value.slice(0, start) + textToInsert + value.slice(end);
2598 input.selectionStart = input.selectionEnd = start + textToInsert.length;
2599}
2600
2601function dontScrollOnExpand(event) {
2602 event.preventDefault()
2603 let target = event.target;
2604 if (!target) {
2605 return;
2606 }
2607
2608 let classes = target.classList;
2609
2610 if (classes.contains("blockquote-jv")) {
2611 let isDown = isScrollDown();
2612 target.setAttribute('data-visible', '1');
2613 if (isDown) {
2614 setScrollDown();
2615 }
2616 } else if (classes.contains("txt-spoil") || classes.contains("aff-spoil") || classes.contains("masq-spoil")) {
2617 event.preventDefault();
2618 let check = target.closest(".bloc-spoil-jv").getElementsByClassName("open-spoil")[0];
2619 let isDown = isScrollDown();
2620 check.checked = !check.checked;
2621 if (isDown) {
2622 setScrollDown();
2623 }
2624 } else if (classes.contains("jvchat-quote")) {
2625 let bloc = target.closest(".jvchat-message");
2626 let quote = reverseQuote(bloc);
2627 let textarea = document.getElementById("message_topic");
2628 if (isReduced) {
2629 toggleTextarea();
2630 }
2631 insertAtCursor(textarea, quote);
2632 textarea.focus();
2633 } else if (classes.contains("jvchat-edit")) {
2634 let bloc = target.closest(".jvchat-message");
2635 requestEdit(bloc);
2636 } else if (classes.contains("jvchat-delete")) {
2637 let bloc = target.closest(".jvchat-message");
2638 requestDelete(bloc);
2639 } else if (classes.contains("jvchat-edition-check")) {
2640 let bloc = target.closest(".jvchat-message");
2641 editMessage(bloc);
2642 } else if (classes.contains("jvchat-edition-cancel")) {
2643 let bloc = target.closest(".jvchat-message");
2644 let isDown = isScrollDown();
2645 bloc.getElementsByClassName("jvchat-content")[0].classList.remove("jvchat-hide");
2646 bloc.getElementsByClassName("jvchat-edition")[0].classList.add("jvchat-hide");
2647 if (isDown) {
2648 setScrollDown();
2649 }
2650 }
2651}
2652
2653function isScrollDown() {
2654 let element = document.getElementById("jvchat-main");
2655 return element.clientHeight + Math.floor(element.scrollTop) >= element.scrollHeight - 1;
2656}
2657
2658function setScrollDown() {
2659 let element = document.getElementById("jvchat-main");
2660 element.scrollTop = element.scrollHeight + 10000;
2661}
2662
2663function main() {
2664 addJVChatButton(document);
2665 bindJVChatButton(document);
2666}
2667
2668main();