· 6 years ago · Nov 24, 2019, 04:54 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
901function getForm(doc) {
902 return doc.getElementsByClassName('form-post-message')[0];
903}
904
905function getHash(doc) {
906 let hash = doc.querySelector("#ajax_hash_liste_messages")
907 if (!hash) {
908 return undefined;
909 }
910 return hash.getAttribute("value");
911}
912
913let freshHash = getHash(document);
914let freshForm = getForm(document);
915let firstMessageId = undefined;
916let firstMessageDate = undefined;
917let allMessagesId = {};
918let userConnected = undefined;
919let 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];
920let 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];
921let updateIntervalIdx = 0;
922let updateIntervalMax = updateIntervals.length - 1;
923let isLocked = false;
924let isError = false;
925let isReduced = true;
926let nbNewMessage = 0;
927let favicon = makeFavicon();
928let currentUser = {notif: undefined, mp: undefined, author: undefined, avatar: undefined};
929let currentTopicTitle = undefined;
930let turboActivated = false;
931let sondageChoices = undefined;
932let urlToFetch = undefined;
933let urlToCheckEdit = undefined;
934let currentFetchedPage = 1;
935let currentTimeoutId = -1;
936let shouldCheckEdited = false;
937let checkEditInterval = 30000;
938let postingMessage = false;
939let fetchingMessages = false;
940let leavingTopic = false;
941let storageKey = "jvchat-premium-configuration";
942let ringBell = undefined;
943let configuration = {
944 default_reduced: false,
945 turbo_delay: 500,
946 max_width: 100,
947 play_sound: false,
948 night_mode: false,
949 load_images: false,
950 hide_mosaic: false,
951 sound: "data:audio/mp3;base64, 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KZ+4/J4hhPMbxk9uZlkvh6/jLtS6T9noZlleNzM1apGt+7CwkdfONPpLpNT0rivtF6d5JRejlihnmuTMIf3OWsl7KKKapZHQ3IBmnFlUchyHaOIzN+Syuo2SUVYPlNqCn+n4xG78SrR1lD/QTSyWlcKHJychjdSVSWMwDAM3EY7Rf/////4vzXlEEQJGHKsO7LsZ6U2J2PwPQf/////wNDUARKBH5g6tXeyKSKCcnRpY3DcYAAEAAAMEoLwyQhqjAOAaMLkNqt00SR7TGnEwMCcLkwGAN/0YLQF4kEeYBQBxgMgDf5zDxADC4wy5TXmbBm6JJimNECMEY0V/+ZUKbI8RFS75hwiwRgQhhQ3//mSGBgiSmIDAYQ8RaowYaYQy///4FAgIFCFcICDBAACE//uSxO0AK+Iu+xnsAAT7PuBXPaAAsrSBICGWxf///q8USLIIaMqLIIUF1n1hhHpwYQrd////69i6hehbyJiOCcatiVjSXVaU3Fpsebiy2x/////+jW3RSxAe2JliKcPPIim67osRh10V2u7ALDWcx1hv///////DiG7T48oOzeXsjTHhtmap3fdFMdYWZaysLddlhtaIrlpqFlMSp//////////3Hh1Qdf8HMPUvasytPttG5svXpBLO1LJlr//////7WYlRuzEotEYCfqZiTvX4k5UPRJynekxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7ksQ5A8AAAaQcAAAgAAA0gAAABKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo="
952};
953
954function saveConfig() {
955 let config = JSON.stringify(configuration);
956 localStorage.setItem(storageKey, config);
957}
958
959function loadConfig() {
960 let config = JSON.parse(localStorage.getItem(storageKey) || "{}");
961 for (let key in config) {
962 if (config.hasOwnProperty(key) && configuration.hasOwnProperty(key)) {
963 configuration[key] = config[key];
964 }
965 }
966}
967
968function getTopicLocked(elem) {
969 let lock = elem.getElementsByClassName("message-lock-topic")[0];
970 if (lock === undefined) {
971 return lock;
972 }
973 let reason = lock.getElementsByTagName("span")[0].textContent.trim();
974 return `Le topic a été vérouillé pour la raison suivante : "${reason}"`;
975}
976
977function getTopicError(elem) {
978 let error = elem.getElementsByClassName("img-erreur")[0];
979 if (error === undefined) {
980 return error;
981 }
982 return `Le topic présente une erreur: ${error.getAttribute("alt")}`;
983}
984
985function parseSondage(elem) {
986 let blocSondage = elem.getElementsByClassName("bloc-sondage")[0];
987 if (!blocSondage) {
988 return null;
989 }
990 let intitule = blocSondage.getElementsByClassName("intitule-sondage")[0].innerHTML;
991 let answered = !!(blocSondage.getElementsByClassName("result-pourcent")[0]);
992
993 let choix = blocSondage.getElementsByClassName("tab-choix")[0].getElementsByTagName("tr");
994 let results = [];
995
996 if (answered) {
997 for (let ch of choix) {
998 let pourcent = parseInt(ch.getElementsByClassName("pourcent")[0].innerHTML.trim().split(" ")[0]);
999 let response = ch.getElementsByClassName("reponse")[0].innerHTML.trim();
1000 results.push({response: response, pourcent: pourcent});
1001 }
1002 } else {
1003 for (let ch of choix) {
1004 let btnResponse = ch.getElementsByClassName("btn-sondage-reponse")[0];
1005 let response = btnResponse.innerHTML.trim();
1006 let sondageId = btnResponse.getAttribute("data-id-sondage");
1007 let responseId = btnResponse.getAttribute("data-id-reponse");
1008 results.push({response: response, sondageId: sondageId, responseId:responseId});
1009 }
1010 }
1011
1012 let votes = parseInt(blocSondage.getElementsByClassName("pied-result")[0].innerHTML.trim().split(" ")[0]);
1013 return {answered:answered, intitule: intitule, results:results, votes:votes};
1014}
1015
1016function tryCatch(func) {
1017 function wrapped(optArg) {
1018 try {
1019 func(optArg);
1020 } catch(err) {
1021 let message = `Une erreur est survenue dans JVChat Premium: '${err.message}' (line ${err.lineNumber})`;
1022 console.error(message);
1023 try {
1024 addAlertbox("danger", message);
1025 } catch(e) {
1026 alert(message);
1027 }
1028 }
1029 }
1030 return wrapped;
1031}
1032
1033function toggleTextarea() {
1034 isReduced = !isReduced;
1035 configuration["default_reduced"] = isReduced;
1036 saveConfig();
1037
1038 let isDown = isScrollDown();
1039 document.getElementById("bloc-formulaire-forum").getElementsByClassName("jv-editor-toolbar")[0].classList.toggle("jvchat-hide");
1040 document.getElementById("jvchat-enlarge").classList.toggle("jvchat-hide");
1041 document.getElementById("jvchat-reduce").classList.toggle("jvchat-hide");
1042 document.getElementById("jvchat-post").classList.toggle("jvchat-hide");
1043 document.getElementById("bloc-formulaire-forum").classList.toggle("jvchat-reduced");
1044
1045 setTextareaHeight();
1046
1047 if (isDown) {
1048 setScrollDown();
1049 }
1050}
1051
1052function parseURL(url) {
1053 let regex = /^(.*?)(\/\d+-\d+-\d+-)(\d+)(-\d+-\d+-\d+-)(.*?)(\.htm)(.*)$/i;
1054 let [_, domain, ids, page, nums, title, htm, anchor] = url.match(regex);
1055 return {domain: domain, ids: ids, page: page, nums: nums, title: title, htm: htm, anchor: anchor};
1056}
1057
1058function buildURL(dict) {
1059 return `${dict.domain}${dict.ids}${dict.page}${dict.nums}${dict.title}${dict.htm}${dict.anchor}`;
1060}
1061
1062function getForum(document) {
1063 let ariane = document.getElementsByClassName("bloc-fil-ariane-crumb-forum")[0];
1064 let links = ariane.getElementsByTagName("a");
1065 let title = "";
1066 let forumLink = "";
1067
1068 for (let i = links.length - 1; i >= 0; i--) {
1069 forumLink = links[i];
1070 title = forumLink.innerHTML.trim();
1071 if (title.startsWith("Forum ")) {
1072 break;
1073 }
1074 }
1075
1076 return {href: forumLink.getAttribute("href"), title: title.replace("Forum ", "")};
1077}
1078
1079function getLastPage(document) {
1080 let blocPages = document.getElementsByClassName("bloc-liste-num-page")[0];
1081 let spans = blocPages.getElementsByTagName("span");
1082 let lastPage = 1;
1083 for (let span of spans) {
1084 let page = parseInt(span.textContent.trim());
1085 if (!isNaN(page) && page > lastPage) {
1086 lastPage = page;
1087 }
1088 }
1089 return lastPage;
1090}
1091
1092function parseMessage(elem) {
1093 let conteneurs = elem.getElementsByClassName("conteneur-message");
1094 let conteneur = conteneurs[conteneurs.length - 1];
1095 let blacklisted = conteneurs[0].classList.contains("conteneur-message-blacklist");
1096 let author = conteneur.getElementsByClassName("bloc-pseudo-msg")[0].textContent.trim();
1097 let avatar = conteneur.getElementsByClassName("user-avatar-msg")[0];
1098 if (avatar !== undefined) {
1099 avatar = avatar.getAttribute("data-srcset");
1100 }
1101 let date = conteneur.getElementsByClassName("bloc-date-msg")[0].textContent.trim();
1102 let content = conteneur.getElementsByClassName("text-enrichi-forum")[0];
1103 let id = parseInt(elem.getAttribute("data-id"));
1104 let edited = elem.getElementsByClassName("info-edition-msg")[0];
1105 if (edited !== undefined) {
1106 let msgEdited = edited.textContent.trim();
1107 edited = msgEdited.match(/Message édité le .*? à (.*?) par/i)[1];
1108 }
1109 return {author: author, dateString: date, date: parseDate(date), avatar: avatar, edited: edited,
1110 id: id, content: content, blacklisted: blacklisted};
1111}
1112
1113function parseUserInfo(elem) {
1114 let accountMp = elem.getElementsByClassName("jv-nav-account-mp")[0];
1115 if (accountMp === undefined) {
1116 return {author: undefined, avatar: undefined, mp: undefined, notif: undefined};
1117 }
1118 let numberMp = accountMp.getElementsByClassName("jv-account-number-mp")[0];
1119 let accountNotif = elem.getElementsByClassName("jv-nav-account-notif")[0];
1120 let numberNotif = accountNotif.getElementsByClassName("jv-account-number-notif")[0];
1121 let accountUser = elem.getElementsByClassName("jv-nav-account-user")[0];
1122 let avatarBox = accountUser.getElementsByClassName("account-avatar-box")[0];
1123 let authorBox = accountUser.getElementsByClassName("account-pseudo")[0];
1124 let mp = parseInt(numberMp.getAttribute("data-val"));
1125 let notif = parseInt(numberNotif.getAttribute("data-val"));
1126 let avatar = avatarBox.style["background-image"].slice(5, -2).replace("/avatar-md/", "/avatar/");
1127 let author = authorBox.textContent.trim();
1128 return {author: author, avatar: avatar, mp: mp, notif: notif};
1129}
1130
1131function parseTopicInfo(elem) {
1132 let title = elem.querySelector("#bloc-title-forum").textContent.trim();
1133 let connected = parseInt(elem.getElementsByClassName("nb-connect-fofo")[0].textContent.trim());
1134 let lastPage = getLastPage(elem);
1135 let pageActive = elem.getElementsByClassName("page-active")[0];
1136 let page = 1;
1137 if (pageActive !== undefined) {
1138 page = parseInt(pageActive.textContent.trim());
1139 }
1140 return {title: title, connected: connected, lastPage: lastPage, page: page};
1141}
1142
1143function fixMessage(elem) {
1144 let jvcares = Array.from(elem.getElementsByClassName("JvCare"));
1145 for (let jvcare of jvcares) {
1146 let a = document.createElement("a");
1147 a.setAttribute("target", "_blank");
1148 a.setAttribute("href", jvCake(jvcare.getAttribute("class")));
1149 a.innerHTML = jvcare.innerHTML;
1150 jvcare.outerHTML = a.outerHTML;
1151 }
1152}
1153
1154function jvCake(cls) {
1155 let base16 = '0A12B34C56D78E9F', lien = '', s = cls.split(' ')[1];
1156 for (let i = 0; i < s.length; i += 2) {
1157 lien += String.fromCharCode(base16.indexOf(s.charAt(i)) * 16 + base16.indexOf(s.charAt(i + 1)));
1158 }
1159 return lien;
1160}
1161
1162function detectMosaic(elem) {
1163 let imagesShack = elem.getElementsByClassName("img-shack");
1164 if (imagesShack.length < 4) {
1165 return;
1166 }
1167 let mosaics = {};
1168 let regex = /^.+\/[0-9]+-[0-9]{1,2}-([a-z0-9]+)\.\w+$/i;
1169 for (let image of imagesShack) {
1170 let match = image.src.match(regex);
1171 if (!match) {
1172 continue;
1173 }
1174 [_, identifier] = match;
1175 if (mosaics.hasOwnProperty(identifier)) {
1176 mosaics[identifier].push(image);
1177 } else {
1178 mosaics[identifier] = [image]
1179 }
1180 }
1181 for (let identifier in mosaics) {
1182 let images = mosaics[identifier];
1183 if (images.length < 4) {
1184 continue;
1185 }
1186 images[0].parentNode.classList.add("jvchat-mosaic-root");
1187 images[0].classList.add("jvchat-mosaic");
1188 for (let image of images.slice(1)) {
1189 image.parentNode.classList.add("jvchat-mosaic");
1190 }
1191 }
1192}
1193
1194function improveImages(elem) {
1195 let imagesShack = elem.getElementsByClassName("img-shack");
1196 for (let image of imagesShack) {
1197 let src = image.src;
1198 let parent = image.parentNode;
1199 let extension = parent.href.split(".").pop();
1200 let direct = src.replace(/(.*?)\/minis\/(.*)\.\w+/i, "$1/fichiers/$2." + extension);
1201 image.setAttribute("data-src-mini", src);
1202 image.setAttribute("data-src-direct", direct);
1203 image.classList.add("jvchat-loadable-image");
1204 parent.href = direct;
1205 if (extension.toUpperCase() === "GIF") {
1206 image.src = direct;
1207 image.classList.remove("jvchat-loadable-image");
1208 } else if (configuration["load_images"]) {
1209 image.src = direct;
1210 }
1211 src = image.src;
1212 image.setAttribute("onerror", `this.onerror=null;this.src=this.getAttribute("data-src-direct");this.classList.remove("jvchat-loadable-image");`);
1213 }
1214}
1215
1216function clearPage(document) {
1217 let buttons = `
1218 <div id="jvchat-buttons-main" class='jvchat-buttons'>
1219 <button id='jvchat-post' tabindex="4" type="button" class='jvchat-hide jvchat-button-top icon-reply' title="Envoyer le message"></button>
1220 <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>
1221 <button id='jvchat-enlarge' tabindex="4" type="button" class='jvchat-button-solo icon-arrow-up-entypo' title="Agrandir la zone de texte"></button>
1222 <div>`;
1223
1224 document.head.insertAdjacentHTML("beforeend", CSS);
1225
1226 let previsu = document.getElementById("bloc-formulaire-forum").getElementsByClassName("previsu-editor")[0];
1227 if (previsu) {
1228 previsu.parentElement.removeChild(previsu);
1229 }
1230
1231 let messageTopic = document.getElementById("message_topic");
1232 if (messageTopic) {
1233 messageTopic.classList.add("jvchat-textarea");
1234 messageTopic.setAttribute("placeholder", "Hop hop hop, le message ne va pas s'écrire tout seul !");
1235 messageTopic.insertAdjacentHTML("afterend", buttons);
1236 messageTopic.addEventListener("keydown", tryCatch(postMessageIfEnter));
1237 document.getElementById("jvchat-post").addEventListener("click", tryCatch(postMessage));
1238 document.getElementById("jvchat-enlarge").addEventListener("click", tryCatch(toggleTextarea));
1239 document.getElementById("jvchat-reduce").addEventListener("click", tryCatch(toggleTextarea));
1240 }
1241 document.getElementsByClassName("conteneur-messages-pagi")[0].insertAdjacentHTML("afterbegin", "<div id='jvchat-main'><hr class='jvchat-ruler'></div>");
1242 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>");
1243
1244 document.getElementById("content-context").insertAdjacentHTML("afterbegin", PANEL);
1245 document.getElementById("content-context").insertAdjacentHTML("beforeend", "<div id='jvchat-right-padding'></div>");
1246
1247 document.getElementById("content").classList.add("jvchat-root");
1248 document.getElementById("bloc-formulaire-forum").classList.add("jvchat-reduced");
1249 document.getElementById("bloc-formulaire-forum").classList.add("jvchat-hide");
1250
1251 let toolbar = document.getElementById("bloc-formulaire-forum").getElementsByClassName("jv-editor-toolbar")[0];
1252 if (toolbar) {
1253 toolbar.classList.add("jvchat-hide");
1254 }
1255
1256 document.getElementById("jvchat-main").addEventListener("click", tryCatch(dontScrollOnExpand));
1257
1258 document.getElementById("jvchat-alerts").addEventListener("click", tryCatch(closeAlert));
1259
1260 document.getElementById("jvchat-leftbar-reduce").addEventListener("click", tryCatch(toggleSidebar));
1261 document.getElementById("jvchat-leftbar-extend").addEventListener("click", tryCatch(toggleSidebar));
1262 document.getElementById("jvchat-leftbar-config-open").addEventListener("click", tryCatch(toggleConfig));
1263 document.getElementById("jvchat-leftbar-config-close").addEventListener("click", tryCatch(toggleConfig));
1264
1265 document.getElementById("jvchat-turbo-checkbox").addEventListener("change", tryCatch(toggleTurbo));
1266
1267 document.getElementById("jvchat-play-sound-checkbox").checked = configuration["play_sound"];
1268 document.getElementById("jvchat-play-sound-checkbox").addEventListener("change", tryCatch(togglePlaySoundOption));
1269
1270 document.getElementById("jvchat-night-mode-checkbox").checked = configuration["night_mode"];
1271 document.getElementById("jvchat-night-mode-checkbox").addEventListener("change", tryCatch(toggleNightModeOption));
1272 if (configuration["night_mode"]) {
1273 document.getElementById("content").classList.add("jvchat-night-mode");
1274 }
1275
1276 document.getElementById("jvchat-hide-mosaic-checkbox").checked = configuration["hide_mosaic"];
1277 document.getElementById("jvchat-hide-mosaic-checkbox").addEventListener("change", tryCatch(toggleHideMosaicOption));
1278 if (configuration["hide_mosaic"]) {
1279 document.getElementById("jvchat-main").classList.add("jvchat-hide-mosaics");
1280 }
1281
1282 document.getElementById("jvchat-load-images-checkbox").checked = configuration["load_images"];
1283 document.getElementById("jvchat-load-images-checkbox").addEventListener("change", tryCatch(toggleLoadImagesOption));
1284
1285 document.getElementById("jvchat-turbo-delay-range").value = configuration["turbo_delay"];
1286 document.getElementById("jvchat-turbo-delay-span").innerHTML = `${configuration["turbo_delay"]} ms`;
1287 document.getElementById("jvchat-turbo-delay-range").addEventListener("input", tryCatch(changeTurboDelayOption));
1288
1289 document.getElementById("jvchat-max-width-range").value = configuration["max_width"];
1290 document.getElementById("jvchat-max-width-span").innerHTML = `${configuration["max_width"]} %`;
1291 document.getElementById("jvchat-max-width-range").addEventListener("input", tryCatch(changeMaxWidthOption));
1292 adjustMaxWidth(configuration["max_width"]);
1293
1294 let favs = Array.from(document.querySelectorAll("link[rel='icon'], link[rel='shortcut icon']"));
1295 for (let fav of favs) {
1296 fav.parentElement.removeChild(fav);
1297 }
1298 setFavicon("");
1299
1300 document.addEventListener("visibilitychange", function() {
1301 let hidden = document.hidden;
1302 if (hidden) {
1303 let newHr = document.getElementById("jvchat-ruler-new");
1304 if (newHr) {
1305 newHr.removeAttribute("id");
1306 }
1307 nbNewMessage = 0;
1308 } else if (!isError && !isLocked) {
1309 setFavicon("");
1310 }
1311 });
1312}
1313
1314function toggleSidebar(event) {
1315 let isDown = isScrollDown();
1316 document.getElementById("jvchat-leftbar-extend").classList.toggle("jvchat-hide");
1317 document.getElementById("jvchat-leftbar-reduce").classList.toggle("jvchat-hide");
1318 document.getElementById("jvchat-leftbar-config").classList.toggle("jvchat-hide");
1319 document.getElementById("jvchat-leftbar").classList.toggle("jvchat-leftbar-reduced");
1320 if (isDown) {
1321 setScrollDown();
1322 }
1323}
1324
1325function toggleConfig(event) {
1326 document.getElementById("jvchat-leftbar-config-open").classList.toggle("jvchat-hide");
1327 document.getElementById("jvchat-leftbar-config-close").classList.toggle("jvchat-hide");
1328 document.getElementById("jvchat-info").classList.toggle("jvchat-hide");
1329 document.getElementById("jvchat-config").classList.toggle("jvchat-hide");
1330}
1331
1332function toggleTurbo(event) {
1333 let checked = document.getElementById("jvchat-turbo-checkbox").checked;
1334 updateIntervalIdx = 0;
1335 if (!checked) {
1336 turboActivated = false;
1337 } else {
1338 turboActivated = true;
1339 // If waiting for next update, restart it immedtialty, otherwise just wait for the HTTP request to end
1340 if (!fetchingMessages) {
1341 clearTimeout(currentTimeoutId);
1342 updateMessages(currentFetchedPage, true);
1343 }
1344 }
1345}
1346
1347function togglePlaySoundOption(event) {
1348 let checked = document.getElementById("jvchat-play-sound-checkbox").checked;
1349 configuration["play_sound"] = checked;
1350 saveConfig();
1351}
1352
1353function toggleNightModeOption(event) {
1354 let checked = document.getElementById("jvchat-night-mode-checkbox").checked;
1355 configuration["night_mode"] = checked;
1356 saveConfig();
1357 document.getElementById("content").classList.toggle("jvchat-night-mode");
1358}
1359
1360function toggleHideMosaicOption(event) {
1361 let checked = document.getElementById("jvchat-hide-mosaic-checkbox").checked;
1362 configuration["hide_mosaic"] = checked;
1363 saveConfig();
1364 let isDown = isScrollDown();
1365 document.getElementById("jvchat-main").classList.toggle("jvchat-hide-mosaics");
1366 if (isDown) {
1367 setScrollDown();
1368 }
1369}
1370
1371function toggleLoadImagesOption(event) {
1372 let checked = document.getElementById("jvchat-load-images-checkbox").checked;
1373 configuration["load_images"] = checked;
1374 saveConfig();
1375 for (let image of document.getElementsByClassName("jvchat-loadable-image")) {
1376 image.src = image.getAttribute(checked ? "data-src-direct" : "data-src-mini");
1377 }
1378}
1379
1380function changeTurboDelayOption(event) {
1381 let ms = document.getElementById("jvchat-turbo-delay-range").value;
1382 document.getElementById("jvchat-turbo-delay-span").innerHTML = `${ms} ms`;
1383 configuration["turbo_delay"] = parseInt(ms);
1384 saveConfig();
1385}
1386
1387function changeMaxWidthOption(event) {
1388 let maxWidth = parseInt(document.getElementById("jvchat-max-width-range").value);
1389 document.getElementById("jvchat-max-width-span").innerHTML = `${maxWidth} %`;
1390 configuration["max_width"] = maxWidth;
1391 saveConfig();
1392 adjustMaxWidth(maxWidth);
1393}
1394
1395function adjustMaxWidth(maxWidth) {
1396 document.getElementById("page-messages-forum").style["flex-grow"] = maxWidth;
1397 document.getElementById("jvchat-right-padding").style["flex-grow"] = 100 - maxWidth;
1398}
1399
1400function closeAlert(event) {
1401 let target = event.target;
1402 if (!target) {
1403 return;
1404 }
1405 if (target.classList.contains("jvchat-alert-close")) {
1406 let parent = target.parentElement;
1407 parent.parentElement.removeChild(parent);
1408 }
1409}
1410
1411function postMessage() {
1412 if (freshForm === undefined) {
1413 addAlertbox("danger", "Impossible de poster le message, aucun formulaire trouvé");
1414 return;
1415 }
1416
1417 let textarea = document.getElementById("message_topic");
1418
1419 let formData = serializeForm(freshForm);
1420 formData["message_topic"] = textarea.value;
1421 let formulaire = document.getElementById("bloc-formulaire-forum");
1422
1423 formulaire.classList.add("jvchat-disabled-form");
1424 textarea.setAttribute("disabled", "true");
1425
1426 function onSuccess(res) {
1427 formulaire.classList.remove("jvchat-disabled-form");
1428 textarea.removeAttribute("disabled");
1429 let alert = parsePage(res).alert;
1430 if (!alert) {
1431 textarea.value = "";
1432 }
1433 setTextareaHeight();
1434 setScrollDown();
1435 postingMessage = false;
1436 }
1437
1438 function onError(err) {
1439 addAlertbox("danger", err);
1440 formulaire.classList.remove("jvchat-disabled-form");
1441 textarea.removeAttribute("disabled");
1442 postingMessage = false;
1443 }
1444
1445 function onTimeout(err) {
1446 addAlertbox("warning", err);
1447 formulaire.classList.remove("jvchat-disabled-form");
1448 textarea.removeAttribute("disabled");
1449 postingMessage = false;
1450 }
1451
1452 let timeout = 20000;
1453 if (turboActivated) {
1454 timeout = 5000;
1455 }
1456
1457 postingMessage = true;
1458 request("POST", document.URL, onSuccess, onError, onTimeout, makeFormData(formData), false, timeout);
1459}
1460
1461function editMessage(bloc) {
1462 let textarea = bloc.getElementsByClassName("jvchat-edition-textarea")[0];
1463
1464 let blocEdition = bloc.getElementsByClassName("jvchat-edition")[0];
1465 let formData = JSON.parse(blocEdition.getAttribute("data-form"));
1466 formData["message_topic"] = textarea.value;
1467 formData["id_message"] = bloc.getAttribute("jvchat-id");
1468 formData["ajax_hash"] = freshHash;
1469 formData["action"] = "post";
1470 let edition = bloc.getElementsByClassName("jvchat-edition")[0];
1471
1472 edition.classList.add("jvchat-disabled-form");
1473 textarea.setAttribute("disabled", "true");
1474
1475 function onSuccess(res) {
1476 edition.classList.remove("jvchat-disabled-form");
1477 if (res['reset_form']) {
1478 let reset = document.createElement("html");
1479 reset.innerHTML = res["hidden_reset"];
1480 let resetData = serializeForm(reset);
1481 for (let key in resetData) {
1482 formData[key] = resetData[key];
1483 }
1484 blocEdition.setAttribute("data-form", JSON.stringify(formData));
1485 }
1486
1487 textarea.removeAttribute("disabled");
1488 if (res.erreur.length > 0) {
1489 for (let err of res.erreur) {
1490 addAlertbox("danger", err);
1491 }
1492 return;
1493 }
1494 let dom = document.createElement("html");
1495 dom.innerHTML = res["html"];
1496 let message = getMessages(dom)[0];
1497 addMessages([message], true);
1498 }
1499
1500 function onError(err) {
1501 addAlertbox("danger", err);
1502 edition.classList.remove("jvchat-disabled-form");
1503 textarea.removeAttribute("disabled");
1504 }
1505
1506 function onTimeout(err) {
1507 addAlertbox("warning", err);
1508 edition.classList.remove("jvchat-disabled-form");
1509 textarea.removeAttribute("disabled");
1510 }
1511
1512 let url = "http://www.jeuxvideo.com/forums/ajax_edit_message.php";
1513
1514 request("POST", url, onSuccess, onError, onTimeout, makeFormData(formData), true, 20000);
1515}
1516
1517function requestEdit(bloc) {
1518 if (!bloc.getElementsByClassName("jvchat-edition")[0].classList.contains("jvchat-hide")) {
1519 return;
1520 }
1521
1522 let contentClasses = bloc.getElementsByClassName("jvchat-content")[0].classList;
1523 contentClasses.add("disabled-content");
1524
1525 function onSuccess(res) {
1526 contentClasses.remove("disabled-content");
1527 if (res.erreur.length > 0) {
1528 for (let err of res.erreur) {
1529 addAlertbox("danger", err);
1530 }
1531 return;
1532 }
1533 let dom = document.createElement("html");
1534 dom.innerHTML = res["html"];
1535 let textarea = dom.getElementsByTagName("textarea")[0]
1536 let txt = textarea.value;
1537 textarea.parentElement.removeChild(textarea);
1538 let form = dom.getElementsByTagName("form")[0];
1539 let formData = serializeForm(form);
1540 let editionBloc = bloc.getElementsByClassName("jvchat-edition")[0];
1541 editionBloc.setAttribute("data-form", JSON.stringify(formData));
1542 let height = computeHeight(countLines(txt));
1543 let isDown = isScrollDown();
1544 bloc.getElementsByClassName("jvchat-edition-textarea")[0].value = txt;
1545 bloc.getElementsByClassName("jvchat-edition-textarea")[0].style["height"] = `${height}rem`;
1546 bloc.getElementsByClassName("jvchat-content")[0].classList.add("jvchat-hide");
1547 editionBloc.classList.remove("jvchat-hide");
1548 if (isDown) {
1549 setScrollDown();
1550 }
1551 }
1552
1553 function onError(err) {
1554 addAlertbox("danger", err);
1555 contentClasses.remove("disabled-content");
1556 }
1557
1558 function onTimeout(err) {
1559 addAlertbox("warning", err);
1560 contentClasses.remove("disabled-content");
1561 }
1562
1563 let id = bloc.getAttribute("jvchat-id");
1564 let url = `http://www.jeuxvideo.com/forums/ajax_edit_message.php?id_message=${id}&ajax_hash=${freshHash}&action=get`;
1565 request("GET", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1566}
1567
1568function requestDelete(bloc) {
1569
1570 if (!bloc.getElementsByClassName("jvchat-edition")[0].classList.contains("jvchat-hide")) {
1571 return;
1572 }
1573
1574 let contentClasses = bloc.getElementsByClassName("jvchat-content")[0].classList;
1575 contentClasses.add("disabled-content");
1576
1577 function onSuccess(res) {
1578 contentClasses.remove("disabled-content");
1579 if (res.erreur.length > 0) {
1580 for (let err of res.erreur) {
1581 addAlertbox("danger", err);
1582 }
1583 return;
1584 }
1585 let dom = document.createElement("html");
1586 dom.innerHTML = res["html"];
1587 let textarea = dom.getElementsByTagName("textarea")[0]
1588 let txt = textarea.value;
1589 textarea.parentElement.removeChild(textarea);
1590 let form = dom.getElementsByTagName("form")[0];
1591 let formData = serializeForm(form);
1592 let editionBloc = bloc.getElementsByClassName("jvchat-edition")[0];
1593 editionBloc.setAttribute("data-form", JSON.stringify(formData));
1594 let height = computeHeight(countLines(txt));
1595 let isDown = isScrollDown();
1596 bloc.getElementsByClassName("jvchat-edition-textarea")[0].value = txt;
1597 bloc.getElementsByClassName("jvchat-edition-textarea")[0].style["height"] = `${height}rem`;
1598 bloc.getElementsByClassName("jvchat-content")[0].classList.add("jvchat-hide");
1599 editionBloc.classList.remove("jvchat-hide");
1600 if (isDown) {
1601 setScrollDown();
1602 }
1603 }
1604
1605 function onError(err) {
1606 addAlertbox("danger", err);
1607 contentClasses.remove("disabled-content");
1608 }
1609
1610 function onTimeout(err) {
1611 addAlertbox("warning", err);
1612 contentClasses.remove("disabled-content");
1613 }
1614
1615 let delHash = getHash(document);
1616 let id = bloc.getAttribute("jvchat-id");
1617 let url = `http://www.jeuxvideo.com/forums/modal_del_message.php?type=delete&ajax_hash=${delHash}&tab_message[]=${id}`;
1618 request("GET", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1619}
1620
1621function countLines(text) {
1622 return text.split(/\r|\r\n|\n/).length;
1623}
1624
1625function computeHeight(lines) {
1626 return 1 * lines + 0.6;
1627}
1628
1629function setTextareaHeight(plusOne) {
1630 let textarea = document.getElementById("message_topic");
1631 if (!isReduced) {
1632 textarea.style["height"] = "";
1633 return;
1634 }
1635 plusOne = !!plusOne;
1636 let lines = countLines(textarea.value);
1637
1638 if (!plusOne && lines === 1) {
1639 textarea.style["height"] = "";
1640 return;
1641 }
1642
1643 if (plusOne) {
1644 lines += 1;
1645 }
1646
1647 let height = computeHeight(lines);
1648 textarea.style["height"] = `${height}rem`;
1649}
1650
1651function postMessageIfEnter(event) {
1652 if (isReduced && (event.which == 13 || event.keyCode == 13)) {
1653 if (event.shiftKey) {
1654 let isDown = isScrollDown();
1655 setTextareaHeight(true);
1656 if (isDown) {
1657 setScrollDown();
1658 }
1659 } else {
1660 event.preventDefault();
1661 postMessage();
1662 }
1663 }
1664}
1665
1666function serializeForm(form) {
1667 // Useless actually, just use new FormData(form)
1668 let dict = {};
1669
1670 for (let select of form.getElementsByTagName("select")) {
1671 dict[select.name] = select.querySelector("option[selected]").value;
1672 }
1673
1674 for (let input of form.getElementsByTagName("input")) {
1675 dict[input.name] = input.value;
1676 }
1677
1678 for (let textarea of form.getElementsByTagName("textarea")) {
1679 dict[textarea.name] = textarea.value;
1680 }
1681
1682 return dict;
1683}
1684
1685function makeFormData(dict) {
1686 var formData = new FormData();
1687 for (let key in dict) {
1688 formData.append(key, dict[key]);
1689 }
1690 return formData;
1691}
1692
1693function getMessages(document) {
1694 let blocMessages = document.getElementsByClassName("bloc-message-forum");
1695 let messages = [];
1696 for (let bloc of blocMessages) {
1697 messages.push(parseMessage(bloc));
1698 }
1699 return messages;
1700}
1701
1702function formatDate(date) {
1703 let now = new Date();
1704 let day = date.getDate();
1705 let month = date.getMonth();
1706 let year = date.getFullYear();
1707 if (now.getDate() === day && now.getMonth() === month && now.getFullYear() === year) {
1708 return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}`;
1709 } else {
1710 return `${day.toString().padStart(2, "0")}/${(month + 1).toString().padStart(2, "0")}/${year}`;
1711 }
1712}
1713
1714function makeMessage(message) {
1715 let content = message.content;
1716 fixMessage(content);
1717 detectMosaic(content);
1718 improveImages(content);
1719 let id = message.id;
1720 let avatar = message.avatar;
1721 let toQuoteDate = message.dateString;
1722 let titleDate = message.dateString;
1723 let textDate = formatDate(message.date);
1724 if (message.edited !== undefined) {
1725 textDate += "*";
1726 titleDate += ` (édité à ${message.edited})`;
1727 }
1728 let exists = avatar !== undefined;
1729 let author = exists ? message.author : `<i>${message.author}</i>`;
1730 let authorHref = exists ? `href="http://www.jeuxvideo.com/profil/${author.toLowerCase()}?mode=infos"` : "";
1731 let authorTitle = exists ? `title="Ouvrir le profil de ${author}"` : "";
1732 let authorAvatarHidden = exists ? "": "class='jvchat-hide-visibility'";
1733 let editionSpan = '<span class="jvchat-edit jvchat-picto picto-msg-crayon" title="Modifier"></span>';
1734 let deletionSpan = '<span class="jvchat-delete jvchat-picto picto-msg-croix" title="Supprimer"></span>';
1735 let deletion = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : deletionSpan;
1736 let edition = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : editionSpan;
1737 let html =
1738 `<div class="jvchat-bloc-message">
1739 <div class="jvchat-message" jvchat-id=${id}>
1740 <div>
1741 <a ${authorAvatarHidden} ${authorHref} target="_blank" ${authorTitle}>
1742 <div class="jvchat-bloc-avatar jvchat-rounded" style="background-image: url(${avatar})"></div>
1743 </a>
1744 </div>
1745 <div class="jvchat-bloc-author-content">
1746 <div class="jvchat-toolbar">
1747 <h5 class="jvchat-author">${author}</h5>
1748 <div class="jvchat-tooltip">
1749 ${edition}
1750 ${deletion}
1751 <span class="jvchat-picto jvchat-quote picto-msg-quote" title="Citer"></span>
1752 <small class="jvchat-date" to-quote="${toQuoteDate}" title="${titleDate}">${textDate}</small>
1753 </div>
1754 </div>
1755 <div class="jvchat-content">${content.outerHTML}</div>
1756 <div class="jvchat-edition jvchat-hide">
1757 <textarea class="jvchat-edition-textarea jvchat-textarea"></textarea>
1758 <div class="jvchat-buttons">
1759 <button tabindex="0" type="button" class='jvchat-edition-check icon-check-jv jvchat-button-top' title="Valider la modification"></button>
1760 <button tabindex="0" type="button" class='jvchat-edition-cancel icon-cancel-circle jvchat-button-bottom' title="Annuler la modification"></button>
1761 </div>
1762 </div>
1763 </div>
1764 </div>
1765 <hr class="jvchat-ruler">
1766 </div>`;
1767 return html;
1768}
1769
1770function parseDate(string) {
1771 let [date, time] = string.toLowerCase().split("à");
1772 let [day, month, year] = date.trim().split(" ");
1773 let [hour, minute, second] = time.trim().split(":");
1774 let monthIndex = ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"].indexOf(month.trim().toLowerCase());
1775 return new Date(parseInt(year), monthIndex, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second));
1776}
1777
1778function addMessages(messages, editing) {
1779 editing = !!editing;
1780 let main = document.getElementById("jvchat-main");
1781 let hasNewMessages = false;
1782 let init = true;
1783 let toInsert = "";
1784 let newMessagesIds = [];
1785 for (let message of messages) {
1786 let date = message.date;
1787 let id = message.id;
1788
1789 if (init === true && !editing) {
1790 init = false;
1791 let now = new Date();
1792 let delta = now - date;
1793 if (delta > 5 * 60 * 1000 + checkEditInterval) {
1794 shouldCheckEdited = false;
1795 } else {
1796 shouldCheckEdited = true;
1797 }
1798 }
1799
1800 if (message.blacklisted) {
1801 continue;
1802 }
1803
1804 if (firstMessageId === undefined) {
1805 firstMessageId = id;
1806 firstMessageDate = date;
1807 }
1808 let referenced = allMessagesId.hasOwnProperty(id);
1809 let edited = message.edited;
1810
1811 // 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
1812 if ((id < firstMessageId && date < firstMessageDate) || (referenced && allMessagesId[id] === edited)) {
1813 continue;
1814 }
1815
1816 let newBloc = makeMessage(message);
1817 allMessagesId[id] = edited;
1818
1819 if (referenced) {
1820 let selector = `.jvchat-message[jvchat-id="${id}"]`;
1821 let oldBloc = main.querySelector(selector).closest(".jvchat-bloc-message");
1822 let isDown = isScrollDown();
1823 oldBloc.outerHTML = newBloc;
1824 if (isDown) {
1825 setScrollDown();
1826 }
1827 continue;
1828 }
1829
1830 hasNewMessages = true;
1831 if (nbNewMessage === 0 && document.hidden) {
1832 let hrs = document.getElementsByClassName("jvchat-ruler");
1833 let lastHr = hrs[hrs.length - 1];
1834 lastHr.setAttribute("id", "jvchat-ruler-new");
1835 }
1836
1837 toInsert += newBloc;
1838 newMessagesIds.push(id);
1839 nbNewMessage++;
1840 }
1841
1842 if (toInsert !== "") {
1843 let isDown = isScrollDown();
1844 main.insertAdjacentHTML("beforeend", toInsert);
1845 if (isDown) {
1846 setScrollDown();
1847 }
1848 }
1849
1850 if (editing) {
1851 return;
1852 }
1853
1854 if (isScrollDown()) {
1855 let blocMessages = main.getElementsByClassName("jvchat-bloc-message");
1856 let nb = blocMessages.length;
1857 if (nb > 100) {
1858 for (let i = 0; i < nb - 100; i++) {
1859 main.removeChild(blocMessages[0]);
1860 }
1861 setScrollDown();
1862 }
1863 }
1864
1865 if (hasNewMessages) {
1866 if (!turboActivated) {
1867 decreaseUpdateInterval();
1868 }
1869 if (document.hidden) {
1870 setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage);
1871 if (configuration["play_sound"]) {
1872 ringBell.pause();
1873 ringBell.currentTime = 0;
1874 ringBell.play();
1875 }
1876 }
1877 for (let newMessageId of newMessagesIds) {
1878 let event = new CustomEvent('jvchat:newmessage', { 'detail': { id: newMessageId } });
1879 dispatchEvent(event);
1880 }
1881 } else {
1882 if (!turboActivated) {
1883 increaseUpdateInterval();
1884 }
1885 }
1886}
1887
1888function submitSondageAnswer(event) {
1889 let target = event.target;
1890 if (!target) {
1891 return;
1892 }
1893 if (target.classList.contains("click-sondage")) {
1894 let reponseNum = parseInt(target.getAttribute("sondage-reponse-num"));
1895 let sondageId = sondageChoices[reponseNum]["sondageId"];
1896 let reponseId = sondageChoices[reponseNum]["responseId"];
1897 let topicId = urlToFetch["ids"].split("-")[2];
1898 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}`;
1899
1900 function onSuccess(res) {
1901 if (res.erreur.length > 0) {
1902 for (let err of res.erreur) {
1903 addAlertbox("danger", err);
1904 }
1905 return;
1906 }
1907 let dom = document.createElement("html");
1908 dom.innerHTML = res["html"];
1909
1910 let sondage = parseSondage(dom);
1911 if (!sondage) {
1912 addAlertbox("warning", "Erreur lors de la récupération du sondage");
1913 return;
1914 }
1915
1916 setSondage(sondage);
1917 }
1918
1919 function onError(err) {
1920 addAlertbox("danger", err);
1921 }
1922
1923 function onTimeout(err) {
1924 addAlertbox("warning", err);
1925 }
1926
1927 request("POST", url, onSuccess, onError, onTimeout, undefined, true, 5000);
1928 }
1929}
1930
1931function setSondage(sondage) {
1932 let choix = document.getElementById("jvchat-sondage-choix");
1933
1934 if (sondage["answered"]) {
1935 choix.removeEventListener("click", submitSondageAnswer);
1936 choix.classList.remove("notanswered");
1937 } else {
1938 if (!sondageChoices) {
1939 sondageChoices = sondage["results"];
1940 }
1941 choix.addEventListener("click", submitSondageAnswer);
1942 choix.classList.add("notanswered");
1943 }
1944
1945 if (!choix.firstChild) {
1946 document.getElementById("jvchat-sondage-intitule").innerHTML = sondage["intitule"];
1947 let results = sondage["results"];
1948 for (let i = 0; i < results.length; i++) {
1949 let res = results[i];
1950 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>`;
1951 choix.insertAdjacentHTML("beforeend", tr);
1952 }
1953 } else {
1954 let trs = choix.getElementsByClassName("result-pourcent");
1955 for (let i = 0; i < trs.length; i++) {
1956 let res = sondage["results"][i];
1957 let tr = trs[i];
1958 tr.getElementsByClassName("pourcent")[0].innerHTML = `${res["pourcent"]} %`;
1959 tr.getElementsByTagName("span")[0].style["width"] = `${res["pourcent"]}%`;
1960 }
1961 }
1962
1963 document.getElementById("jvchat-sondage-votes").innerHTML = `(${sondage["votes"]} votes)`;
1964}
1965
1966function setUser(document, user) {
1967 let isConnected = (user.author !== undefined);
1968
1969 if (isConnected) {
1970 if (user.author !== currentUser.author) {
1971 let pseudo = document.getElementById("jvchat-user-pseudo");
1972 pseudo.innerHTML = user.author;
1973 let avatarLink = document.getElementById("jvchat-user-avatar-link");
1974 let notifLink = document.getElementById("jvchat-user-notif-link");
1975 avatarLink.setAttribute("href", `http://www.jeuxvideo.com/profil/${user.author.toLowerCase()}?mode=infos`);
1976 notifLink.setAttribute("href", `http://www.jeuxvideo.com/profil/${user.author.toLowerCase()}?mode=abonnements`);
1977 }
1978
1979 if (user.avatar !== currentUser.avatar) {
1980 let avatar = document.getElementById("jvchat-user-avatar");
1981 avatar.style["background-image"] = `url("${user.avatar}")`;
1982 }
1983
1984 if (user.mp !== currentUser.mp) {
1985 let mp = document.getElementById("jvchat-user-mp");
1986 mp.setAttribute("data-val", user.mp);
1987 if (user.mp > 0) {
1988 mp.classList.add("has-notif");
1989 } else {
1990 mp.classList.remove("has-notif");
1991 }
1992 }
1993
1994 if (user.notif !== currentUser.notif) {
1995 let notif = document.getElementById("jvchat-user-notif");
1996 notif.setAttribute("data-val", user.notif);
1997 if (user.notif > 0) {
1998 notif.classList.add("has-notif");
1999 } else {
2000 notif.classList.remove("has-notif");
2001 }
2002 }
2003 }
2004
2005 if ((userConnected === undefined && isConnected) || (userConnected !== undefined && isConnected !== userConnected)) {
2006 document.getElementById("jvchat-profil").classList.toggle("jvchat-hide");
2007 let isDown = isScrollDown();
2008 document.getElementById("bloc-formulaire-forum").classList.toggle("jvchat-hide");
2009 if (isDown) {
2010 setScrollDown();
2011 }
2012 }
2013
2014 if (userConnected !== undefined) {
2015 if (isConnected && !userConnected) {
2016 addAlertbox("success", "Vous êtes désormais connecté");
2017 } else if (!isConnected && userConnected) {
2018 addAlertbox("warning", "Vous avez été déconnecté");
2019 }
2020 }
2021
2022 userConnected = isConnected;
2023 currentUser = user;
2024}
2025
2026function setTopicTitle(document, topicTitle) {
2027 if (topicTitle !== currentTopicTitle) {
2028 currentTopicTitle = topicTitle;
2029 document.getElementById("jvchat-topic-title").innerHTML = topicTitle;
2030 }
2031}
2032
2033function setTopicNbConnected(document, nbConnected) {
2034 let txt = `${nbConnected} connectés`;
2035 if (!(nbConnected > 1)) {
2036 if (nbConnected === undefined) {
2037 txt = "? connectés";
2038 } else {
2039 txt = txt.slice(0, -1);
2040 }
2041 }
2042 document.getElementById("jvchat-topic-nb-connected").innerHTML = txt;
2043}
2044
2045function setTopicNbMessages(document, nbMessages) {
2046 let txt = `${nbMessages} messages`;
2047 if (!(nbMessages > 1)) {
2048 if (nbMessages === undefined) {
2049 txt = "? messages";
2050 } else {
2051 txt = txt.slice(0, -1);
2052 }
2053 }
2054 document.getElementById("jvchat-topic-nb-messages").innerHTML = txt;
2055}
2056
2057function triggerJVChat() {
2058 // TamperMonkey / Chrome bug: https://github.com/Tampermonkey/tampermonkey/issues/705#issuecomment-493895776
2059 if (window) {
2060 if (window.clearTimeout) {
2061 window.clearTimeout = window.clearTimeout.bind(window);
2062 }
2063 if (window.clearInterval) {
2064 window.clearInterval = window.clearInterval.bind(window);
2065 }
2066 if (window.setTimeout) {
2067 window.setTimeout = window.setTimeout.bind(window);
2068 }
2069 if (window.setInterval) {
2070 window.setInterval = window.setInterval.bind(window);
2071 }
2072 window.onbeforeunload = function(event) {
2073 leavingTopic = true;
2074 }
2075 }
2076
2077 let topicUrl = document.URL;
2078 let topic = parseTopicInfo(document);
2079 let user = parseUserInfo(document);
2080 let sondage = parseSondage(document);
2081
2082 urlToFetch = parseURL(topicUrl);
2083 urlToFetch.page = 1;
2084 urlToFetch.anchor = "";
2085
2086 urlToCheckEdit = parseURL(topicUrl);
2087 urlToCheckEdit.page = 1;
2088 urlToCheckEdit.anchor = "";
2089
2090 loadConfig();
2091 ringBell = new Audio(configuration["sound"]);
2092 clearPage(document);
2093
2094 setUser(document, user);
2095 setTopicTitle(document, topic.title);
2096 setTopicNbMessages(document, undefined);
2097 setTopicNbConnected(document, topic.connected);
2098
2099 if (sondage) {
2100 document.getElementById("jvchat-sondage").classList.remove("jvchat-hide")
2101 setSondage(sondage);
2102 }
2103
2104 document.getElementById("jvchat-topic-title").setAttribute("href", buildURL(urlToFetch));
2105
2106 let forum = getForum(document);
2107 let forumSide = document.getElementById("jvchat-forum-title");
2108 forumSide.setAttribute("href", forum.href);
2109 forumSide.innerHTML = forum.title;
2110
2111 let defaultReduced = configuration["default_reduced"];
2112 let messageTopic = document.getElementById("message_topic");
2113
2114 if (defaultReduced === false || (messageTopic && messageTopic.value !== "")) {
2115 toggleTextarea();
2116 }
2117
2118 let event = new CustomEvent('jvchat:activation');
2119 dispatchEvent(event);
2120
2121 let page = topic.lastPage > 1 ? topic.lastPage - 1 : topic.lastPage;
2122 updateMessages(page, true);
2123
2124 setInterval(checkEdited, checkEditInterval);
2125}
2126
2127
2128function updateMessages(page, goToLast) {
2129 if (postingMessage && turboActivated) {
2130 // Postpone message fetching, posting the message is priorized
2131 fetchingMessages = false;
2132 currentTimeoutId = setTimeout(tryCatch(function() {
2133 updateMessages(page, goToLast);
2134 }), 100);
2135 return;
2136 }
2137
2138 function scheduleNextUpdate(interval, p, goLast) {
2139 fetchingMessages = false;
2140 currentTimeoutId = setTimeout(tryCatch(function() {
2141 updateMessages(p, goLast);
2142 }), interval);
2143 };
2144
2145 function onSuccess(res) {
2146 let parsed = parsePage(res);
2147 let lastPage = parsed.lastPage;
2148 let currPage = parsed.page;
2149 let int = turboActivated ? configuration["turbo_delay"] : updateIntervals[updateIntervalIdx] * 1000;
2150
2151 if (page < lastPage && goToLast) {
2152 updateMessages(page + 1, true);
2153 } else if (currPage < page || parsed.nbMessagesPage === 0) { // Bug des messages supprimés
2154 scheduleNextUpdate(int, page - 1, false);
2155 } else if (page > lastPage) {
2156 updateMessages(lastPage, true);
2157 } else {
2158 scheduleNextUpdate(int, page, true);
2159 }
2160 }
2161
2162 function onError(err) {
2163 if (!isError) {
2164 isError = true;
2165 setFixedAlert("danger", err);
2166 }
2167 scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 60000, page, true);
2168 }
2169
2170 function onTimeout(err) {
2171 addAlertbox("warning", err);
2172 scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 10000, page, true);
2173 }
2174
2175 let timeout = 10000;
2176 if (turboActivated) {
2177 timeout = 5000;
2178 }
2179
2180 fetchingMessages = true;
2181 currentFetchedPage = page;
2182 urlToFetch.page = page;
2183 let urlLastPage = buildURL(urlToFetch);
2184 request("GET", urlLastPage, onSuccess, onError, onTimeout, undefined, false, timeout);
2185}
2186
2187function checkEdited() {
2188 if (!shouldCheckEdited || currentFetchedPage === 1 || isError) {
2189 return;
2190 }
2191
2192 urlToCheckEdit.page = currentFetchedPage - 1;
2193 let urlPrevLastPage = buildURL(urlToCheckEdit);
2194
2195 function onSuccess(res) {
2196 let newMessages = [];
2197 let edited = res.getElementsByClassName("info-edition-msg");
2198 for (let msg of edited) {
2199 let bloc = msg.closest(".bloc-message-forum");
2200 newMessages.push(parseMessage(bloc));
2201 }
2202 addMessages(newMessages, true);
2203 }
2204
2205 function onError() {}
2206
2207 function onTimeout() {}
2208
2209 request("GET", urlPrevLastPage, onSuccess, onError, onTimeout, undefined, false, 20000);
2210}
2211
2212function parseAlerts(res) {
2213 let alerts = [];
2214 let alertsDiv = res.getElementsByClassName("alert");
2215 for (let a of alertsDiv) {
2216 let type = "danger";
2217 if (a.classList.contains("alert-warning")) {
2218 type = "warning";
2219 } else if (a.classList.contains("alert-success")) {
2220 type = "success";
2221 }
2222 let message = a.getElementsByClassName("alert-row")[0].textContent.trim();
2223 alerts.push({type: type, message: message});
2224 }
2225 return alerts;
2226}
2227
2228function increaseUpdateInterval() {
2229 if (updateIntervalIdx < updateIntervalMax) {
2230 updateIntervalIdx++;
2231 }
2232}
2233
2234function decreaseUpdateInterval() {
2235 updateIntervalIdx = transisitions[updateIntervalIdx];
2236}
2237
2238function parsePage(res) {
2239 let error = getTopicError(res);
2240 if (error !== undefined) {
2241 if (!isError) {
2242 updateIntervalIdx = updateIntervalMax;
2243 isError = true;
2244 setFixedAlert("danger", error);
2245 }
2246 return {lastPage: undefined, page: undefined, alert: true, nbMessagesPage: 0}
2247 }
2248
2249 if (isError) {
2250 isError = false;
2251 updateIntervalIdx = 0;
2252 removeFixedAlert("Le topic ne retourne plus d'erreur");
2253 }
2254
2255 let form = getForm(res);
2256 if (form !== undefined) {
2257 freshForm = form;
2258 }
2259
2260 let hash = getHash(res);
2261 if (hash !== undefined) {
2262 freshHash = hash;
2263 }
2264
2265 let messages = getMessages(res);
2266 addMessages(messages);
2267 let user = parseUserInfo(res);
2268 setUser(document, user);
2269 let topic = parseTopicInfo(res);
2270 let nbMessages = (topic.lastPage - 1) * 20;
2271 if (topic.page == topic.lastPage) {
2272 nbMessages += messages.length;
2273 }
2274 setTopicNbMessages(document, nbMessages);
2275 setTopicNbConnected(document, topic.connected);
2276 let alerts = parseAlerts(res);
2277 for (let alert of alerts) {
2278 addAlertbox(alert.type, alert.message);
2279 }
2280 let locked = getTopicLocked(res);
2281 let isLocked_ = (locked !== undefined);
2282
2283 if (isLocked_ && !isLocked) {
2284 updateInterval = updateIntervalMax;
2285 setFixedAlert("warning", locked);
2286 } else if (!isLocked_ && isLocked) {
2287 updateInterval = 0;
2288 removeFixedAlert("Le topic a été dévérouillé");
2289 }
2290 isLocked = isLocked_;
2291
2292 let sondage = parseSondage(res);
2293 if (sondage) {
2294 setSondage(sondage);
2295 }
2296
2297 return {page: topic.page, lastPage: topic.lastPage,
2298 nbMessagesPage: messages.length, alert: isLocked_ || (alerts.length > 0)};
2299}
2300
2301function addAlertbox(type, message) {
2302 // type: success / warning / danger
2303 let alert = `<div class="alert alert-${type}">
2304 <button class="close jvchat-alert-close" aria-hidden="true" data-dismiss="alert" type="button">×</button>
2305 <div class="alert-row">${message}</div>
2306 </div>`;
2307 document.getElementById("jvchat-fixed-alert").insertAdjacentHTML("afterend", alert);
2308}
2309
2310function setFixedAlert(type, message) {
2311 setFavicon("⨯");
2312 document.getElementById("jvchat-fixed-alert").getElementsByClassName("alert-row")[0].innerHTML = message;
2313 document.getElementById("jvchat-fixed-alert").setAttribute("class", `alert alert-${type}`);
2314}
2315
2316function removeFixedAlert(message) {
2317 document.getElementById("jvchat-fixed-alert").classList.add("jvchat-hide");
2318 if (message !== undefined) {
2319 addAlertbox("success", message);
2320 }
2321 if (document.hidden && nbNewMessage > 0) {
2322 setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage);
2323 } else {
2324 setFavicon("");
2325 }
2326}
2327
2328function makeJVChatButton() {
2329 let cls = 'btn-jvchat';
2330 let text = 'JVChat';
2331 let btn = `<button class="btn btn-actu-new-list-forum ${cls}">${text}</button>`;
2332 return btn;
2333}
2334
2335function addJVChatButton(document) {
2336 let css = `<style type="text/css">
2337 #forum-main-col .bloc-pre-pagi-forum {
2338 display: flex;
2339 }
2340
2341 #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right {
2342 position: relative;
2343 right: unset;
2344 left: unset;
2345 top: unset;
2346 bottom: unset;
2347 overflow: hidden;
2348 display: flex;
2349 flex-wrap: wrap;
2350 justify-content: flex-end;
2351 margin-top: auto;
2352 flex: 1;
2353 }
2354
2355 #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right button {
2356 float: right;
2357 min-width: 5.25rem;
2358 margin-left: 0.3125rem;
2359 }
2360 </style>`
2361 document.head.insertAdjacentHTML("beforeend", css);
2362 let blocPreRight = document.getElementsByClassName("bloc-pre-right");
2363 let jvchatButton = makeJVChatButton();
2364 for (let bloc of blocPreRight) {
2365 bloc.insertAdjacentHTML('afterbegin', jvchatButton);
2366 }
2367}
2368
2369function bindJVChatButton(document) {
2370 let buttons = document.getElementsByClassName('btn-jvchat');
2371 for (let btn of buttons) {
2372 btn.addEventListener('click', tryCatch(triggerJVChat));
2373 }
2374}
2375
2376function request(mode, url, callbackSuccess, callbackError, callbackTimeout, data, json, timeout) {
2377 json = !!json;
2378 let xhr = new XMLHttpRequest();
2379 xhr.timeout = timeout;
2380
2381 xhr.ontimeout = tryCatch(function() {
2382 callbackTimeout(`La délai d'attente de la requête a expiré`);
2383 });
2384
2385 xhr.onerror = tryCatch(function() {
2386 callbackError(`La requête a échoué (${xhr.status}): ${xhr.statusText}`);
2387 });
2388
2389 xhr.onabort = tryCatch(function() {
2390 if (!leavingTopic) {
2391 callbackTimeout(`La requête a été interrompue pour une raison inconnue`);
2392 }
2393 });
2394
2395 xhr.onload = tryCatch(function() {
2396 if (xhr.status !== 200) {
2397 callbackError(`La requête a retourné une erreur (${xhr.status}): ${xhr.statusText}`);
2398 return;
2399 }
2400 callbackSuccess(xhr.response);
2401 });
2402
2403 if (data === undefined) {
2404 data = null;
2405 }
2406
2407 if (json) {
2408 xhr.responseType = "json";
2409 } else {
2410 xhr.responseType = "document";
2411 }
2412
2413 xhr.open(mode, url, true);
2414 xhr.setRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate");
2415 xhr.send(data);
2416};
2417
2418// On copie/colle le code de TopicLive et on se sent développeur :)
2419function makeFavicon() {
2420 let canvas = document.createElement("canvas");
2421 canvas.width = 16;
2422 canvas.height = 16;
2423 let context = canvas.getContext('2d');
2424 let image = new Image();
2425 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==';
2426 return {canvas: canvas, context: context, image: image};
2427};
2428
2429function clearFavicon() {
2430 favicon.context.clearRect(0, 0, favicon.canvas.width, favicon.canvas.height);
2431 favicon.context.drawImage(favicon.image, 0, 0);
2432};
2433
2434function fillFavicon(txt) {
2435 clearFavicon();
2436
2437 if (txt !== '') {
2438 let context = favicon.context;
2439 context.fillStyle = 'DodgerBlue';
2440 context.fillRect(0, 0, context.measureText(txt).width + 3, 11);
2441 context.fillStyle = 'white';
2442 context.font = 'bold 10px Verdana';
2443 context.textBaseline = 'bottom';
2444 context.fillText(txt, 1, 11);
2445 }
2446};
2447
2448function setFavicon(txt) {
2449 let fav = document.getElementById("jvchat-favicon");
2450 if (fav) {
2451 fav.parentElement.removeChild(fav);
2452 }
2453 fillFavicon(txt);
2454 let url = favicon.canvas.toDataURL('image/png');
2455 let icon = `<link id="jvchat-favicon" rel="shortcut icon" type="image/png" href="${url}">`;
2456 document.head.insertAdjacentHTML("beforeend", icon);
2457}
2458
2459function reverseMessage(node, isInit, isUl) {
2460 let quote = "";
2461 let prevIsP = false;
2462
2463 for (let child of node.childNodes) {
2464 let name = child.nodeName;
2465
2466 switch (name) {
2467 case "P": {
2468 quote += reverseMessage(child) + "\n\n";
2469 break;
2470 }
2471 case "STRONG": {
2472 quote += "'''" + reverseMessage(child) + "'''";
2473 break;
2474 }
2475 case "EM": {
2476 quote += "''" + reverseMessage(child) + "''";
2477 break;
2478 }
2479 case "BR": {
2480 break;
2481 }
2482 case "UL": {
2483 quote += reverseMessage(child, false, true) + "\n\n";
2484 break;
2485 }
2486 case "OL": {
2487 quote += reverseMessage(child, false, false) + "\n\n";
2488 break;
2489 }
2490 case "LI": {
2491 if (isUl === true) {
2492 quote += "* " + reverseMessage(child) + "\n";
2493 } else {
2494 quote += "# " + reverseMessage(child) + "\n";
2495 }
2496 break;
2497 }
2498 case "DIV": {
2499 let classList = child.classList;
2500 if (classList.contains("bloc-spoil-jv")) {
2501 quote += "<spoil>" + reverseMessage(child) + "</spoil>\n\n"
2502 } else if (classList.contains("contenu-spoil")) {
2503 quote += reverseMessage(child);
2504 }
2505 break;
2506 }
2507 case "SPAN": {
2508 let classList = child.classList;
2509 if (classList.contains("bloc-spoil-jv")) {
2510 quote += "<spoil>" + reverseMessage(child) + "</spoil>";
2511 } else if (classList.contains("contenu-spoil")) {
2512 quote += reverseMessage(child);
2513 }
2514 break;
2515 }
2516 case "LABEL": {
2517 break;
2518 }
2519 case "INPUT": {
2520 break;
2521 }
2522 case "IMG": {
2523 quote += child.alt;
2524 break;
2525 }
2526 case "A": {
2527 if (child.title) {
2528 quote += child.href;
2529 } else {
2530 quote += reverseMessage(child);
2531 }
2532 break;
2533 }
2534 case "PRE": {
2535 quote += reverseMessage(child) + "\n\n";
2536 break;
2537 }
2538 case "CODE": {
2539 quote += "<code>" + child.textContent + "</code>";
2540 break;
2541 }
2542 case "BLOCKQUOTE": {
2543 if (prevIsP) {
2544 quote = quote.trimEnd() + "\n" + reverseMessage(child).replace(/^/gm, '> ') + "\n\n";
2545 } else {
2546 quote += reverseMessage(child).replace(/^/gm, '> ') + "\n\n";
2547 }
2548
2549 break;
2550 }
2551 case "#text": {
2552 // The "isInit" check is to prevent the empty text surroudning message
2553 // However, it may happen that the root node contains valid text child, so it need to be added somehow
2554 // For some reason, an "new line" may be missing in this case, so just add it
2555 if (!isInit || child.textContent.trim() !== "") {
2556 quote += child.textContent;
2557 if (isInit && !quote.endsWith("\n")) {
2558 quote += "\n";
2559 }
2560 }
2561 break;
2562 }
2563 default: {
2564 break;
2565 }
2566 }
2567
2568 if (name == "P") {
2569 prevIsP = true;
2570 } else {
2571 prevIsP = false;
2572 }
2573 }
2574
2575 quote = quote.replace(/(\n){3,}/g, '\n\n').trim();
2576
2577 if (isInit) {
2578 quote = quote.replace(/^/gm, '> ');
2579 }
2580
2581 return quote;
2582}
2583
2584function reverseQuote(blocMessage) {
2585 let author = blocMessage.getElementsByClassName("jvchat-author")[0].textContent.trim();
2586 let date = blocMessage.getElementsByClassName("jvchat-date")[0].getAttribute("to-quote");
2587 let header = `> Le ${date} ${author} a écrit :\n`;
2588 let quoted = reverseMessage(blocMessage.getElementsByClassName("txt-msg")[0], true);
2589 return header + quoted + '\n\n';
2590}
2591
2592function insertAtCursor(input, textToInsert) {
2593 const value = input.value;
2594 const start = input.selectionStart;
2595 const end = input.selectionEnd;
2596 input.value = value.slice(0, start) + textToInsert + value.slice(end);
2597 input.selectionStart = input.selectionEnd = start + textToInsert.length;
2598}
2599
2600function dontScrollOnExpand(event) {
2601 let target = event.target;
2602 if (!target) {
2603 return;
2604 }
2605
2606 let classes = target.classList;
2607
2608 if (classes.contains("blockquote-jv")) {
2609 let isDown = isScrollDown();
2610 target.setAttribute('data-visible', '1');
2611 if (isDown) {
2612 setScrollDown();
2613 }
2614 } else if (classes.contains("txt-spoil") || classes.contains("aff-spoil") || classes.contains("masq-spoil")) {
2615 event.preventDefault();
2616 let check = target.closest(".bloc-spoil-jv").getElementsByClassName("open-spoil")[0];
2617 let isDown = isScrollDown();
2618 check.checked = !check.checked;
2619 if (isDown) {
2620 setScrollDown();
2621 }
2622 } else if (classes.contains("jvchat-quote")) {
2623 let bloc = target.closest(".jvchat-message");
2624 let quote = reverseQuote(bloc);
2625 let textarea = document.getElementById("message_topic");
2626 if (isReduced) {
2627 toggleTextarea();
2628 }
2629 insertAtCursor(textarea, quote);
2630 textarea.focus();
2631 } else if (classes.contains("jvchat-edit")) {
2632 let bloc = target.closest(".jvchat-message");
2633 requestEdit(bloc);
2634 } else if (classes.contains("jvchat-delete")) {
2635 let bloc = target.closest(".jvchat-message");
2636 requestDelete(bloc);
2637 } else if (classes.contains("jvchat-edition-check")) {
2638 let bloc = target.closest(".jvchat-message");
2639 editMessage(bloc);
2640 } else if (classes.contains("jvchat-edition-cancel")) {
2641 let bloc = target.closest(".jvchat-message");
2642 let isDown = isScrollDown();
2643 bloc.getElementsByClassName("jvchat-content")[0].classList.remove("jvchat-hide");
2644 bloc.getElementsByClassName("jvchat-edition")[0].classList.add("jvchat-hide");
2645 if (isDown) {
2646 setScrollDown();
2647 }
2648 }
2649}
2650
2651function isScrollDown() {
2652 let element = document.getElementById("jvchat-main");
2653 return element.clientHeight + Math.floor(element.scrollTop) >= element.scrollHeight - 1;
2654}
2655
2656function setScrollDown() {
2657 let element = document.getElementById("jvchat-main");
2658 element.scrollTop = element.scrollHeight + 10000;
2659}
2660
2661function main() {
2662 addJVChatButton(document);
2663 bindJVChatButton(document);
2664}
2665
2666main();