<commit_before>var Chat = {
    left : null,
    right: null,
    room: null,
    date: null,
    currentDate: null,
    lastScroll: null,
    lastHeight: null,
    edit: false,

    // Chat state
    state: null,
    since: null,

    sendMessage: function(jid, muc)
    {
        var n = document.querySelector('#chat_textarea');
        var text = n.value;
        n.value = "";
        n.focus();
        MovimUtils.textareaAutoheight(n);

        localStorage.removeItem(n.dataset.jid + '_message');

        if(Chat.edit) {
            Chat.edit = false;
            Chat_ajaxCorrect(jid, encodeURIComponent(text));
        } else {
            Chat_ajaxSendMessage(jid, encodeURIComponent(text), muc);
        }
    },

    focus: function(jid)
    {
        if(jid) {
            document.querySelector('#chat_widget').dataset.jid = jid;
        }

        var textarea = document.querySelector('#chat_textarea');

        setTimeout(function() {
            var textarea = document.querySelector('#chat_textarea');
            textarea.value = localStorage.getItem(textarea.dataset.jid + '_message');
        }, 0); // Fix Me

        textarea.onkeydown = function(event) {
            if(event.keyCode == 38 && this.value == '') {
                Chat_ajaxLast(this.dataset.jid);
            } else if(event.keyCode == 40
            && (this.value == '' || Chat.edit == true)) {
                Chat.clearReplace();
            }
        };

        textarea.onkeypress = function(event) {
            if(event.keyCode == 13) {
                if(event.shiftKey) {
                    return;
                }
                Chat.state = 0;
                Chat.sendMessage(this.dataset.jid, Boolean(this.dataset.muc));

                return false;
            } else if(!Boolean(this.dataset.muc)) {
                if(Chat.state == 0 || Chat.state == 2) {
                    Chat.state = 1;
                    Chat_ajaxSendComposing(this.dataset.jid);
                    Chat.since = new Date().getTime();
                }
            }
        };

        textarea.onkeyup = function(event) {
            localStorage.setItem(this.dataset.jid + '_message', this.value);

            setTimeout(function()
            {
                var textarea = document.querySelector('#chat_textarea');

                if(textarea
                && !Boolean(textarea.dataset.muc)
                && Chat.state == 1
                && Chat.since + 5000 < new Date().getTime()) {
                    Chat.state = 2;
                    Chat_ajaxSendPaused(textarea.dataset.jid);
                }
            },5000);

            Chat.toggleAction(this.value.length);
        };

        textarea.oninput = function() {
            MovimUtils.textareaAutoheight(this);
        };

        if(document.documentElement.clientWidth > 1024) {
            document.querySelector('#chat_textarea').focus();
        }
    },
    setTextarea: function(value)
    {
        Chat.edit = true;
        var textarea = document.querySelector('#chat_textarea');
        textarea.value = value;
        MovimUtils.textareaAutoheight(textarea);

    },
    clearReplace: function()
    {
        Chat.edit = false;
        var textarea = document.querySelector('#chat_textarea');
        textarea.value = '';
        MovimUtils.textareaAutoheight(textarea);
    },
    notify : function(title, body, image)
    {
        if(document_focus == false) {
            movim_title_inc();
            movim_desktop_notification(title, body, image);
        }
    },
    empty : function()
    {
        Chat_ajaxGet();
    },
    setBubbles : function(left, right, room, date) {
        var div = document.createElement('div');

        div.innerHTML = left;
        Chat.left = div.firstChild.cloneNode(true);
        div.innerHTML = right;
        Chat.right = div.firstChild.cloneNode(true);
        div.innerHTML = room;
        Chat.room = div.firstChild.cloneNode(true);
        div.innerHTML = date;
        Chat.date = div.firstChild.cloneNode(true);

        Chat.setScrollBehaviour();
    },
    setScrollBehaviour : function() {
        var discussion = document.querySelector('#chat_widget div.contained');
        discussion.onscroll = function() {
            if(discussion.dataset.muc != true) {
                if(this.scrollTop < 1) {
                    var chat = document.querySelector('#chat_widget');
                    Chat_ajaxGetHistory(chat.dataset.jid, Chat.currentDate);
                }
            }
            Chat.lastHeight = this.clientHeight;
        };
    },
    appendMessagesWrapper : function(page, prepend) {
        Chat.currentDate = null;
        if(page) {
            var scrolled = MovimTpl.isPanelScrolled();

            var discussion = document.querySelector('#chat_widget div.contained');

            if(discussion == null) return;

            Chat.lastScroll = discussion.scrollHeight;

            for(date in page) {
                if (page[date].constructor == Array) {
                    for(id in page[date]) {
                        Chat.appendMucMessage(page[date][id]);
                    }
                } else {
                    for(speakertime in page[date]) {
                        if(!Chat.currentDate) {
                            Chat.currentDate = page[date][speakertime].published;
                        }
                        Chat.appendMessage(speakertime, page[date][speakertime], prepend);
                    }
                }

                if(date != '') {
                    Chat.appendDate(date, prepend);
                }
            }

            // Only scroll down if scroll was at the bottom before the new msg
            // => don't scroll if the user was reading previous messages
            if(scrolled && prepend !== true) {
                setTimeout(function() {
                    MovimTpl.scrollPanel();
                }, 20);
            }

            if(prepend) {
                // And we scroll where we were
                var scrollDiff = discussion.scrollHeight - Chat.lastScroll;
                discussion.scrollTop += scrollDiff;
                Chat.lastScroll = discussion.scrollHeight;
            }
        }
    },
    appendMucMessage : function(message) {
        var conversation = document.getElementById(
            MovimUtils.cleanupId(message.jidfrom + '_conversation')
        );
        //datebox = Chat.room.cloneNode(true);
        //datebox.innerHTML = date;

        //if(conversation) {
        //    conversation.appendChild(datebox);
        //}

        bubble = Chat.room.cloneNode(true);

        var p = bubble.querySelector('p.message');

        if(message.body.match(/^\/me/)) {
            p.classList.add('quote');
            message.body = message.body.substr(4);
        }

        if (message.quoted) {
            p.classList.add('quoted');
        }

        /*if (message.sticker != null) {
            MovimUtils.addClass(bubble.querySelector('p.message'), 'sticker');
            bubble.querySelector('p.message').appendChild(Chat.getStickerHtml(message.sticker));
        } else {*/
        p.innerHTML = message.body.replace(/\r\n?|\n/g, '<br />');
        //}

        bubble.querySelector('span.info').innerHTML = message.publishedPrepared;

        var user = bubble.querySelector('p.user');
        user.className = 'user ' + message.color;
        user.innerHTML = message.resource;
        user.onclick = function(n) {
            var textarea = document.querySelector('#chat_textarea');
            textarea.value = this.innerHTML + ', ' + textarea.value;
            textarea.focus();
        };

        if(conversation) {
            conversation.appendChild(bubble);
        }
    },
    appendMessage : function(idjidtime, data, prepend) {
        var bubble = null,
            mergeMsg = false,
            msgStack,
            refBubble;
        var jidtime = idjidtime.substring(idjidtime.indexOf('<') + 1);

        if(prepend) {
            refBubble = document.querySelector("#chat_widget .contained li:first-child");
            msgStack = document.querySelector("[data-bubble='" + jidtime + "']");
        } else {
            refBubble = document.querySelector("#chat_widget .contained li:last-child");
            var stack = document.querySelectorAll("[data-bubble='" + jidtime + "']");
            msgStack = stack[stack.length-1];
        }

        if(msgStack != null
            && msgStack.parentNode == refBubble
            && data.file === null
            && data.sticker === null
            && !MovimUtils.hasClass(refBubble.querySelector('div.bubble'), "sticker")
            && !MovimUtils.hasClass(refBubble.querySelector('div.bubble'), "file")
        ){
            bubble = msgStack.parentNode;
            mergeMsg = true;
        } else {
            if (data.session == data.jidfrom) {
                bubble = Chat.right.cloneNode(true);
                id = data.jidto + '_conversation';
            } else {
                bubble = Chat.left.cloneNode(true);
                id = data.jidfrom + '_conversation';
            }

            id = MovimUtils.cleanupId(id);

            bubble.querySelector('div.bubble').dataset.bubble = jidtime;
            bubble.querySelector('div.bubble').dataset.publishedprepared = data.publishedPrepared;
        }

        var msg = bubble.querySelector('div.bubble > div');
        var span = msg.getElementsByTagName('span')[0];
        var p = msg.getElementsByTagName('p')[0];

        // If there is already a msg in this bubble, create another div (next msg or replacement)
        if (bubble.querySelector('div.bubble p')
        && bubble.querySelector('div.bubble p').innerHTML != '') {
            msg = document.createElement("div");
            p = document.createElement("p");
            span = document.createElement("span");
            span.className = 'info';
        }

        if (data.rtl) {
            bubble.querySelector('div.bubble').setAttribute('dir', 'rtl');
        }

        if (data.body.match(/^\/me\s/)) {
            p.className = 'quote';
            data.body = data.body.substr(4);
        }

        if (data.id != null) {
            msg.setAttribute("id", data.id);
            if (data.newid != null) {
                msg.setAttribute("id", data.newid);
            }
        }

        if (data.sticker != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'sticker');
            p.appendChild(Chat.getStickerHtml(data.sticker));
        } else {
            p.innerHTML = data.body.replace(/\r\n?|\n/g, '<br />');
        }

        if (data.audio != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'file');
            p.appendChild(Chat.getAudioHtml(data.file));
        } else if (data.file != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'file');
            p.appendChild(Chat.getFileHtml(data.file, data.sticker));
        }

        if (data.edited) {
            span.appendChild(Chat.getEditedIcoHtml());
        }
        if (data.delivered) {
            span.appendChild(Chat.getDeliveredIcoHtml(data.delivered));
        }

        msg.appendChild(p);
        msg.appendChild(span);

        var elem = document.getElementById(data.id);
        if (elem) {
            elem.parentElement.replaceChild(msg, elem);
            mergeMsg = true;
        } else {
            if(prepend) {
                bubble.querySelector('div.bubble').insertBefore( msg, bubble.querySelector('div.bubble').firstChild );
            } else {
                bubble.querySelector('div.bubble').appendChild(msg);
            }
        }

        if(prepend){
            Chat.currentDate = data.published;

            // We prepend
            if (!mergeMsg) {
                MovimTpl.prepend("#" + id, bubble.outerHTML);
            }
        } else {
            if (!mergeMsg) {
                MovimTpl.append("#" + id, bubble.outerHTML);
            }
        }
    },
    appendDate: function(date, prepend) {
        var list = document.querySelector('#chat_widget > div ul');
        dateNode = Chat.date.cloneNode(true);
        dateNode.querySelector('p').innerHTML = date;

        if(prepend) {
            list.insertBefore(dateNode, list.firstChild);
        } else {
            list.appendChild(dateNode);
        }
    },
    getStickerHtml: function(sticker) {
        var img = document.createElement("img");
        if(sticker.url) {
            img.setAttribute("src", sticker.url);
            if(sticker.width)  img.setAttribute("width", sticker.width);
            if(sticker.height)
                img.setAttribute("height", sticker.height);
            else {
                img.setAttribute("height", "150");
            }
        }

        if(sticker.picture) {
            var a = document.createElement("a");
            a.setAttribute("href", sticker.url);
            a.setAttribute("target", "_blank");
            a.appendChild(img);
            return a;
        } else {
            return img;
        }<commit_msg>Small fix with the date separators when scrolling the history<commit_after>var Chat = {
    left : null,
    right: null,
    room: null,
    date: null,
    currentDate: null,
    lastScroll: null,
    lastHeight: null,
    edit: false,

    // Chat state
    state: null,
    since: null,

    sendMessage: function(jid, muc)
    {
        var n = document.querySelector('#chat_textarea');
        var text = n.value;
        n.value = "";
        n.focus();
        MovimUtils.textareaAutoheight(n);

        localStorage.removeItem(n.dataset.jid + '_message');

        if(Chat.edit) {
            Chat.edit = false;
            Chat_ajaxCorrect(jid, encodeURIComponent(text));
        } else {
            Chat_ajaxSendMessage(jid, encodeURIComponent(text), muc);
        }
    },

    focus: function(jid)
    {
        if(jid) {
            document.querySelector('#chat_widget').dataset.jid = jid;
        }

        var textarea = document.querySelector('#chat_textarea');

        setTimeout(function() {
            var textarea = document.querySelector('#chat_textarea');
            textarea.value = localStorage.getItem(textarea.dataset.jid + '_message');
        }, 0); // Fix Me

        textarea.onkeydown = function(event) {
            if(event.keyCode == 38 && this.value == '') {
                Chat_ajaxLast(this.dataset.jid);
            } else if(event.keyCode == 40
            && (this.value == '' || Chat.edit == true)) {
                Chat.clearReplace();
            }
        };

        textarea.onkeypress = function(event) {
            if(event.keyCode == 13) {
                if(event.shiftKey) {
                    return;
                }
                Chat.state = 0;
                Chat.sendMessage(this.dataset.jid, Boolean(this.dataset.muc));

                return false;
            } else if(!Boolean(this.dataset.muc)) {
                if(Chat.state == 0 || Chat.state == 2) {
                    Chat.state = 1;
                    Chat_ajaxSendComposing(this.dataset.jid);
                    Chat.since = new Date().getTime();
                }
            }
        };

        textarea.onkeyup = function(event) {
            localStorage.setItem(this.dataset.jid + '_message', this.value);

            setTimeout(function()
            {
                var textarea = document.querySelector('#chat_textarea');

                if(textarea
                && !Boolean(textarea.dataset.muc)
                && Chat.state == 1
                && Chat.since + 5000 < new Date().getTime()) {
                    Chat.state = 2;
                    Chat_ajaxSendPaused(textarea.dataset.jid);
                }
            },5000);

            Chat.toggleAction(this.value.length);
        };

        textarea.oninput = function() {
            MovimUtils.textareaAutoheight(this);
        };

        if(document.documentElement.clientWidth > 1024) {
            document.querySelector('#chat_textarea').focus();
        }
    },
    setTextarea: function(value)
    {
        Chat.edit = true;
        var textarea = document.querySelector('#chat_textarea');
        textarea.value = value;
        MovimUtils.textareaAutoheight(textarea);

    },
    clearReplace: function()
    {
        Chat.edit = false;
        var textarea = document.querySelector('#chat_textarea');
        textarea.value = '';
        MovimUtils.textareaAutoheight(textarea);
    },
    notify : function(title, body, image)
    {
        if(document_focus == false) {
            movim_title_inc();
            movim_desktop_notification(title, body, image);
        }
    },
    empty : function()
    {
        Chat_ajaxGet();
    },
    setBubbles : function(left, right, room, date) {
        var div = document.createElement('div');

        div.innerHTML = left;
        Chat.left = div.firstChild.cloneNode(true);
        div.innerHTML = right;
        Chat.right = div.firstChild.cloneNode(true);
        div.innerHTML = room;
        Chat.room = div.firstChild.cloneNode(true);
        div.innerHTML = date;
        Chat.date = div.firstChild.cloneNode(true);

        Chat.setScrollBehaviour();
    },
    setScrollBehaviour : function() {
        var discussion = document.querySelector('#chat_widget div.contained');
        discussion.onscroll = function() {
            if(discussion.dataset.muc != true) {
                if(this.scrollTop < 1) {
                    var chat = document.querySelector('#chat_widget');
                    Chat_ajaxGetHistory(chat.dataset.jid, Chat.currentDate);
                }
            }
            Chat.lastHeight = this.clientHeight;
        };
    },
    appendMessagesWrapper : function(page, prepend) {
        Chat.currentDate = null;
        if(page) {
            var scrolled = MovimTpl.isPanelScrolled();

            var discussion = document.querySelector('#chat_widget div.contained');

            if(discussion == null) return;

            Chat.lastScroll = discussion.scrollHeight;

            for(date in page) {
                if (page[date].constructor == Array) {
                    for(id in page[date]) {
                        Chat.appendMucMessage(page[date][id]);
                    }
                } else {
                    for(speakertime in page[date]) {
                        if(!Chat.currentDate) {
                            Chat.currentDate = page[date][speakertime].published;
                        }
                        Chat.appendMessage(speakertime, page[date][speakertime], prepend);
                    }
                }

                if(date != '') {
                    Chat.appendDate(date, prepend);
                }
            }

            // Only scroll down if scroll was at the bottom before the new msg
            // => don't scroll if the user was reading previous messages
            if(scrolled && prepend !== true) {
                setTimeout(function() {
                    MovimTpl.scrollPanel();
                }, 20);
            }

            if(prepend) {
                // And we scroll where we were
                var scrollDiff = discussion.scrollHeight - Chat.lastScroll;
                discussion.scrollTop += scrollDiff;
                Chat.lastScroll = discussion.scrollHeight;
            }
        }
    },
    appendMucMessage : function(message) {
        var conversation = document.getElementById(
            MovimUtils.cleanupId(message.jidfrom + '_conversation')
        );
        //datebox = Chat.room.cloneNode(true);
        //datebox.innerHTML = date;

        //if(conversation) {
        //    conversation.appendChild(datebox);
        //}

        bubble = Chat.room.cloneNode(true);

        var p = bubble.querySelector('p.message');

        if(message.body.match(/^\/me/)) {
            p.classList.add('quote');
            message.body = message.body.substr(4);
        }

        if (message.quoted) {
            p.classList.add('quoted');
        }

        /*if (message.sticker != null) {
            MovimUtils.addClass(bubble.querySelector('p.message'), 'sticker');
            bubble.querySelector('p.message').appendChild(Chat.getStickerHtml(message.sticker));
        } else {*/
        p.innerHTML = message.body.replace(/\r\n?|\n/g, '<br />');
        //}

        bubble.querySelector('span.info').innerHTML = message.publishedPrepared;

        var user = bubble.querySelector('p.user');
        user.className = 'user ' + message.color;
        user.innerHTML = message.resource;
        user.onclick = function(n) {
            var textarea = document.querySelector('#chat_textarea');
            textarea.value = this.innerHTML + ', ' + textarea.value;
            textarea.focus();
        };

        if(conversation) {
            conversation.appendChild(bubble);
        }
    },
    appendMessage : function(idjidtime, data, prepend) {
        var bubble = null,
            mergeMsg = false,
            msgStack,
            refBubble;
        var jidtime = idjidtime.substring(idjidtime.indexOf('<') + 1);

        if(prepend) {
            refBubble = document.querySelector("#chat_widget .contained li:first-child");
            msgStack = document.querySelector("[data-bubble='" + jidtime + "']");
        } else {
            refBubble = document.querySelector("#chat_widget .contained li:last-child");
            var stack = document.querySelectorAll("[data-bubble='" + jidtime + "']");
            msgStack = stack[stack.length-1];
        }

        if(msgStack != null
            && msgStack.parentNode == refBubble
            && data.file === null
            && data.sticker === null
            && !MovimUtils.hasClass(refBubble.querySelector('div.bubble'), "sticker")
            && !MovimUtils.hasClass(refBubble.querySelector('div.bubble'), "file")
        ){
            bubble = msgStack.parentNode;
            mergeMsg = true;
        } else {
            if (data.session == data.jidfrom) {
                bubble = Chat.right.cloneNode(true);
                id = data.jidto + '_conversation';
            } else {
                bubble = Chat.left.cloneNode(true);
                id = data.jidfrom + '_conversation';
            }

            id = MovimUtils.cleanupId(id);

            bubble.querySelector('div.bubble').dataset.bubble = jidtime;
            bubble.querySelector('div.bubble').dataset.publishedprepared = data.publishedPrepared;
        }

        var msg = bubble.querySelector('div.bubble > div');
        var span = msg.getElementsByTagName('span')[0];
        var p = msg.getElementsByTagName('p')[0];

        // If there is already a msg in this bubble, create another div (next msg or replacement)
        if (bubble.querySelector('div.bubble p')
        && bubble.querySelector('div.bubble p').innerHTML != '') {
            msg = document.createElement("div");
            p = document.createElement("p");
            span = document.createElement("span");
            span.className = 'info';
        }

        if (data.rtl) {
            bubble.querySelector('div.bubble').setAttribute('dir', 'rtl');
        }

        if (data.body.match(/^\/me\s/)) {
            p.className = 'quote';
            data.body = data.body.substr(4);
        }

        if (data.id != null) {
            msg.setAttribute("id", data.id);
            if (data.newid != null) {
                msg.setAttribute("id", data.newid);
            }
        }

        if (data.sticker != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'sticker');
            p.appendChild(Chat.getStickerHtml(data.sticker));
        } else {
            p.innerHTML = data.body.replace(/\r\n?|\n/g, '<br />');
        }

        if (data.audio != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'file');
            p.appendChild(Chat.getAudioHtml(data.file));
        } else if (data.file != null) {
            MovimUtils.addClass(bubble.querySelector('div.bubble'), 'file');
            p.appendChild(Chat.getFileHtml(data.file, data.sticker));
        }

        if (data.edited) {
            span.appendChild(Chat.getEditedIcoHtml());
        }
        if (data.delivered) {
            span.appendChild(Chat.getDeliveredIcoHtml(data.delivered));
        }

        msg.appendChild(p);
        msg.appendChild(span);

        var elem = document.getElementById(data.id);
        if (elem) {
            elem.parentElement.replaceChild(msg, elem);
            mergeMsg = true;
        } else {
            if(prepend) {
                bubble.querySelector('div.bubble').insertBefore( msg, bubble.querySelector('div.bubble').firstChild );
            } else {
                bubble.querySelector('div.bubble').appendChild(msg);
            }
        }

        if(prepend){
            Chat.currentDate = data.published;

            // We prepend
            if (!mergeMsg) {
                MovimTpl.prepend("#" + id, bubble.outerHTML);
            }
        } else {
            if (!mergeMsg) {
                MovimTpl.append("#" + id, bubble.outerHTML);
            }
        }
    },
    appendDate: function(date, prepend) {
        var list = document.querySelector('#chat_widget > div ul');
        dateNode = Chat.date.cloneNode(true);
        dateNode.dataset.value = date;
        dateNode.querySelector('p').innerHTML = date;

        var dates = list.querySelectorAll('li.date');

        if(prepend) {
            // If the date was already displayed we remove it
            if(dates.length > 0
            && dates[0].dataset.value == date) {
                dates[0].remove();
            }

            list.insertBefore(dateNode, list.firstChild);
        } else {
            list.appendChild(dateNode);
        }
    },
    getStickerHtml: function(sticker) {
        var img = document.createElement("img");
        if(sticker.url) {
            img.setAttribute("src", sticker.url);
            if(sticker.width)  img.setAttribute("width", sticker.width);
            if(sticker.height)
                img.setAttribute("height", sticker.height);
            else {
                img.setAttribute("height", "150");
            }
        }

        if(sticker.picture) {
            var a = document.createElement("a");
            a.setAttribute("href", sticker.url);
            a.setAttribute("target", "_blank");
            a.appendChild(img);
            return a;
        } else {
            return img;
        }
{'fraction_non_alphanumeric': 0.12887469472102198, 'fraction_numerical': 0.002893105391696412, 'mean_word_length': 1.6629314657328664, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5414470', 'n_tokens_mistral': 7391, 'n_tokens_neox': 7143, 'n_words': 1204}