您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Outil de discussion instantanée pour les forums de onche.org
// ==UserScript==ontchat // @name OnTchat // @description Outil de discussion instantanée pour les forums de onche.org // @author PingKungFu // @namespace OnTchat // @license MIT // @version 0.2.2 // @match http://onche.org/topic/* // @match https://onche.org/topic/* // @grant none // ==/UserScript== let bodyBgColor = getStyle(document.getElementsByTagName("body")[0], "background-color"); let textareaBgColor = getStyle(document.getElementsByTagName("textarea")[0], "background-color"); let textareaBorderColor = getStyle(document.getElementsByTagName("textarea")[0], "border-color"); let messageBgColor = getStyle(document.getElementsByClassName("message")[0], "background-color"); let messageBorderColor = getStyle(document.getElementsByClassName("message")[0], "border-color"); let messageAnswerBgColor = getStyle((document.getElementsByClassName("message answer")[0]) ? document.getElementsByClassName("message answer")[0] : document.getElementsByClassName("favoriteStickers")[0], "background-color"); let fontColor = getStyle(document.getElementsByClassName("message-content")[0], "color"); let CSS = `<style type="text/css" id="OnTchat-css"> header, .left, .logo, .container > .right, .screen, .bloc.hot, .message-anchor, .message:not(.answer, .small), .pagination, #confirmation, #right, #topic.bloc { display: none!important; } html, body, #ontchat-main, #page-messages-forum, #left, #forum-main-col > .left, .messages { height: 100%; width: 100%; } .ontchat-hide { display: none!important; } .ontchat-hide-visibility { visibility: hidden; } body { overflow-y: unset; padding: 0!important; } .ontchat-disabled-form { opacity: 0.5; cursor: not-allowed; pointer-events: none; } #ontchat-leftbar h4 { font-weight: 600; } #bloc-formulaire-forum > .form-post-message > .row { margin: 0; } .jv-editor > .conteneur-editor { background-color: var(--jv-bg-color); } .jv-editor > .conteneur-editor > .text-editor { border: 0; display: flex!important; } #ontchat-alerts { position: absolute; z-index: 3; right: 1rem; left: 0; overflow-y: hidden; } #ontchat-alerts .alert { color: #842029!important; background-color: #f8d7da!important; margin: 1rem 2rem; border-radius: 0.5rem; } #ontchat-leftbar { max-width: 15rem; flex-grow: 100000; flex-shrink: 100; position: relative; } #ontchat-leftbar-button { display: flex; position: absolute; right: 0; top: 6px; } #ontchat-leftbar-button span { font-size: 1.3rem; color: white; padding: 0 0.5rem 0 0rem; max-width: 100%; cursor: pointer; opacity: 0.3; } #ontchat-leftbar-button span:hover { opacity: 1; } #content { margin: 0; padding: 0; line-height: 1.42857; font-size: .875rem; } #page-messages-forum > .layout__contentMain { display: flex; padding: 0!important; height: 100%; max-width: unset; } #page-messages-forum { margin: 0; display: flex; } label { display: inline-block; max-width: 100%; margin-bottom: .3125rem; font-weight: 700; } #forum-main-col { flex-basis: 35rem; flex-grow: 100; overflow-x: auto; position: relative; min-width: 13rem; } #ontchat-right-padding { flex-shrink:1000; flex-grow:0; } #forum-main-col > .conteneur-messages-pagi { display: flex; flex-direction: column; } #page-messages-forum > .container-content { padding: 0; max-width: unset; min-width: unset; min-height: unset; max-height: unset; } .form-post-message { margin: 0; } .ontchat-textarea { resize: none; min-width: unset; } .ontchat-edition-textarea { resize: none; width: 100%; max-height: 6.5rem; min-height: 3.5rem; overflow-y: auto; } .ontchat-reduced { padding: 0.3rem; min-height: 1.5rem!important; max-height: 6.5rem; overflow: auto; line-height: 1rem; height: 1.8rem; } .ontchat-reduced .jv-editor .conteneur-editor > * { display: none; } #ontchat-buttons-main button { padding: 0; width: 2rem; } #ontchat-buttons-main button::before { font-size: 1.4rem; } #ontchat-buttons-main button.icon-reply::before { font-size: 1rem; } .ontchat-buttons { display: flex; flex-direction: column; } .ontchat-buttons button { border: 0.0625rem solid ${textareaBorderColor}; border-left-width: 0; height: 100%; background: white; color: gray; } .ontchat-buttons .ontchat-button-solo { border-radius: 0 0.3rem 0.3rem 0; } .ontchat-buttons .ontchat-button-top { border-radius: 0 0.3rem 0 0; } .ontchat-buttons .ontchat-button-bottom { border-radius: 0 0 0.3rem 0; border-top: 0!important; } .ontchat-textarea { border-radius: initial; border-right: none !important; color: inherit !important; } .ontchat-buttons button:hover { background: lightgray; color: black; } .ontchat-buttons button:focus { outline: none; border: dotted 1px!important; color: black; border: blue; } #forum-main-col { display: block; padding: 0; max-width: unset; } #ontchat-leftbar > .panel { margin: 0; padding: 0 0.5rem; } #ontchat-config { line-height: 1.40; } #ontchat-leftbar #ontchat-profil .titre-info-fofo, #ontchat-leftbar #ontchat-configuration .titre-info-fofo { margin-top: 0.5rem; } #ontchat-configuration-intro { color: grey; font-size: 0.84rem; } #ontchat-leftbar .titre-info-fofo { margin-top: 1rem; } .ontchat-config-option { margin-top: 2rem; } .ontchat-config-option p { font-size:0.83rem; } .ontchat-config-option > label { margin-bottom: 0.15rem; } .ontchat-range-option { display: flex; } .ontchat-range-option > span { white-space: nowrap; margin: 0px 10px; } .ontchat-range-option > input { width: 65%; } .ontchat-message { display: flex; margin-bottom: 0.35rem; } .ontchat-bloc-message { animation-duration:0.5s; animation-name: slidein; } .ontchat-message-deleted > div { opacity: 0.2; filter: grayscale(100%); } .ontchat-message-deleted { position: relative; } .ontchat-message-deleted:after { content: "Message supprimé"; position: absolute; top: 40%; left: 50%; color: gray; font-weight: bold; opacity: 0.7; } .ontchat-message-deleted .ontchat-delete, .ontchat-message-deleted .ontchat-edit { display: none; } @keyframes slidein { from { opacity: 0; } to { opacity: 1; } } .ontchat-toolbar { margin: 0 0 .3rem 0; } .ontchat-author { margin: 0; display: inline-block; font-size: .875rem; font-weight: 600; line-height: 1.1; } .ontchat-tooltip { display: flex; float: right; color: ##fffdfd; } .ontchat-picto { margin-right: 0.8rem; visibility: hidden; font-size: 1rem; } .ontchat-bloc-message:hover .ontchat-picto { visibility: visible; cursor: pointer; opacity: 0.25; } .ontchat-picto:hover { opacity: 1!important; } .ontchat-edition { display: flex; } .ontchat-edition-check { color: darkgreen!important; } .ontchat-night-mode .ontchat-edition-check { color: green!important; } .ontchat-edition-cancel { color: darkred!important; } .ontchat-night-mode .ontchat-edition-cancel { color: red!important; } .ontchat-edition-textarea { outline: none; width: 100%; background-color: var(--jv-input-bg-color); } hr.ontchat-ruler:first-of-type { margin-top: auto; } .ontchat-ruler { opacity: 1; margin: 0rem 0rem .35rem 0rem; border: 0; border-style: solid; border-top: 0.0625rem solid #1d1e20; border-top-width: 0.0625rem; border-bottom-width: 0.0625rem; border-block-end-color: #4a4c4f; box-sizing: content-box; height: 0!important; color: unset; background-color: unset; } #ontchat-ruler-new { border-bottom: 1px outset gray; } .ontchat-bloc-author-content { overflow: hidden; width: 100%; margin-left: .875rem; } .ontchat-content { font-size: 0.835rem; line-height: 1.1rem; } .ontchat-content > .txt-msg > p:last-of-type { margin-bottom: 0; } .ontchat-content > .txt-msg p { margin-bottom: 0.2rem; } .ontchat-content .text-enrichi-forum blockquote.blockquote-jv { margin: 0.2rem 0; padding: 0rem 0.3rem 0 0.3rem; color:#8b8b8b; } .ontchat-content .text-enrichi-forum .nested-quote-toggle-box { position: relative!important; } .ontchat-rounded { overflow: hidden; border-radius: 15%; background-size: cover; background-repeat: no-repeat; background-position: center center; } .ontchat-bloc-avatar { min-width: 40px; min-height: 40px; width: 40px; height: 40px; box-shadow: -3px 3px 7px grey; } #ontchat-user-avatar-link { width: 60%; min-width: 3rem; min-height: 3rem; margin: auto; } .ontchat-user-avatar { width: 100%; padding-top: 100%; } .ontchat-content .img-shack { height: 39px; width: 52px; display: inline-block; vertical-align: bottom; margin-bottom:0.27rem; overflow: hidden; } .ontchat-content .img-stickers { max-height: 39px; min-height: 39px; width: auto; display: inline-block; vertical-align: bottom; margin-bottom:0.1rem; } #ontchat-main .bloc-spoil-jv .open-spoil { position: unset; display: none; } .new-stickers { background-color: unset; } #ontchat-user-mp { font-size: 2rem; margin: auto; position: relative; } #ontchat-user-notif { font-size: 2rem; margin: auto; position: relative; } #ontchat-user-notif.has-notif::after, #ontchat-user-mp.has-notif::after { z-index: 2; content: " " attr(data-val) ""; color: #fff; line-height: 1.25rem; font-size: 0.9rem; padding: 0 .25rem; position: absolute; top: .6875rem; right: -.6875rem; background: #ff3c00; width: 1.1rem; height: 1.1rem; border-radius: 1rem; } #ontchat-user-pseudo { margin: 0.5rem; text-align: center; font-size: 1.125rem; font-weight: 500; line-height: 1.1; /* overflow-x: hidden; */ } #ontchat-user-info { display: flex; } #ontchat-mp-and-notif { position: unset; display: flex; justify-content: center; flex-direction: column; margin: auto; } #ontchat-topic-link { color: white; } #ontchat-topic-info { display: flex; flex-direction: column; } #ontchat-topic-nb-connected { color: lightgray; } #ontchat-topic-nb-messages { color: lightgray; } #bloc-formulaire-forum .jv-editor > .conteneur-editor { margin: 0; border: 0; padding: 0.5rem; line-height: normal; } #ontchat-main { overflow-y: auto; padding: 0.35rem 0.875rem; display: flex; flex-direction: column; } #ontchat-leftbar > .panel-jv-forum { height: 100%; overflow-y: auto; } #ontchat-leftbar.ontchat-leftbar-reduced { flex-grow: 0; } #ontchat-leftbar.ontchat-leftbar-reduced > .panel > .panel-body { display: none; } #ontchat-leftbar.ontchat-leftbar-reduced #ontchat-leftbar-button { position: relative; } #ontchat-leftbar.ontchat-leftbar-reduced span { padding: 0; } #ontchat-leftbar > .panel { position: relative; } .disabled-content { opacity: 0.3; cursor: not-allowed; pointer-events: none; } #ontchat-sondage-bloc { background: unset; padding: 0; } #ontchat-sondage-bloc .pourcent { background: unset; width: 5rem; } #ontchat-sondage-bloc .back-barre { width: 5rem; } #ontchat-sondage-bloc .tab-choix { margin-bottom: 1rem; } #ontchat-sondage-choix.notanswered .result-pourcent { display: none; } #ontchat-sondage-choix.notanswered .reponse { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAAG0lEQVQImWP4DwUMyOA/EqBAAkOQsACyILL5ACUbV6n3UrG0AAAAAElFTkSuQmCC') no-repeat left 0.35rem; padding-left: 0.7rem; } #ontchat-sondage-choix.notanswered .reponse > div { cursor: pointer; } #ontchat-turbo { display: inline-block; cursor: pointer; margin-top: 0.3rem; -webkit-tap-highlight-color: transparent; position: relative; } #ontchat-turbo i { position: relative; display: inline-block; margin-right: .5rem; width: 46px; height: 26px; background-color: #e6e6e6; border-radius: 23px; vertical-align: text-bottom; transition: all 0.3s linear; } #ontchat-turbo i::before { content: ""; position: absolute; left: 0; width: 42px; height: 22px; background-color: #fff; border-radius: 11px; transform: translate3d(2px, 2px, 0) scale3d(1, 1, 1); transition: all 0.25s linear; } #ontchat-turbo i::after { content: ""; position: absolute; left: 0; width: 22px; height: 22px; background-color: #fff; border-radius: 11px; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.24); transform: translate3d(2px, 2px, 0); transition: all 0.2s ease-in-out; } #ontchat-turbo:active i::after { width: 28px; transform: translate3d(2px, 2px, 0); } #ontchat-turbo:active input:checked + i::after { transform: translate3d(16px, 2px, 0); } #ontchat-turbo input:checked + i { background-color: #4BD763; } #ontchat-turbo input:checked + i::before { transform: translate3d(18px, 2px, 0) scale3d(0, 0, 0); } #ontchat-turbo input:checked + i::after { transform: translate3d(22px, 2px, 0); } #ontchat-turbo-span { position: absolute; margin-top: 4px; } #ontchat-alerts.ontchat-hide-alerts #ontchat-turbo-warning, #ontchat-alerts.ontchat-hide-alerts #ontchat-degraded-refresh-warning { display: none!important; } #ontchat-main.ontchat-hide-mosaics .ontchat-mosaic-root::before { content: "Mosaïque Cachée ¯\\\\_(ツ)_/¯"; color:black; text-align:center; font-size:10px; display:block; height:55px; width:55px; background: white; border: solid #f00; } #ontchat-main.ontchat-hide-mosaics .ontchat-mosaic-root { pointer-events: none; } #ontchat-main.ontchat-hide-mosaics .ontchat-mosaic { display: none; } #ontchat-turbo-delay-range, #ontchat-max-width-range, #ontchat-hide-mosaic-checkbox, #ontchat-hide-mosaic-span, #ontchat-night-mode-checkbox, #ontchat-night-mode-span, #ontchat-load-images-checkbox, #ontchat-load-images-span, #ontchat-play-sound-checkbox, #ontchat-play-sound-span { cursor: pointer; } .ontchat-night-mode #ontchat-leftbar > .panel { background-color: #2F3136!important; } .ontchat-night-mode { color: #dcddde!important; scrollbar-color: #191A1C #2F3136!important; } .ontchat-night-mode .ontchat-ruler { border-color: #2e3035!important; border-top: 1px solid transparent !important; } .ontchat-night-mode .conteneur-editor, .ontchat-night-mode .bloc-editor-forum, .ontchat-night-mode .ontchat-bloc-message, .ontchat-night-mode .conteneur-messages-pagi { background-color: ${messageBgColor} !important; } .ontchat-night-mode #message_topic, .ontchat-night-mode .btn-group { background: #484C52!important; } .ontchat-night-mode .ontchat-bloc-avatar { box-shadow: -3px 3px 7px black!important; } .ontchat-night-mode #ontchat-leftbar > .panel { background-color: #2F3136!important; } .ontchat-night-mode .ontchat-edition-textarea { background: #484c52!important; } /*.ontchat-night-mode .ontchat-buttons button { background: #484c52!important; }*/ .ontchat-night-mode .text-enrichi-forum blockquote.blockquote-jv { border-left-color: #484C52!important; } .ontchat-night-mode .text-enrichi-forum .nested-quote-toggle-box::after { background-color: #484c52!important; border-color: #737373!important; color: #737373!important; } .ontchat-night-mode .text-enrichi-forum .nested-quote-toggle-box:hover::before { color: #cbcdce!important; } .ontchat-night-mode .bloc-spoil-jv .contenu-spoil { background-color: #2d2d2d!important; border-color: #202020!important; color: #dcddde !important; } /* Rajout Onche */ a { color: #7dc3f7; text-decoration: none; } input[type="checkbox"] { -moz-appearance: auto; -webkit-appearance: auto; } #content { padding: 0; background-color: #36393f; } .container { width: 100%; } #ontchat-main { flex: 1; } .messages { background-color: ${messageBgColor} !important; display: flex; flex-direction: column; color: ${fontColor}; } .message.answer { background: ${messageAnswerBgColor} !important; } #answer .message-content { height: auto; max-height: 120px; overflow-y: scroll; } .bloc.insert-image { margin: 0; border: 1px solid #2a2d34; } .bloc.insert-image > .title { display: none; } .boc.content { padding: 0; } .textarea { font-size: 1.5em; resize: none; min-height: 138px; } .items { flex-direction: column; } .format { background-color: ${textareaBgColor}; border-top: 0.0625rem solid ${textareaBorderColor}; border-bottom: 0.0625rem solid ${textareaBorderColor}; } .ontchat-textarea-wrapper { display: flex; } #ontchat-post-2 { border-radius: 0; } .ontchat-hide-stickers { display: none!important; } /* Lavydavant */ .panel-jv-forum { background-color: #2A2A2A !important; border-radius: 0 !important; } .panel-body { color: #FFFFFF !important; } .panel-body .titre-info-fofo { color: #ffca20; font-weight: 500; line-height: 1.1; font-size: .875rem; text-transform: uppercase; border-bottom: .0625rem solid #9c9da7; padding-bottom: .5rem; margin: 0 0 .5rem; } .onchat-quoting { cursor: pointer; opacity: 0.5; margin: 0.3rem; } .onchat-quoting:hover { opacity: 1; } .alert-row { flex: 1; } #ontchat-mp-and-notif .nav-link, .nav-link-search, .account-pseudo, .jv-account-number-mp, .jv-account-number-notif { color: white !important; } .alert.alert-success { color: #842029!important; background-color: #f8d7da!important; border-color: #f5c2c7; display: flex; filter: brightness(0.85) flex-direction: row-reverse; } .row.wrap .button.medium.filled.right{ display: none; } .item.onche { height: 42px; } .ontchat-poll { background-color: transparent!important; border: none; margin: 0; padding: 5px; } .ontchat-poll-answers{ flex-direction: column!important; } .signature { display: none; } /* Revert random CSS changes by Webedia */ .ontchat-alert-close { float: right; font-size: 1.3125rem; font-weight: 700; line-height: 1; color: #000; text-shadow: 0 0.0625rem 0 #fff; filter: alpha(opacity=20); opacity: 0.2; padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .ontchat-alert-close:focus, .ontchat-alert-close:hover { color: #000; text-decoration: none; cursor: pointer; filter: alpha(opacity=50); opacity: 0.5; } </style>`; let PANEL = ` <div id='ontchat-leftbar'> <div class='panel panel-jv-forum'> <div id="ontchat-leftbar-button"> <div id="ontchat-leftbar-config"> <span id="ontchat-leftbar-config-open" class="material-icons" title="Afficher les paramètres">settings</span> <span id="ontchat-leftbar-config-close" class="material-icons ontchat-hide" title="Fermer les paramètres">close</span> </div> <div id="jvchar-leftbar-size"> <span id="ontchat-leftbar-reduce" class="material-icons icon-arrow-left" title="Masquer la sidebar">arrow_back_ios</span> <span id="ontchat-leftbar-extend" class="material-icons icon-arrow-right ontchat-hide" title="Afficher la sidebar">arrow_forward_ios</span> </div> </div> <div class='panel-body'> <div id='ontchat-info'> <div id='ontchat-profil' class='ontchat-hide'> <h4 class='titre-info-fofo'>Profil</h4> <h4 id='ontchat-user-pseudo'></h4> <div id='ontchat-user-info'> <a title="Ouvrir le profil" id="ontchat-user-avatar-link" target="_blank"><div id='ontchat-user-avatar' class='ontchat-rounded ontchat-user-avatar'></div></a> <div id='ontchat-mp-and-notif'> <a target="_blank" href="https://onche.org/chat" title="Ouvrir la boîte de réception" id="ontchat-user-mp-link"> <span id="ontchat-user-mp" class="material-icons jv-account-number-mp" data-val="0">email</span> </a> </div> </div> </div> <div id='ontchat-topic'> <h4 class='titre-info-fofo'>Topic</h4> <div id="ontchat-topic-info"> <div><strong><a title="Ouvrir le topic" id="ontchat-topic-title"></a></strong></div> <span id="ontchat-topic-nb-connected"></span> <span id="ontchat-topic-nb-messages"></span> <!-- <label id="ontchat-turbo" title="Actualise la liste des messages plus rapidement"> <input id="ontchat-turbo-checkbox" type="checkbox"> <i></i> <span id="ontchat-turbo-span">Mode Turbo</span> </label> --> </div> </div> <div id='ontchat-forum'> <h4 class='titre-info-fofo'>Forum</h4> <div id="ontchat-forum-info"> <div><strong><a title="Ouvrir le forum" id="ontchat-forum-title"></a></strong></div> </div> </div> <div id='ontchat-sondage' class='ontchat-hide'> <h4 class='titre-info-fofo'>Sondage</h4> <div id="ontchat-sondage-bloc" class="bloc-sondage"> <label><span id="ontchat-sondage-intitule"></span></label> <table class="tab-choix"><tbody id="ontchat-sondage-choix" class="notanswered"></tbody></table> <span id="ontchat-sondage-votes"></span> </div> </div> </div> <div id='ontchat-config' class='ontchat-hide'> <div id='ontchat-configuration'> <h4 class='titre-info-fofo'>Configuration</h4> <p id='ontchat-configuration-intro'><i>Les paramètres sont automatiquement sauvegardés et mis à jour lorsque vous les modifiez.</i></p> <div class="ontchat-config-option" id="ontchat-play-sound"> <label> <input id="ontchat-play-sound-checkbox" type="checkbox"> <span id="ontchat-play-sound-span">Alerte sonore</span> </label> <p>Joue un son de notification lorsqu'un nouveau message est posté et que vous êtes sur un onglet différent.</p> </div> <!-- <div class="ontchat-config-option" id="ontchat-night-mode"> <label> <input id="ontchat-night-mode-checkbox" type="checkbox"> <span id="ontchat-night-mode-span">Thème sombre</span> </label> <p>Active un mode nuit pour protéger vos petits yeux fatigués le soir.</p> </div> --> <div class="ontchat-config-option" id="ontchat-load-imagesc"> <label> <input id="ontchat-load-images-checkbox" type="checkbox"> <span id="ontchat-load-images-span">Charger les images</span> </label> <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> </div> <div class="ontchat-config-option" id="ontchat-hide-mosaic"> <label> <input id="ontchat-hide-mosaic-checkbox" type="checkbox"> <span id="ontchat-hide-mosaic-span">Masquer les mosaïques</span> </label> <p>Cache automatiquement les mosaïques d'images NoelShack pour réduire le flooding.</p> </div> <div class="ontchat-config-option" id="ontchat-hide-stickers"> <label> <input id="ontchat-hide-onche-stickers-checkbox" type="checkbox"> <span id="ontchat-hide-onche-stickers-span">Masquer les stickers favoris d'Onche</span> </label> <p>Cache automatiquement la barre des stickers favoris d'Onche.</p> </div> </div> </div> </div> </div> </div> `; let freshHash = undefined; let freshDeletionHash = undefined; let freshForm = undefined; let firstMessageId = undefined; let firstMessageDate = undefined; let lastEditionTime = {}; // id => [timestamp, edition, deleted] let messagesByPage = {}; let userConnected = undefined; let 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]; let 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]; let updateIntervalIdx = 2; let updateIntervalMax = updateIntervals.length - 1; let isLocked = false; let isError = false; let isReduced = true; let nbNewMessage = 0; let topicNbMessages = 0; let favicon = undefined; let faviconLoaded = false; let faviconTextWhenLoaded = ""; let currentUser = { notif: undefined, mp: undefined, author: undefined, avatar: undefined }; let currentTopicTitle = undefined; let turboActivated = false; let turboDateActivated = undefined; let turboWarnTimeoutId = -1; let turboDateSessions = []; let refreshDegraded = false; let refreshDegradedTimeoutId = -1; let timeoutedDates = []; let refreshInfosAcceptable = []; let sondageChoices = undefined; let urlToFetch = undefined; let urlToRefreshInfos = undefined; let urlToCheckEdited = undefined; let currentFetchedPage = 1; let currentTimeoutId = -1; let shouldCheckEdited = false; let checkEditedInterval = 30000; let refreshInfosTimeoutId = -1; let postingMessage = false; let fetchingMessages = false; let leavingTopic = false; let storageKey = "ontchat-configuration"; let ringBell = undefined; let configuration = undefined; let sondageExist = false; let counterSondage = 0; function defaultConfig() { return { default_reduced: false, turbo_delay: 1000, max_width: 100, hide_alerts: false, play_sound: false, night_mode: false, load_images: false, hide_mosaic: false, hide_stickers: false, turbo_alerted: false, 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=" }; } function saveConfig() { let config = JSON.stringify(configuration); localStorage.setItem(storageKey, config); } function loadConfig() { let config = JSON.parse(localStorage.getItem(storageKey) || "{}"); for (let key in config) { if (config.hasOwnProperty(key) && configuration.hasOwnProperty(key)) { configuration[key] = config[key]; } } } function getTimestamp() { return new Date().getTime(); } function escape(str, isAttribute) { str = str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); if (isAttribute) { str = str.replace(/"/g, """).replace(/'/g, "'"); } return str; } function getForm(doc) { return doc.getElementById("post").firstChild; } function getTopicLocked(elem) { let lock = elem.getElementsByClassName("message-lock-topic")[0]; if (lock === undefined) { return lock; } let reason = lock.getElementsByTagName("span")[0].textContent.trim(); return `Le topic a été verrouillé pour la raison suivante : "${reason}"`; } function getTopicError(elem) { let error = elem.getElementsByClassName("img-erreur")[0]; if (error === undefined) { return error; } return `Le topic présente une erreur: ${error.getAttribute("alt")}`; } function tryCatch(func) { function wrapped(optArg) { try { func(optArg); } catch (err) { let message = `Une erreur est survenue dans ontchat: '${err.message}' (function '${func.name}', line ${err.lineNumber})`; console.error("===== ontchat ERROR ====="); console.error(message) console.error(err); console.error("========================"); try { addAlertbox("danger", message); } catch (e) { alert(message); } } } return wrapped; } function toggleTextarea() { isReduced = !isReduced; configuration["default_reduced"] = isReduced; saveConfig(); let isDown = isScrollDown(); document.getElementsByClassName("format")[0].classList.toggle("ontchat-hide"); document.getElementById("ontchat-enlarge").classList.toggle("ontchat-hide"); document.getElementById("ontchat-reduce").classList.toggle("ontchat-hide"); document.getElementById("ontchat-post").classList.toggle("ontchat-hide"); document.getElementById("ontchat-post-2").classList.toggle("ontchat-hide"); document.getElementsByClassName("textarea")[0].classList.toggle("ontchat-reduced"); // document.getElementsByClassName("favoriteStickers")[0].classList.toggle("ontchat-hide"); let risiOnche = document.getElementsByClassName("quote-risionche")[0]; if (risiOnche) { risiOnche.classList.toggle("ontchat-hide"); } setTextareaHeight(); if (isDown) { setScrollDown(); } } function parseURL(url) { let regex = /^(.*?)\/(\d+)\/([\w-]+)\/?(\d*)\/?(.*)?$/i; let [_, domain, ids, title, page, anchor] = url.match(regex); return { domain: domain, ids: ids, title: title, page: page, anchor: anchor }; } function buildURL(dict) { return `${dict.domain}/${dict.ids}/${dict.title}${(dict.page) ? '/' + dict.page : ''}${(dict.anchor) ? '/' + dict.anchor : ''}`; } function getForum(document) { let link = document.getElementsByClassName("links")[0].getElementsByClassName("active")[0]; return { href: link.href, title: link.textContent }; } function getLastPage(document) { let blocPages = document.getElementsByClassName("pagination")[0]; let ahrefs = blocPages.getElementsByTagName("a"); let lastPage = 1; for (let ahref of ahrefs) { let page = parseInt(ahref.textContent.trim()); if (!isNaN(page) && page > lastPage) { lastPage = page; } } return lastPage; } function parseMessage(elem) { let conteneur = elem; let author = conteneur.getElementsByClassName("message-username")[0].textContent.trim(); //badge let avatar = conteneur.getElementsByClassName("avatar")[0]; if (avatar !== undefined) { avatar = avatar.getAttribute("src"); } let date = conteneur.getElementsByClassName("message-date")[0].getAttribute("title").trim(); let content = conteneur.querySelectorAll(":scope > .message-content")[0]; let message_answer = conteneur.getElementsByClassName("message answer")[0]; let id = parseInt(conteneur.getAttribute("data-id")); let id_message_author = parseInt(conteneur.getAttribute("data-user-id")); let edited = elem.getElementsByClassName("edited")[0]; if (edited !== undefined) { let msgEdited = edited.getAttribute("title").trim(); edited = msgEdited.match(/Publié le (\d{2}\/\d{2}\/\d{4}) à (\d{2}\:\d{2}\:\d{2}) et modifié le (\d{2}\/\d{2}\/\d{4}) à (\d{2}\:\d{2}\:\d{2})/i)[4]; } return { author: author, dateString: date, date: parseDate(date), avatar: avatar, id: id, content: content, id_message_author: id_message_author, message_answer: message_answer, edited: edited }; } function parseUserInfo(elem) { let accountMp = elem.getElementsByClassName("account__badge")[0]; if (accountMp === undefined) { return { author: undefined, avatar: undefined, mp: undefined, notif: undefined }; } let accountNotif = elem.getElementById("notification-button"); // mdi-notification-button let avatarBox = elem.getElementsByClassName("account")[0].getElementsByClassName("avatar")[0]; let authorBox = elem.getElementsByClassName("account")[0].getElementsByTagName("span")[0]; let mp = parseInt(accountMp.getAttribute("data-chat-nb")); let notif = parseInt(accountNotif.getAttribute("data-nb")); let avatar = avatarBox.src; let author = authorBox.textContent.trim(); return { author: author, avatar: avatar, mp: mp, notif: notif }; } function getPage(elem) { let pageActive = elem.getElementsByClassName("active")[0]; let page = 1; if (pageActive !== undefined) { page = parseInt(pageActive.textContent.trim()); } return page; } function parseTopicInfo(elem) { let title = elem.getElementsByClassName('title is_sticky')[0].getElementsByTagName("h1")[0].textContent.trim(); let connected = parseInt(elem.getElementsByClassName("bloc border green")[0].getElementsByClassName("content rows")[0].getElementsByTagName("span")[1].textContent.trim()); let lastPage = getLastPage(elem); let page = getPage(elem); return { title: title, connected: connected, lastPage: lastPage, page: page }; } function fixMessage(elem) { let jvcares = Array.from(elem.getElementsByClassName("JvCare")); for (let jvcare of jvcares) { let a = document.createElement("a"); a.setAttribute("target", "_blank"); a.setAttribute("href", jvCake(jvcare.getAttribute("class"))); a.innerHTML = jvcare.innerHTML; jvcare.outerHTML = a.outerHTML; } let togglableQuotes = Array.from(elem.querySelectorAll(".text-enrichi-forum > blockquote > blockquote")); for (let togglableQuote of togglableQuotes) { let toggleButton = document.createElement("div"); toggleButton.classList.add("nested-quote-toggle-box"); togglableQuote.insertBefore(toggleButton, togglableQuote.firstChild); // The click event is bound in the "dontScrollOnExpand()" function } } function jvCake(cls) { let base16 = '0A12B34C56D78E9F', lien = '', s = cls.split(' ')[1]; for (let i = 0; i < s.length; i += 2) { lien += String.fromCharCode(base16.indexOf(s.charAt(i)) * 16 + base16.indexOf(s.charAt(i + 1))); } return lien; } function detectMosaic(elem) { let imagesShack = elem.getElementsByClassName("img-shack"); if (imagesShack.length < 4) { return; } let mosaics = {}; let regex1 = /^.+\/(?:[0-9]+-)+[0-9]{1,2}-([a-z0-9]+)\.\w+$/i; let regex2 = /^.+\/(?:[0-9]+-)+row-[0-9]+-col-[0-9](?:-[0-9]+)?\.\w+$/i; for (let image of imagesShack) { let match1 = image.src.match(regex1); if (match1) { let [_, identifier] = match1; if (mosaics.hasOwnProperty(identifier)) { mosaics[identifier].push(image); } else { mosaics[identifier] = [image]; } continue; } let match2 = image.src.match(regex2); if (match2) { if (mosaics.hasOwnProperty("@rowcol")) { mosaics["@rowcol"].push(image); } else { mosaics["@rowcol"] = [image]; } continue; } } for (let identifier in mosaics) { let images = mosaics[identifier]; if (images.length < 4) { continue; } images[0].parentNode.classList.add("ontchat-mosaic-root"); images[0].classList.add("ontchat-mosaic"); for (let image of images.slice(1)) { image.parentNode.classList.add("ontchat-mosaic"); } } } function improveImages(elem) { let imagesShack = elem.getElementsByClassName("img-shack"); for (let image of imagesShack) { let src = image.src; let parent = image.parentNode; let extension = parent.href.split(".").pop(); let direct = src.replace(/(.*?)\/minis\/(.*)\.\w+/i, "$1/fichiers/$2." + extension); image.setAttribute("data-src-mini", src); image.setAttribute("data-src-direct", direct); image.classList.add("ontchat-loadable-image"); parent.href = direct; if (extension.toUpperCase() === "GIF") { image.src = direct; image.classList.remove("ontchat-loadable-image"); } else if (configuration["load_images"]) { image.src = direct; } src = image.src; image.setAttribute("onerror", `this.onerror=null;this.src=this.getAttribute("data-src-direct");this.classList.remove("ontchat-loadable-image");`); } } function clearPage(document) { let buttons = ` <div id="ontchat-buttons-main-2" class='ontchat-buttons'> <button id='ontchat-post-2' tabindex="4" type="button" class='ontchat-button-top icon-reply material-icons' title="Envoyer le message">send</button> </div> <div id="ontchat-buttons-main" class='ontchat-buttons'> <button id='ontchat-post' tabindex="4" type="button" class='ontchat-hide ontchat-button-top icon-reply material-icons' title="Envoyer le message">send</button> <button id='ontchat-reduce' tabindex="5" type="button" class='ontchat-hide ontchat-button-bottom icon-arrow-down-entypo material-icons' title="Réduire la zone de texte">expand_more</button> <button id='ontchat-enlarge' tabindex="4" type="button" class='ontchat-button-solo icon-arrow-up-entypo material-icons' title="Agrandir la zone de texte">expand_less</button> </div>`; document.head.insertAdjacentHTML("beforeend", CSS); let messageTopic = document.getElementsByClassName("textarea")[0]; // remove previsu messageTopic.removeAttribute("data-preview"); if (messageTopic) { let form = messageTopic.parentElement; let answerDiv = document.getElementById("answer"); answerDiv.insertAdjacentHTML("afterend", "<div class='ontchat-textarea-wrapper'></div>"); let textareaWrapper = document.getElementsByClassName("ontchat-textarea-wrapper")[0]; textareaWrapper.appendChild(messageTopic.parentNode.removeChild(messageTopic)); let format = document.getElementsByClassName("format")[0]; format.classList.add('ontchat-hide'); textareaWrapper.appendChild(format.parentNode.removeChild(format)); textareaWrapper.insertAdjacentHTML("beforeend", buttons); messageTopic = document.getElementsByClassName("textarea")[0]; messageTopic.classList.add("ontchat-textarea"); messageTopic.setAttribute("placeholder", "Hop hop hop, le message ne va pas s'écrire tout seul !"); messageTopic.addEventListener("keydown", tryCatch(postMessageIfEnter)); form.addEventListener('submit', tryCatch(postingMessageOnche)); document.getElementById("ontchat-post").addEventListener("click", tryCatch(postingMessageOnche)); document.getElementById("ontchat-post-2").addEventListener("click", tryCatch(postingMessageOnche)); document.getElementById("ontchat-enlarge").addEventListener("click", tryCatch(toggleTextarea)); document.getElementById("ontchat-reduce").addEventListener("click", tryCatch(toggleTextarea)); } document.getElementsByClassName("messages")[0].insertAdjacentHTML("afterbegin", "<div id='ontchat-main'><hr class='ontchat-ruler'></div>"); document.getElementById("left").insertAdjacentHTML("afterbegin", "<div id='ontchat-alerts'><div id='ontchat-fixed-alert' class='ontchat-hide'><div class='alert-row'></div></div><div id='ontchat-turbo-warning' class='ontchat-hide'><button class='close ontchat-alert-hide' aria-hidden='true' data-dismiss='alert' type='button'>×</button><div class='alert-row'></div></div><div id='ontchat-degraded-refresh-warning' class='ontchat-hide'><div class='alert-row'></div></div></div>"); document.getElementsByClassName("container")[0].insertAdjacentHTML("afterbegin", PANEL); document.getElementsByClassName("container")[0].insertAdjacentHTML("beforeend", "<div id='ontchat-right-padding'></div>"); document.getElementById("content").classList.add("ontchat-root"); document.getElementsByClassName("textarea")[0].classList.add("ontchat-reduced"); let risiOnche = document.getElementsByClassName("quote-risionche")[0]; if (risiOnche) { risiOnche.classList.add("ontchat-hide") } document.getElementsByClassName("bloc insert-image")[0].classList.add("ontchat-hide"); document.getElementById("ontchat-main").addEventListener("click", tryCatch(dontScrollOnExpand)); document.getElementById("ontchat-alerts").addEventListener("click", tryCatch(closeAlert)); let sondage = document.getElementsByClassName("poll")[0]; if (!!sondage) { sondageExist = true; let sondageTitle = sondage.getElementsByTagName("h2")[0]; sondageTitle.classList.add("ontchat-hide"); sondage.classList.add("ontchat-poll"); sondage.getElementsByClassName("poll-answers")[0].classList.add("ontchat-poll-answers"); document.getElementById("ontchat-sondage").classList.toggle("ontchat-hide"); let sondageBloc = document.getElementById("ontchat-sondage-bloc"); let sondageOntchat = sondage.cloneNode(true); sondage.classList.add("ontchat-hide"); sondageBloc.insertBefore(sondageOntchat, sondageBloc.firstChild); sondageTitle.classList.add("ontchat-hide"); if (sondageTitle.textContent.length > 7){ let numberVotes = sondageTitle.textContent.match(/\d+/)[0]; document.getElementById("ontchat-sondage-votes").textContent = `(${numberVotes} votes)`; } } document.getElementById("ontchat-leftbar-config-open").addEventListener("click", tryCatch(toggleConfig)); document.getElementById("ontchat-leftbar-config-close").addEventListener("click", tryCatch(toggleConfig)); document.getElementById("ontchat-play-sound-checkbox").checked = configuration["play_sound"]; document.getElementById("ontchat-play-sound-checkbox").addEventListener("change", tryCatch(togglePlaySoundOption)); document.getElementById("ontchat-hide-onche-stickers-checkbox").checked = configuration["hide_stickers"]; document.getElementById("ontchat-hide-onche-stickers-checkbox").addEventListener("change", tryCatch(toggleOncheStickersOption)); if (configuration["hide_stickers"]){ document.getElementsByClassName("favoriteStickers")[0].classList.add("ontchat-hide-stickers"); } document.getElementById("content").classList.add("ontchat-night-mode"); document.getElementById("ontchat-hide-mosaic-checkbox").checked = configuration["hide_mosaic"]; document.getElementById("ontchat-hide-mosaic-checkbox").addEventListener("change", tryCatch(toggleHideMosaicOption)); if (configuration["hide_mosaic"]) { document.getElementById("ontchat-main").classList.add("ontchat-hide-mosaics"); } if (configuration["hide_alerts"]) { document.getElementById("ontchat-alerts").classList.add("ontchat-hide-alerts"); } document.getElementById("ontchat-load-images-checkbox").checked = configuration["load_images"]; document.getElementById("ontchat-load-images-checkbox").addEventListener("change", tryCatch(toggleLoadImagesOption)); // change la position du submit pour mettre dans la div messages let submitForm = document.getElementsByClassName("bloc insert-image")[0]; let submitFormCut = submitForm.parentNode.removeChild(submitForm); let messages = document.getElementsByClassName("messages")[0]; messages.insertBefore(submitFormCut, messages.children[1]); let favs = Array.from(document.querySelectorAll("link[rel='icon'], link[rel='shortcut icon']")); for (let fav of favs) { fav.parentElement.removeChild(fav); } setFavicon(""); document.addEventListener("visibilitychange", function () { let hidden = document.hidden; if (hidden) { let newHr = document.getElementById("ontchat-ruler-new"); if (newHr) { newHr.removeAttribute("id"); } nbNewMessage = 0; } else if (!isError && !isLocked) { setFavicon(""); } }); document.getElementsByClassName("bloc insert-image")[0].addEventListener("click", tryCatch(deleteAnswer)); } function deleteAnswer(event) { if(event.target.classList.contains(".mdi-close")) { console.log("abc"); } } function toggleSidebar(event) { let isDown = isScrollDown(); document.getElementById("ontchat-leftbar-extend").classList.toggle("ontchat-hide"); document.getElementById("ontchat-leftbar-reduce").classList.toggle("ontchat-hide"); document.getElementById("ontchat-leftbar-config").classList.toggle("ontchat-hide"); document.getElementById("ontchat-leftbar").classList.toggle("ontchat-leftbar-reduced"); if (isDown) { setScrollDown(); } } function toggleConfig(event) { document.getElementById("ontchat-leftbar-config-open").classList.toggle("ontchat-hide"); document.getElementById("ontchat-leftbar-config-close").classList.toggle("ontchat-hide"); document.getElementById("ontchat-info").classList.toggle("ontchat-hide"); document.getElementById("ontchat-config").classList.toggle("ontchat-hide"); } function forceUpdate() { // If waiting for next update, restart it immediately, otherwise just wait for the HTTP request to end if (!fetchingMessages) { clearTimeout(currentTimeoutId); updateMessages(currentFetchedPage, true); } } function scheduleTurboWarningDelay() { let now = getTimestamp(); let maxAllowedTime = 60 * 1000; let lookupTime = now - 90 * 1000; let nbToCleanup = 0; let duration = 0; for (let session of turboDateSessions) { let begin = session[0]; let end = session[1]; if (end < lookupTime) { nbToCleanup++; continue; } duration += end - Math.max(lookupTime, begin); } for (let i = 0; i < nbToCleanup; i++) { turboDateSessions.shift(); } let remainingTimeAllowed = Math.max(0, maxAllowedTime - duration); turboDateActivated = now; turboWarnTimeoutId = setTimeout(tryCatch(setTurboWarning), remainingTimeAllowed); } function togglePlaySoundOption(event) { let checked = document.getElementById("ontchat-play-sound-checkbox").checked; configuration["play_sound"] = checked; saveConfig(); } function toggleHideMosaicOption(event) { let checked = document.getElementById("ontchat-hide-mosaic-checkbox").checked; configuration["hide_mosaic"] = checked; saveConfig(); let isDown = isScrollDown(); document.getElementById("ontchat-main").classList.toggle("ontchat-hide-mosaics"); if (isDown) { setScrollDown(); } } function toggleLoadImagesOption(event) { let checked = document.getElementById("ontchat-load-images-checkbox").checked; configuration["load_images"] = checked; saveConfig(); for (let image of document.getElementsByClassName("ontchat-loadable-image")) { image.src = image.getAttribute(checked ? "data-src-direct" : "data-src-mini"); } } function toggleOncheStickersOption(event) { let checked = document.getElementById("ontchat-hide-onche-stickers-checkbox").checked; configuration["hide_stickers"] = checked; saveConfig(); document.getElementsByClassName("favoriteStickers")[0].classList.toggle("ontchat-hide-stickers"); } // function toggleRisioncheOption(event) { // } function adjustMaxWidth(maxWidth) { document.getElementById("forum-main-col").style["flex-grow"] = maxWidth; document.getElementById("ontchat-right-padding").style["flex-grow"] = 100 - maxWidth; } function closeAlert(event) { let target = event.target; if (!target) { return; } if (target.classList.contains("ontchat-alert-close")) { let parent = target.parentElement; parent.parentElement.removeChild(parent); } else if (target.classList.contains("ontchat-alert-hide")) { let parent = target.parentElement; parent.classList.add("ontchat-hide"); } } function postingMessageOnche(e) { e.preventDefault(); if (freshForm === undefined) { addAlertbox("danger", "Impossible de poster le message, aucun formulaire trouvé"); return; } let textarea = document.getElementsByClassName("textarea")[0]; let formData = serializeForm(freshForm); formData["message"] = textarea.value; if (document.getElementsByName("answer")[0]) { formData["answer"] = document.getElementsByName("answer")[0].value; } let formulaire = document.getElementById("post"); formulaire.classList.add("ontchat-disabled-form"); textarea.setAttribute("disabled", "true"); let timestamp = getTimestamp(); function onSuccess(res) { formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); let parsedPage = parsePage(res, timestamp); document.getElementById("answer").innerHTML=''; if (!parsedPage.alert) { textarea.value = ""; } setTextareaHeight(); setScrollDown(); postingMessage = false; if (parsedPage.nbMessagesPage === 20) { // Bug si on poste un message générant une nouvelle page : la requête retourne la page // courante, donc notre nouveau message n'apparaît pas, il faut forcer un refetch() // MAIS il faut attendre un peu, car JVC galère à créer la page... setTimeout(tryCatch(forceUpdate), 3000); } } function onError(err, _) { addAlertbox("danger", err); formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); postingMessage = false; } function onTimeout(err) { addAlertbox("warning", err); formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); postingMessage = false; } let timeout = 20000; if (turboActivated) { timeout = 5000; } postingMessage = true; request("POST", document.URL, onSuccess, onError, onTimeout, makeFormData(formData), false, timeout, false); } function postMessage() { if (freshForm === undefined) { addAlertbox("danger", "Impossible de poster le message, aucun formulaire trouvé"); return; } let textarea = document.getElementsByClassName("textarea")[0]; let formData = serializeForm(freshForm); formData["message_topic"] = textarea.value; let formulaire = document.getElementById("post"); formulaire.classList.add("ontchat-disabled-form"); textarea.setAttribute("disabled", "true"); let timestamp = getTimestamp(); function onSuccess(res) { formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); let parsedPage = parsePage(res, timestamp); if (!parsedPage.alert) { textarea.value = ""; } setTextareaHeight(); setScrollDown(); postingMessage = false; if (parsedPage.nbMessagesPage === 20) { // Bug si on poste un message générant une nouvelle page : la requête retourne la page // courante, donc notre nouveau message n'apparaît pas, il faut forcer un refetch() // MAIS il faut attendre un peu, car JVC galère à créer la page... setTimeout(tryCatch(forceUpdate), 3000); } } function onError(err, _) { addAlertbox("danger", err); formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); postingMessage = false; } function onTimeout(err) { addAlertbox("warning", err); formulaire.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); postingMessage = false; } let timeout = 20000; if (turboActivated) { timeout = 5000; } postingMessage = true; request("POST", document.URL, onSuccess, onError, onTimeout, makeFormData(formData), false, timeout, false); } function editMessage(bloc) { let textarea = bloc.getElementsByClassName("ontchat-edition-textarea")[0]; let blocEdition = bloc.getElementsByClassName("ontchat-edition")[0]; let formData = JSON.parse(blocEdition.getAttribute("data-form")); formData["message"] = textarea.value; formData["action"] = "post"; formData["token"] = document.getElementById('topic').dataset.token; let edition = bloc.getElementsByClassName("ontchat-edition")[0]; let id = bloc.getAttribute("ontchat-id"); let messageAnswer = bloc.getElementsByClassName("message answer")[0]; edition.classList.add("ontchat-disabled-form"); textarea.setAttribute("disabled", "true"); let timestamp = getTimestamp(); function onSuccess(res) { edition.classList.remove("ontchat-disabled-form"); if (res['reset_form']) { let reset = document.createElement("html"); reset.innerHTML = res["hidden_reset"]; let resetData = serializeForm(reset); for (let key in resetData) { formData[key] = resetData[key]; } blocEdition.setAttribute("data-form", JSON.stringify(formData)); } textarea.removeAttribute("disabled"); if (res && res.erreur && res.erreur.length > 0) { for (let err of res.erreur) { addAlertbox("danger", err); } return; } let dom = document; let message = getMessagesOnche(bloc); message.message_answer = messageAnswer; let divMessage = document.getElementsByClassName("message-content")[0].cloneNode(true); divMessage.innerHTML = res.message; message.content = divMessage; addMessages([message], true, timestamp, false); } function onError(err, _) { addAlertbox("danger", err); edition.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); } function onTimeout(err) { addAlertbox("warning", err); edition.classList.remove("ontchat-disabled-form"); textarea.removeAttribute("disabled"); } let url = `https://onche.org/message/edit/${id}`; request("POST", url, onSuccess, onError, onTimeout, makeFormData(formData), true, 20000, false); } function requestEdit(bloc) { if (!bloc.getElementsByClassName("ontchat-edition")[0].classList.contains("ontchat-hide")) { return; } let contentClasses = bloc.getElementsByClassName("ontchat-content")[0].classList; contentClasses.add("disabled-content"); contentClasses.remove("disabled-content"); let txtsub = bloc.getElementsByClassName("message-content"); let text = txtsub[txtsub.length - 1].cloneNode(true); cleanQuote(text); let txt = text.innerHTML.replace(/<br>/g, ""); let form = document.getElementsByTagName("form")[0]; let formData = serializeForm(form); let editionBloc = bloc.getElementsByClassName("ontchat-edition")[0]; editionBloc.setAttribute("data-form", JSON.stringify(formData)); let height = computeHeight(countLines(txt)); let isDown = isScrollDown(); bloc.getElementsByClassName("ontchat-edition-textarea")[0].value = txt; bloc.getElementsByClassName("ontchat-edition-textarea")[0].style["height"] = `${height}rem`; bloc.getElementsByClassName("ontchat-content")[0].classList.add("ontchat-hide"); editionBloc.classList.remove("ontchat-hide"); if (isDown) { setScrollDown(); } } function cleanQuote(text) { for (const child of text.childNodes) { if (child.tagName == "A") { const textNode = document.createTextNode(child.href); child.replaceWith(textNode); } else if (child.tagName == "DIV" && child.classList.contains("sticker")) { const textNode = document.createTextNode(child.getElementsByTagName("img")[0].getAttribute("title")); child.replaceWith(textNode); } else if (child.tagName == "DIV" && child.classList.contains("youtube")) { if (child.hasChildNodes()) { let textNode; if (child.getElementsByTagName("iframe")[0].src.includes("youtube")) textNode = document.createTextNode(youtubeURL(child.getElementsByTagName("iframe")[0].src)); else textNode = document.createTextNode(child.getElementsByTagName("iframe")[0].src); child.replaceWith(textNode); } } else if (child.tagName == "DIV" && child.classList.contains("_format _gif")) { const textNode = document.createTextNode(child.getElementsByTagName("img")[0].src); child.replaceWith(textNode); } } } function youtubeURL(url) { const match = url.match(/(?:embed\/|watch\?v=)([^&?]*)&?(t=(\d*))?/); const videoId = match[1]; const startTime = match[3]; return `https://www.youtube.com/watch?v=${videoId}${startTime ? `&t=${startTime}` : ''}`; } function requestDelete(bloc) { let contentClasses = bloc.getElementsByClassName("ontchat-content")[0].classList; contentClasses.add("disabled-content"); let id = parseInt(bloc.getAttribute("ontchat-id")); function onSuccess(res) { contentClasses.remove("disabled-content"); if (res && res.erreur && res.erreur.length > 0) { for (let err of res.erreur) { addAlertbox("danger", err); } return; } let [timestamp, edition, deleted] = lastEditionTime[id]; if (deleted === true) { return; } let isDown = isScrollDown(); if (!bloc.getElementsByClassName("ontchat-edition")[0].classList.contains("ontchat-hide")) { bloc.getElementsByClassName("ontchat-content")[0].classList.remove("ontchat-hide"); bloc.getElementsByClassName("ontchat-edition")[0].classList.add("ontchat-hide"); } bloc.closest(".ontchat-message").classList.add("ontchat-message-deleted"); lastEditionTime[id] = [timestamp, edition, true]; if (isDown) { setScrollDown(); } } function onError(err, _) { addAlertbox("danger", err); contentClasses.remove("disabled-content"); } function onTimeout(err) { addAlertbox("warning", err); contentClasses.remove("disabled-content"); } let token = document.getElementById('topic').dataset.token; let url = `https://onche.org/message/remove/${id}`; let deleteData = { token: token }; request("POST", url, onSuccess, onError, onTimeout, makeFormData(deleteData), true, 5000, false); } function countLines(text) { return text.split(/\r|\r\n|\n/|"<br>").length; } function computeHeight(lines) { return 1 * lines + 0.6; } function setTextareaHeight(plusOne) { let textarea = document.getElementsByClassName("textarea")[0]; if (!isReduced) { textarea.style["height"] = ""; return; } plusOne = !!plusOne; let lines = countLines(textarea.value); if (!plusOne && lines === 1) { textarea.style["height"] = ""; return; } if (plusOne) { lines += 1; } let height = computeHeight(lines); textarea.style["height"] = `${height}rem`; } function postMessageIfEnter(event) { if (isReduced && (event.which == 13 || event.keyCode == 13)) { if (event.shiftKey) { let isDown = isScrollDown(); setTextareaHeight(true); if (isDown) { setScrollDown(); } } else { // event.preventDefault(); // postMessage(); } } } function serializeForm(form) { // Useless actually, just use new FormData(form) let dict = {}; for (let select of form.getElementsByTagName("select")) { dict[select.name] = select.querySelector("option[selected]").value; } for (let input of form.getElementsByTagName("input")) { dict[input.name] = input.value; } for (let textarea of form.getElementsByTagName("textarea")) { dict[textarea.name] = textarea.value; } return dict; } function makeFormData(dict) { var formData = new FormData(); for (let key in dict) { formData.append(key, dict[key]); } return formData; } function getMessages(document) { let blocMessages = document.querySelectorAll(".message:not(.answer)"); let messages = []; for (let bloc of blocMessages) { messages.push(parseMessage(bloc)); } return messages; } function getMessagesOnche(doc) { let author = doc.getElementsByClassName("ontchat-author")[0].textContent.trim(); let avatar = doc.getElementsByClassName("ontchat-bloc-avatar")[0].getAttribute("data-avatar"); let dateString = doc.getElementsByClassName("message-date")[0].getAttribute("title"); let [dateCreated, dateEdited] = getOncheDate(dateString); let id = doc.getAttribute("ontchat-id"); return {author: author, avatar: avatar, dateString: dateString, date: dateCreated, edited: dateEdited, id: id}; } function getSondages(doc) { let sondage = doc.getElementsByClassName("poll")[0]; let arrayAnswers = {}; let numberVotes = 0; if (!!sondage) { let sondageAnswers = sondage.getElementsByClassName("poll-answer"); for (let i = 0; i < sondageAnswers.length; i++) { let answer = sondageAnswers[i]; arrayAnswers[answer.getAttribute("data-poll-answer")] = answer.getAttribute("data-percent"); } let sondageTitle = sondage.getElementsByTagName("h2")[0]; if (sondageTitle.textContent.length > 7){ numberVotes = +sondageTitle.textContent.match(/\d+/)[0]; } } return { answered : arrayAnswers, votes : numberVotes}; } function updateSondage(choix) { let sondage = document.getElementsByClassName("poll")[0]; if (choix.votes > 0) { sondage.getElementsByTagName("h2").textContent = `Sondage – ${choix.votes} votes`; document.getElementById("ontchat-sondage-votes").textContent = `(${choix.votes} votes)`; } else { sondage.getElementsByTagName("h2").textContent = `Sondage`; document.getElementById("ontchat-sondage-votes").textContent = ``; } let sondageAnswers = sondage.getElementsByClassName("poll-answer"); for (let i = 0; i < sondageAnswers.length; i++) { let answer = sondageAnswers[i]; if (choix.votes > 0) { answer.setAttribute("data-percent", choix.answered[answer.getAttribute("data-poll-answer")]); answer.setAttribute("style", `--percent: ${choix.answered[answer.getAttribute("data-poll-answer")]}%`); } else { answer.setAttribute("data-percent", ''); answer.setAttribute("style", "--percent: false%"); } } } function getOncheDate(date) { let textDate = date.toLocaleLowerCase(); if (textDate.includes("et modifié")) { let [created, edited] = textDate.split("et modifié"); created = parseDate(created); edited = edited.slice(4); [dateEdited, timeEdited] = edited.toLocaleLowerCase().split("à"); let [day, month, year] = dateEdited.trim().split("/"); let [hour, minute, second] = timeEdited.trim().split(":"); return [created, new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second))]; } created = parseDate(textDate); return [created, {}]; } function findDeletedMessages(res, requestTimestamp) { let page = getPage(res); let blocMessages = res.querySelectorAll('.message:not(.answer)'); let newIds = [] let newDates = []; for (let bloc of blocMessages) { let id = parseInt(bloc.getAttribute("data-id")); let date = bloc.getElementsByClassName("message-date")[0].getAttribute("title").trim(); newIds.push(id); newDates.push(date); } if (!messagesByPage.hasOwnProperty(page)) { messagesByPage[page] = [newIds, newDates]; return; } let [regIds, regDates] = messagesByPage[page]; let regLength = regIds.length; let newLength = newIds.length; messagesByPage[page] = [newIds, newDates]; for (let i = 0; i < newLength; i++) { let id = newIds[i]; if (!lastEditionTime.hasOwnProperty(id)) { continue; } let [timestamp, edition, deleted] = lastEditionTime[id]; // Message "ressuscité" (parfois bug, message peut disparaître) if (deleted) { let msg = document.querySelector(`.ontchat-message[ontchat-id="${id}"]`); if (msg) { msg.classList.remove("ontchat-message-deleted"); lastEditionTime[id] = [timestamp, edition, false]; } } } if (regLength === 0) { return; } if (regLength <= newLength && regIds[0] === newIds[0] && regIds[regLength - 1] === newIds[regLength - 1]) { return; } let after = new Set(newIds); let isFirst = true; for (let i = 0; i < regIds.length; i++) { let id = regIds[i]; if (after.has(id)) { isFirst = false; continue; } // Pas enregistré => blacklist if (!lastEditionTime.hasOwnProperty(id)) { continue; } let [timestamp, edition, _] = lastEditionTime[id]; if (timestamp >= requestTimestamp) { continue; } // Si message en début de page : vérifier qu'il n'est pas sur la page précédente // Vérifier aussi les début/fin de page en cas de PEMT, car 2 messages peuvent être "swap" if (isFirst || (regDates[i] === newDates[0]) || (newLength === 20 && regDates[i] === newDates[19])) { // checkDeleted(id); continue; } let msg = document.querySelector(`.ontchat-message[ontchat-id="${id}"]`); if (msg) { msg.classList.add("ontchat-message-deleted"); lastEditionTime[id] = [timestamp, edition, true]; } } } function formatDate(date) { let now = new Date(); try { now = new Date(now.toLocaleString('en-US', { timeZone: "Europe/Paris" })); } catch (e) { } let day = date.getDate(); let month = date.getMonth(); let year = date.getFullYear(); if (now.getDate() === day && now.getMonth() === month && now.getFullYear() === year) { return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${date.getSeconds().toString().padStart(2, "0")}`; } else { return `${day.toString().padStart(2, "0")}/${(month + 1).toString().padStart(2, "0")}/${year}`; } } function makeMessage(message) { let content = message.content; fixMessage(content); detectMosaic(content); improveImages(content); let message_answer_before = message.message_answer; let message_answer = ''; if (message_answer_before) { let dateAnswer = message_answer_before.getElementsByClassName("answer-date")[0].getAttribute("title"); message_answer_before.getElementsByClassName("answer-date")[0].textContent = formatDate(parseDateEdit(dateAnswer)); let quoteForAnswer = message_answer_before.getElementsByClassName("onchat-quoting")[0]; if (!quoteForAnswer) { quoteForAnswer = message_answer_before.getElementsByClassName("mdi mdi-share")[0]; } if (!quoteForAnswer.classList.contains("material-icons")) { quoteForAnswer.classList.add("material-icons" , "onchat-quoting"); quoteForAnswer.innerHTML = "format_quote"; } if (!quoteForAnswer.classList.contains("onchat-quoting")) { quoteForAnswer.classList.add("onchat-quoting"); } if (quoteForAnswer.classList.contains("mdi") && quoteForAnswer.classList.contains("mdi-share")) quoteForAnswer.classList.remove("mdi", "mdi-share"); message_answer = message_answer_before.outerHTML; } let id = message.id; let avatar = message.avatar; let toQuoteDate = message.dateString; let titleDate = message.dateString; let textDate = formatDate(message.date); if (message.edited !== undefined) { textDate += "*"; titleDate += ` (édité à ${message.edited})`; } let exists = avatar !== undefined; let author = exists ? message.author : `<i>${message.author}</i>`; let authorHref = exists ? `href="https://onche.org/profil/${author}"` : ""; let authorTitle = exists ? `title="Ouvrir le profil de ${author}"` : ""; let authorAvatarHidden = exists ? "" : "class='ontchat-hide-visibility'"; let editionSpan = '<span class="material-icons ontchat-edit ontchat-picto" title="Modifier"> edit </span>'; let deletionSpan = '<span class="material-icons ontchat-delete ontchat-picto" title="Supprimer"> delete </span>'; let deletion = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : deletionSpan; let edition = (currentUser.author === undefined) || (message.author.toLowerCase() !== currentUser.author.toLowerCase()) ? "" : editionSpan; let html = `<div class="ontchat-bloc-message"> <div class="ontchat-message" ontchat-id=${id}> <div> <a ${authorAvatarHidden} ${authorHref} target="_blank" ${authorTitle}> <div class="ontchat-bloc-avatar ontchat-rounded" style="background-image: url(${avatar})" data-avatar="${avatar}"></div> </a> </div> <div class="ontchat-bloc-author-content"> <div class="ontchat-toolbar"> <h5 class="ontchat-author">${author}</h5> <div class="ontchat-tooltip"> ${deletion} ${edition} <span class="material-icons ontchat-picto ontchat-quote picto-msg-quote" title="Citer">format_quote</span> <small class="ontchat-date message-date" to-quote="${toQuoteDate}" title="${titleDate}">${textDate}</small> </div> </div> <div class="ontchat-content">${message_answer}${content.outerHTML}</div> <div class="ontchat-edition ontchat-hide"> <textarea class="ontchat-edition-textarea ontchat-textarea"></textarea> <div class="ontchat-buttons"> <button tabindex="0" type="button" class='ontchat-edition-check icon-check-jv ontchat-button-top material-icons' title="Valider la modification">check_circle</button> <button tabindex="0" type="button" class='ontchat-edition-cancel icon-cancel-circle ontchat-button-bottom material-icons' title="Annuler la modification">cancel</button> </div> </div> </div> </div> <hr class="ontchat-ruler"> </div>`; return html; } function parseDate(string) { let [date, time] = string.toLowerCase().split("à"); date = date.slice(10); let [day, month, year] = date.trim().split("/"); let [hour, minute, second] = time.trim().split(":"); return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second)); } function parseDateEdit(string) { let [date, time] = string.toLowerCase().split("à"); let [string_day, day, month, year] = date.trim().split(" "); let [hour, minute, second] = time.trim().split(":"); let monthIndex = ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"].indexOf(month.trim().toLowerCase()); return new Date(parseInt(year), monthIndex, parseInt(day), parseInt(hour), parseInt(minute), parseInt(second)); } function addMessages(messages, editing, requestTimestamp) { let main = document.getElementById("ontchat-main"); let hasNewMessages = false; let init = true; let toInsert = ""; let newMessagesIds = []; for (let message of messages) { let date = message.date; let id = message.id; if (init === true && !editing) { init = false; let now = new Date(); let delta = now - date; if (delta > 5 * 60 * 1000 + checkEditedInterval) { shouldCheckEdited = false; } else { shouldCheckEdited = true; } } if (message.blacklisted) { continue; } if (firstMessageId === undefined) { firstMessageId = id; firstMessageDate = date; } // 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 if (id < firstMessageId && date < firstMessageDate) { continue; } let referenced = lastEditionTime.hasOwnProperty(id); let edited = message.edited; if (referenced) { let [timestamp, edition, deleted] = lastEditionTime[id]; if (deleted) { continue; } if (timestamp >= requestTimestamp || edition === edited) { continue; } } let newBloc = makeMessage(message); lastEditionTime[id] = [requestTimestamp, edited, false]; if (referenced) { let selector = `.ontchat-message[ontchat-id="${id}"]`; let oldBloc = main.querySelector(selector).closest(".ontchat-bloc-message"); let isDown = isScrollDown(); oldBloc.outerHTML = newBloc; if (isDown) { setScrollDown(); } let event = new CustomEvent('ontchat:newmessage', { 'detail': { id: id, isEdit: true } }); dispatchEvent(event); continue; } hasNewMessages = true; if (nbNewMessage === 0 && document.hidden) { let hrs = document.getElementsByClassName("ontchat-ruler"); let lastHr = hrs[hrs.length - 1]; lastHr.setAttribute("id", "ontchat-ruler-new"); } toInsert += newBloc; newMessagesIds.push(id); nbNewMessage++; } if (toInsert !== "") { let isDown = isScrollDown(); main.insertAdjacentHTML("beforeend", toInsert); if (isDown) { setScrollDown(); } } if (editing) { return; } if (isScrollDown()) { let blocMessages = main.getElementsByClassName("ontchat-bloc-message"); let nb = blocMessages.length; if (nb > 100) { for (let i = 0; i < nb - 100; i++) { main.removeChild(blocMessages[0]); } setScrollDown(); } } if (hasNewMessages) { if (!turboActivated && !refreshDegraded) { decreaseUpdateInterval(); } if (document.hidden) { setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage); if (configuration["play_sound"]) { ringBell.pause(); ringBell.currentTime = 0; ringBell.play(); } } for (let newMessageId of newMessagesIds) { let event = new CustomEvent('ontchat:newmessage', { 'detail': { id: newMessageId, isEdit: false } }); dispatchEvent(event); } } else { if (!turboActivated && !refreshDegraded) { increaseUpdateInterval(); } } } function parseSondage() { let sondage = document.getElementsByClassName("poll")[0]; if (!sondage) return null; let choix = sondage.getElementsByClassName("poll-answer"); let results = {}; let numberVotes = 0; let sondageTitle = sondage.getElementsByTagName("h2")[0]; if (sondageTitle.textContent.length > 7){ for (let i = 0; i < choix.length; i++) { let answer = choix[i]; results[answer.getAttribute("data-poll-answer")] = { name: answer.getElementsByTagName("span").textContent, percent: answer.getAttribute("data-percent")}; } numberVotes = +sondageTitle.textContent.match(/\d+/)[0]; } else { for (let i = 0; i < choix.length; i++) { let answer = choix[i]; results[answer.getAttribute("data-poll-answer")] = { name: answer.getElementsByTagName("span").textContent, percent: null}; } } return { answered : results, numberVotes : numberVotes}; } function setUser(document, user) { let isConnected = (user.author !== undefined); if (isConnected) { if (user.author !== currentUser.author) { let pseudo = document.getElementById("ontchat-user-pseudo"); pseudo.innerHTML = user.author; let avatarLink = document.getElementById("ontchat-user-avatar-link"); avatarLink.setAttribute("href", `https://onche.org/account/profil`); } if (user.avatar !== currentUser.avatar) { let avatar = document.getElementById("ontchat-user-avatar"); avatar.style["background-image"] = `url("${user.avatar}")`; } if (user.mp !== currentUser.mp) { let mp = document.getElementById("ontchat-user-mp"); mp.setAttribute("data-val", user.mp); if (user.mp > 0) { mp.classList.add("has-notif"); } else { mp.classList.remove("has-notif"); } } } if ((userConnected === undefined && isConnected) || (userConnected !== undefined && isConnected !== userConnected)) { document.getElementById("ontchat-profil").classList.toggle("ontchat-hide"); let isDown = isScrollDown(); document.getElementsByClassName("bloc insert-image")[0].classList.toggle("ontchat-hide"); if (isDown) { setScrollDown(); } } if (userConnected !== undefined) { if (isConnected && !userConnected) { addAlertbox("success", "Vous êtes désormais connecté"); } else if (!isConnected && userConnected) { addAlertbox("warning", "Vous avez été déconnecté"); } } userConnected = isConnected; currentUser = user; } function setTopicTitle(document, topicTitle) { if (topicTitle !== currentTopicTitle) { currentTopicTitle = topicTitle; document.getElementById("ontchat-topic-title").innerHTML = escape(topicTitle); } } function setTopicNbConnected(document, nbConnected) { let txt = `${nbConnected} connectés`; if (!(nbConnected > 1)) { if (nbConnected === undefined) { txt = "? connectés"; } else { txt = txt.slice(0, -1); } } document.getElementById("ontchat-topic-nb-connected").innerHTML = txt; } function setTopicNbMessages(document, nbMessages) { let txt = `${nbMessages} messages`; if (!(nbMessages > 1)) { if (nbMessages === undefined) { txt = "? messages"; } else { txt = txt.slice(0, -1); } } document.getElementById("ontchat-topic-nb-messages").innerHTML = txt; if (nbMessages !== undefined) { topicNbMessages = nbMessages; } } function triggerontchat() { // TamperMonkey / Chrome bug: https://github.com/Tampermonkey/tampermonkey/issues/705#issuecomment-493895776 let link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = 'https://fonts.googleapis.com/icon?family=Material+Icons'; document.head.appendChild(link); freshForm = getForm(document); favicon = makeFavicon(); let topicUrl = document.URL; let topic = parseTopicInfo(document); let user = parseUserInfo(document); urlToFetch = parseURL(topicUrl); urlToFetch.page = 1; urlToFetch.anchor = ""; urlToRefreshInfos = parseURL(topicUrl); urlToRefreshInfos.page = 1; urlToRefreshInfos.anchor = ""; urlToCheckEdited = parseURL(topicUrl); urlToCheckEdited.page = 1; urlToCheckEdited.anchor = ""; configuration = defaultConfig(); loadConfig(); ringBell = new Audio(configuration["sound"]); clearPage(document); setUser(document, user); setTopicTitle(document, topic.title); setTopicNbMessages(document, undefined); setTopicNbConnected(document, topic.connected); document.getElementById("ontchat-topic-title").setAttribute("href", buildURL(urlToFetch)); let forum = getForum(document); let forumSide = document.getElementById("ontchat-forum-title"); forumSide.setAttribute("href", forum.href); forumSide.innerHTML = escape(forum.title); let defaultReduced = configuration["default_reduced"]; let messageTopic = document.getElementsByClassName("ontchat-textarea")[0]; if (messageTopic && (defaultReduced === false || (messageTopic.value !== ""))) { toggleTextarea(); } let event = new CustomEvent('ontchat:activation'); dispatchEvent(event); let page = topic.lastPage > 1 ? topic.lastPage - 1 : topic.lastPage; updateMessages(page, true); setInterval(tryCatch(checkEdited), checkEditedInterval); } function refreshNoLongerDegraded() { removeDegradedRefreshWarning(); timeoutedDates = []; refreshDegraded = false; refreshDegradedTimeoutId = -1; } function scheduleDegradedRefreshWarning() { if (!refreshDegraded) { let now = getTimestamp(); let lookupDate = now - 60 * 1000; let nbClean = 0; for (let date of timeoutedDates) { if (date < lookupDate) { nbClean++; } else { break; } } for (i = 0; i < nbClean; i++) { timeoutedDates.shift(); } timeoutedDates.push(now); if (timeoutedDates.length >= 3) { refreshDegraded = true; updateIntervalIdx = 2; setDegradedRefreshWarning(); } else { return; } } if (refreshDegradedTimeoutId !== -1) { clearTimeout(refreshDegradedTimeoutId); } refreshDegradedTimeoutId = setTimeout(tryCatch(refreshNoLongerDegraded), 30000); } function updateMessages(page, goToLast) { if (postingMessage && turboActivated) { // Postpone message fetching, posting the message is priorized fetchingMessages = false; currentTimeoutId = setTimeout(tryCatch(function postponedUpdate() { updateMessages(page, goToLast); }), 100); return; } let timestamp = getTimestamp(); function scheduleNextUpdate(interval, p, goLast) { fetchingMessages = false; currentTimeoutId = setTimeout(tryCatch(function scheduledUpdate() { updateMessages(p, goLast); }), interval); }; function onSuccess(res) { let parsed = parsePage(res, timestamp); let lastPage = parsed.lastPage; let currPage = parsed.page; let interval = turboActivated ? configuration["turbo_delay"] : updateIntervals[updateIntervalIdx] * 1000; if (page < lastPage && goToLast) { updateMessages(page + 1, true); } else if (currPage < page || parsed.nbMessagesPage === 0) { // Bug des messages supprimés scheduleNextUpdate(interval, page - 1, false); } else if (page > lastPage) { updateMessages(lastPage, true); } else { scheduleNextUpdate(interval, page, true); } } function onSuccessSondage(res) { parseSondage(res); } function onError(err, code) { if (code === 0) { scheduleDegradedRefreshWarning(); scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 10000, page, true); return } if (!isError) { isError = true; setFixedAlert("danger", err); } scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 60000, page, true); } function onTimeout(_) { scheduleDegradedRefreshWarning(); scheduleNextUpdate(turboActivated ? configuration["turbo_delay"] : 5000, page, true); } let timeout = 10000;; if (turboActivated) { timeout = 5000; } fetchingMessages = true; currentFetchedPage = page; urlToFetch.page = page; let urlLastPage = buildURL(urlToFetch); if (counterSondage > 3) { counterSondage = 0; let urlFirstPage = urlLastPage.replace(/\d+(?=[^/]*$)/, '1'); request("GET", urlFirstPage, onSuccessSondage, onError, onTimeout, undefined, false, 20000); } counterSondage++; request("GET", urlLastPage, onSuccess, onError, onTimeout, undefined, false, timeout, turboActivated); } function checkEdited() { if (!shouldCheckEdited || currentFetchedPage === 1 || isError) { return; } urlToCheckEdited.page = currentFetchedPage - 1; let urlPrevLastPage = buildURL(urlToCheckEdited); let timestamp = getTimestamp(); function onSuccess(res) { let newMessages = []; let edited = res.getElementsByClassName("edited"); for (let msg of edited) { let bloc = msg.closest(".message"); newMessages.push(parseMessage(bloc)); } addMessages(newMessages, true, timestamp, false); findDeletedMessages(res, timestamp); } function onError(_, _) { } function onTimeout(_) { } request("GET", urlPrevLastPage, onSuccess, onError, onTimeout, undefined, false, 20000); } function checkDeleted(id) { let url = `https://www.jeuxvideo.com/ontchat/forums/message/${id}`; let requestTimestamp = getTimestamp(); function onSuccess(_) { // Le message existe, il a disparu de la page car un message plus ancien a été supprimé } function onError(_, status) { let [timestamp, edition, deleted] = lastEditionTime[id]; if (status === 410 && !deleted) { if (timestamp >= requestTimestamp) { return; } let msg = document.querySelector(`.ontchat-message[ontchat-id="${id}"]`); if (msg) { msg.classList.add("ontchat-message-deleted"); lastEditionTime[id] = [timestamp, edition, true]; } } } function onTimeout(_) { } request("GET", url, onSuccess, onError, onTimeout, undefined, false, 20000, false); } function parseAlerts(res) { let alerts = []; let alertsDiv = res.getElementsByClassName("alert"); for (let a of alertsDiv) { let type = "danger"; if (a.classList.contains("alert-warning")) { type = "warning"; } else if (a.classList.contains("alert-success")) { type = "success"; } for (let p of a.getElementsByTagName("p")) { let message = p.textContent.trim(); alerts.push({ type: type, message: message }); } } return alerts; } function increaseUpdateInterval() { if (updateIntervalIdx < updateIntervalMax) { updateIntervalIdx++; } } function decreaseUpdateInterval() { updateIntervalIdx = transisitions[updateIntervalIdx]; } function parsePage(res, requestTimestamp) { let error = getTopicError(res); if (error !== undefined) { if (!isError) { updateIntervalIdx = updateIntervalMax; isError = true; setFixedAlert("danger", error); } return { lastPage: undefined, page: undefined, alert: true, nbMessagesPage: 0 } } if (isError) { isError = false; updateIntervalIdx = 2; removeFixedAlert("Le topic ne retourne plus d'erreur"); } let form = getForm(res); if (form !== undefined) { freshForm = form; } let messages = getMessages(res); addMessages(messages, false, requestTimestamp, false); let user = parseUserInfo(res); setUser(document, user); let topic = parseTopicInfo(res); findDeletedMessages(res, requestTimestamp); let nbMessages = (topic.lastPage - 1) * 20; if (topic.page === topic.lastPage) { nbMessages += messages.length; } if (topic.page === topic.lastPage || nbMessages > topicNbMessages) { setTopicNbMessages(document, nbMessages); } setTopicNbConnected(document, topic.connected); let alerts = parseAlerts(res); for (let alert of alerts) { addAlertbox(alert.type, alert.message); } let locked = getTopicLocked(res); let isLocked_ = (locked !== undefined); if (isLocked_ && !isLocked) { updateIntervalIdx = updateIntervalMax; setFixedAlert("warning", locked); } else if (!isLocked_ && isLocked) { updateIntervalIdx = 0; removeFixedAlert("Le topic a été dévérouillé"); } isLocked = isLocked_; return { page: topic.page, lastPage: topic.lastPage, nbMessagesPage: messages.length, alert: isLocked_ || (alerts.length > 0) }; } function parseSondage(res) { let sondage = document.getElementsByClassName("poll")[0]; if (!!sondage) { let sondageAnswer = getSondages(res); updateSondage(sondageAnswer); } } function addAlertbox(type, message) { // type: success / warning / danger let alertsSuccess = document.getElementsByClassName('alert alert-success'); if (type == 'success' && alertsSuccess.length > 0) { return; } let alert = `<div class="alert alert-${type}"> <button class="material-icons close ontchat-alert-close" aria-hidden="true" data-dismiss="alert" type="button">close</button> <div class="alert-row">${escape(message)}</div> </div>`; document.getElementById("ontchat-fixed-alert").insertAdjacentHTML("afterend", alert); } function setFixedAlert(type, message) { setFavicon("⨯"); if (configuration["hide_alerts"]) { addAlertbox(type, message); return } document.getElementById("ontchat-fixed-alert").getElementsByClassName("alert-row")[0].innerHTML = escape(message); document.getElementById("ontchat-fixed-alert").setAttribute("class", `alert alert-${type}`); } function removeFixedAlert(message) { document.getElementById("ontchat-fixed-alert").classList.add("ontchat-hide"); if (message !== undefined) { addAlertbox("success", message); } if (document.hidden && nbNewMessage > 0) { setFavicon(nbNewMessage > 99 ? 99 : nbNewMessage); } else { setFavicon(""); } } function setTurboWarning() { let message = "Le mode turbo est resté activé pendant plus d'une minute, les requêtes pour récupérer les nouveaux messages risquent d'être ralenties"; document.getElementById("ontchat-turbo-warning").getElementsByClassName("alert-row")[0].innerHTML = message; document.getElementById("ontchat-turbo-warning").setAttribute("class", "alert alert-warning"); } function removeTurboWarning() { document.getElementById("ontchat-turbo-warning").classList.add("ontchat-hide"); } function setDegradedRefreshWarning() { let message = "Les serveurs d'Onche semblent surchargés, l'actualisation des nouveaux messages peut s'en voir dégradée"; document.getElementById("ontchat-degraded-refresh-warning").getElementsByClassName("alert-row")[0].innerHTML = message; document.getElementById("ontchat-degraded-refresh-warning").setAttribute("class", "alert alert-warning"); } function removeDegradedRefreshWarning() { document.getElementById("ontchat-degraded-refresh-warning").classList.add("ontchat-hide"); } function makeontchatButton() { let cls = 'btn-ontchat'; let text = 'OnTchat'; let btn = `<button class="btn btn-actu-new-list-forum ${cls}">${text}</button>`; return btn; } function addontchatButton(document) { let fontColor = getStyle(document.getElementsByTagName("h1")[0], "color"); let css = `<style type="text/css"> #forum-main-col .bloc-pre-pagi-forum { display: flex; } #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right { position: relative; right: unset; left: unset; top: unset; bottom: unset; overflow: hidden; display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: auto; flex: 1; } #forum-main-col .bloc-pre-pagi-forum .bloc-pre-right button { float: right; min-width: 5.25rem; margin-left: 0.3125rem; } .btn-ontchat { background-color: inherit; border-radius: 4px; height: 1.75rem; border-width: thin; border-style: ridge; padding: 0.1875rem 1rem; color: ${fontColor}; border-color: ${fontColor}; cursor: pointer; margin-right: 1rem; } </style>` document.head.insertAdjacentHTML("beforeend", css); let blocPreRight = document.getElementsByClassName("bloc")[0].getElementsByClassName("right")[0]; let ontchatButton = makeontchatButton(); blocPreRight.insertAdjacentHTML('afterbegin', ontchatButton); } function bindontchatButton(document) { let buttons = document.getElementsByClassName('btn-ontchat'); for (let btn of buttons) { btn.addEventListener('click', tryCatch(triggerontchat)); } } function getStyle(el,styleProp) { if (el.currentStyle) return el.currentStyle[styleProp]; return document.defaultView.getComputedStyle(el,null)[styleProp]; } function request(mode, url, callbackSuccess, callbackError, callbackTimeout, data, json, timeout, nocache) { json = !!json; let xhr = new XMLHttpRequest(); xhr.timeout = timeout; xhr.ontimeout = tryCatch(function xhrOnTimeout() { callbackTimeout(`La délai d'attente de la requête a expiré`); }); xhr.onerror = tryCatch(function xhrOnError() { callbackError(`La requête a échoué (${xhr.status}): ${xhr.statusText}`, xhr.status); }); xhr.onabort = tryCatch(function xhrOnAbort() { if (!leavingTopic) { callbackTimeout(`La requête a été interrompue pour une raison inconnue`); } }); xhr.onload = tryCatch(function xhrOnLoad() { if (xhr.status !== 200) { callbackError(`La requête a retourné une erreur (${xhr.status}): ${xhr.statusText}`, xhr.status); return; } callbackSuccess(xhr.response); }); if (data === undefined) { data = null; } if (json) { xhr.responseType = "json"; } else { xhr.responseType = "document"; } xhr.open(mode, url, true); if (nocache) { xhr.setRequestHeader("Cache-Control", "no-cache, no-store, must-revalidate"); } xhr.send(data); }; // On copie/colle le code de TopicLive et on se sent développeur :) function makeFavicon() { let canvas = document.createElement("canvas"); canvas.width = 16; canvas.height = 16; let context = canvas.getContext('2d'); let image = new Image(); image.onload = function () { faviconLoaded = true; setFavicon(faviconTextWhenLoaded); } image.src = 'data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAMASURBVDhPZVJbSFRRFF3n3rkz4+TkOPlIkZSxDDUzKQXxmalBUElERPTAj/CrPqKfso9+Koion0KwfoKQRIwQLMxHTokpWiJiKWo+Rs3n5DPnOnfubd8zalQL7jln77P3OvuuvRkInteRWQC7C4ZUMk3QaNVv/t11aJBp7aRDqblo0snk6ohsuqwnp5HfU3D/hIKeUS/cq/6smFCGnEQjzMZNFg6FyAqYXBXeQkaGnlj5yYsZIQKJiZE4EG+H3UbFMBED4zIanCOwLvTjfJYBwh+eNia/DFund6WyJhWHT2ZiryPIf8UYVGkbNNHktwmuiWVUPK3D9SMemCTOogjMp0rNPetIzDy0lawJBvhMtq3khSUZVTX9mJ3/hZJrx/GoUQJ8KijXIKiKis9zdmSlhvPgvuEVPK4YwrBrmds6Ai0S8nOi4ZEVPHvRjcIzeajpoMJVFcLotAJHwi4eOD3nQUO7GyUXUxAWYuE+Hbo+V282orN7CmeL4uGj1wfUaGheIugeUZAcv4MH1jaPo/hcEi5dqUVsWjnm5te4f3FZRm39EN42DiMq0oqUpHAkpcWhd0yBoBDLZo9VjcFsMmCPIxhxsXaYzSL3h9gD0P2+GJXlJ7itY39CKHqIgHXdCtC+haTh1FEqiURTjYEbIX7xbNtN8JJOPxc8f/3W9OwqPj55DiGahO/78p07mU/vqI+fdbjGl/CueQT19AXbzBtePz60juFgFINgEVXEC1Nwtk+RW4Mok/obJElUZmFuDI7lOyAZBO7T4aZqBp3tiLFpECTSsmA34KxuhevHKk8WPYtgij7y/2PEtYiHt1/h8r4VmAVNYeoDqcWnahmTixrKugKQfTodeekRPFgfKM0QQLuErwNu1L3pBRvqwYVkHyK2M4gCa2PqfTGbKq8nEuPMCtA0qKF31QqLPQhMFKB4ZHjcS4ixrCHXwbDTClhJDpExhZpWwBuo3ROyab1Dg5W65tVMy6QlDR0fIP3XzTS5NIwwGehVhnVqewdJXspuqM7fCoY2RzEU22EAAAAASUVORK5CYII='; return { canvas: canvas, context: context, image: image }; }; function setFavicon(txt) { if (!faviconLoaded) { faviconTextWhenLoaded = txt; return; } let fav = document.getElementById("ontchat-favicon"); if (fav) { fav.parentElement.removeChild(fav); } favicon.context.clearRect(0, 0, favicon.canvas.width, favicon.canvas.height); favicon.context.drawImage(favicon.image, 0, 0); if (txt !== '') { let context = favicon.context; context.fillStyle = 'DodgerBlue'; context.fillRect(0, 0, context.measureText(txt).width + 3, 11); context.fillStyle = 'white'; context.font = 'bold 10px Verdana'; context.textBaseline = 'bottom'; context.fillText(txt, 1, 11); } let url = favicon.canvas.toDataURL('image/png'); let icon = `<link id="ontchat-favicon" rel="shortcut icon" type="image/png" href="${url}">`; document.head.insertAdjacentHTML("beforeend", icon); } function reverseMessage(node, isInit, isUl) { let quote = ""; let prevIsP = false; let startsWithSpoil = false; for (let child of node.childNodes) { let name = child.nodeName; switch (name) { case "P": { quote += reverseMessage(child) + "\n\n"; break; } case "STRONG": { quote += "'''" + reverseMessage(child) + "'''"; break; } case "U": { quote += "<u>" + reverseMessage(child) + "</u>"; break; } case "S": { quote += "<s>" + reverseMessage(child) + "</s>"; break; } case "EM": { quote += "''" + reverseMessage(child) + "''"; break; } case "BR": { quote += "\n"; break; } case "UL": { quote += reverseMessage(child, false, true) + "\n\n"; break; } case "OL": { quote += reverseMessage(child, false, false) + "\n\n"; break; } case "LI": { if (isUl === true) { quote += "* " + reverseMessage(child) + "\n"; } else { quote += "# " + reverseMessage(child) + "\n"; } break; } case "DIV": { let classList = child.classList; if (classList.contains("bloc-spoil-jv")) { if (quote === "") { startsWithSpoil = true; } quote += "<spoil>" + reverseMessage(child) + "</spoil>\n\n" } else if (classList.contains("contenu-spoil")) { quote += reverseMessage(child); } break; } case "SPAN": { let classList = child.classList; if (classList.contains("bloc-spoil-jv")) { quote += "<spoil>" + reverseMessage(child) + "</spoil>"; } else if (classList.contains("contenu-spoil")) { quote += reverseMessage(child); } break; } case "LABEL": { break; } case "INPUT": { break; } case "IMG": { quote += child.alt; break; } case "A": { if (child.href) { quote += child.href; } else { quote += reverseMessage(child); } break; } case "PRE": { quote += reverseMessage(child) + "\n\n"; break; } case "CODE": { quote += "<code>" + child.textContent + "</code>"; break; } case "BLOCKQUOTE": { if (prevIsP) { quote = quote.trimEnd() + "\n" + reverseMessage(child).replace(/^/gm, '> ') + "\n\n"; } else { quote += reverseMessage(child).replace(/^/gm, '> ') + "\n\n"; } break; } case "#text": { // The "isInit" check is to prevent the empty text surroudning message // However, it may happen that the root node contains valid text child, so it need to be added somehow // For some reason, an "new line" may be missing in this case, so just add it if (!isInit || child.textContent.trim() !== "") { quote += child.textContent; if (isInit && !quote.endsWith("\n")) { quote += "\n"; } } break; } default: { break; } } if (name == "P") { prevIsP = true; } else { prevIsP = false; } } quote = quote.replace(/(\n){3,}/g, '\n\n'); if (startsWithSpoil && isInit) { quote = "\n" + quote.trimEnd(); } else { quote = quote.trim(); } if (isInit) { quote = quote.replace(/^/gm, '> '); } return quote; } function reverseQuote(blocMessage) { let author_name = blocMessage.getElementsByClassName("ontchat-author")[0].textContent.trim(); let author_avatar = blocMessage.getElementsByClassName("ontchat-bloc-avatar")[0].getAttribute("data-avatar"); let messageLast = blocMessage.getElementsByClassName("message-content"); let message = messageLast[messageLast.length - 1].innerHTML; let data_id = blocMessage.getAttribute('ontchat-id'); return {author_name: author_name, author_avatar: author_avatar, message: message, data_id: data_id}; } function insertTextareaAnswer(textToInsert) { let answer = document.getElementById("answer"); if (answer.innerHTML != "") { answer.innerHTML = ""; } let textInsert = ` <div class="message small"> <div class="message-top"> <img class="avatar" alt="${textToInsert.author_name}" src="${textToInsert.author_avatar}"> <div class="message-infos"> <div class="message-username">${textToInsert.author_name}</div> </div> <div class="right"> <div class="mdi mdi-close" data-message-close></div> </div> </div> <div class="message-content rmjs-3"> ${textToInsert.message} </div> </div> <input type="hidden" name="answer" value="${textToInsert.data_id}"> `; answer.insertAdjacentHTML('beforeend', textInsert); } function dontScrollOnExpand(event) { let target = event.target; if (!target) { return; } let classes = target.classList; if (classes.contains("nested-quote-toggle-box")) { let isDown = isScrollDown(); let blockQuote = target.closest(".blockquote-jv"); let visible = blockQuote.getAttribute("data-visible"); let value = visible === "1" ? "" : "1"; blockQuote.setAttribute('data-visible', value); if (isDown) { setScrollDown(); } } else if (classes.contains("txt-spoil") || classes.contains("aff-spoil") || classes.contains("masq-spoil")) { event.preventDefault(); let check = target.closest(".bloc-spoil-jv").getElementsByClassName("open-spoil")[0]; let isDown = isScrollDown(); check.checked = !check.checked; if (isDown) { setScrollDown(); } } else if (classes.contains("ontchat-quote")) { let bloc = target.closest(".ontchat-message"); let quote = reverseQuote(bloc); let textarea = document.getElementsByClassName("textarea")[0]; insertTextareaAnswer(quote); textarea.focus(); } else if (classes.contains("ontchat-edit")) { let bloc = target.closest(".ontchat-message"); requestEdit(bloc); } else if (classes.contains("ontchat-delete")) { let bloc = target.closest(".ontchat-message"); event.stopPropagation(); requestDelete(bloc); } else if (classes.contains("ontchat-edition-check")) { let bloc = target.closest(".ontchat-message"); editMessage(bloc); } else if (classes.contains("ontchat-edition-cancel")) { let bloc = target.closest(".ontchat-message"); let isDown = isScrollDown(); bloc.getElementsByClassName("ontchat-content")[0].classList.remove("ontchat-hide"); bloc.getElementsByClassName("ontchat-edition")[0].classList.add("ontchat-hide"); if (isDown) { setScrollDown(); } } } function isScrollDown() { let element = document.getElementById("ontchat-main"); return element.clientHeight + Math.floor(element.scrollTop) >= element.scrollHeight - 100; } function setScrollDown() { setTimeout(() => { let element = document.getElementById("ontchat-main"); element.scrollTop = element.scrollHeight + 10000; }, 50); } function main() { addontchatButton(document); bindontchatButton(document); } main();