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