(function (root, factory) { if (typeof define === 'function' && define.amd) { define(["converse"], factory); } else { factory(converse); } }(this, function (converse) { var Strophe, $iq, _converse, html, __, converseConn; var mucJids = {}, nextItem = 0, nickColors = {}, roomJids = [], timestamp = (new Date()).toISOString(); converse.plugins.add("muc-directory", { 'dependencies': [], 'initialize': function () { _converse = this._converse; html = converse.env.html; __ = _converse.__; Strophe = converse.env.Strophe; $iq = converse.env.$iq; class MUCDirectoryDialog extends _converse.exports.BaseModal { initialize() { super.initialize(); this.listenTo(this.model, "change", () => this.requestUpdate()); this.addEventListener('shown.bs.modal', () => { nextItem = 0; this.doDirectory(); this.keyInput = this.querySelector('#pade-muc-directory-filter'); this.keyInput.focus(); this.keyInput.addEventListener('keyup', (ev) => { this.keyUp(ev); }); }); } renderModal() { return html` ` } getModalTitle () { return __('Group Chat Directory'); } keyUp(ev) { if (ev.key === "Enter") { const filter = this.querySelector("#pade-muc-directory-filter").value.trim(); this.doFilter(filter); } } async doDirectory() { console.debug("doDirectory"); const directoryResults = this.querySelector("#pade-directory-results"); if (nextItem == 0) { roomJids = Object.getOwnPropertyNames(mucJids); if (roomJids.length == 0 || converse.env.dayjs().isAfter(timestamp, 'hour')) { timestamp = (new Date()).toISOString(); await fetchMUCs(); roomJids = Object.getOwnPropertyNames(mucJids); } // uncomment this if you want sorted listing //roomJids = roomJids.sort(); directoryResults.addEventListener('scroll', () => { const left = directoryResults.scrollTop + directoryResults.clientHeight; const right = directoryResults.scrollHeight - 1; if (left >= right) { this.loadMore(); } }); this.loadMore(); } } loadMore() { const directoryResults = this.querySelector("#pade-directory-results"); const filter = this.querySelector("#pade-muc-directory-filter").value.trim(); console.debug("loadMore", roomJids.length, nextItem); if (nextItem < roomJids.length) for (let i = 0; i < 16; i++) { if (nextItem < roomJids.length) { getRoomDetails(roomJids[nextItem], directoryResults, filter); nextItem++; } } } doFilter(filter) { const panels = this.querySelectorAll('.pade-col > div'); console.debug("doFilter", filter, panels); let needMore = false; panels.forEach(function(panel) { panel.parentNode.style.display = "block"; const jid = panel.getAttribute("data-room-jid"); const name = panel.getAttribute("data-room-name"); const desc = panel.getAttribute("data-room-desc"); if (filter.length > 2 && jid.indexOf(filter) == -1 && name.indexOf(filter) == -1 && desc.indexOf(filter) == -1) { panel.parentNode.style.display = "none"; needMore = true; } }); if (needMore) this.loadMore(); } async doDirectory() { console.debug("doDirectory"); const directoryResults = this.querySelector("#pade-directory-results"); const that = this; if (nextItem == 0) { roomJids = Object.getOwnPropertyNames(mucJids); if (roomJids.length == 0 || converse.env.dayjs().isAfter(timestamp, 'hour')) { timestamp = (new Date()).toISOString(); await fetchMUCs(); roomJids = Object.getOwnPropertyNames(mucJids); } // uncomment this if you want sorted listing //roomJids = roomJids.sort(); directoryResults.addEventListener('scroll', function() { const left = directoryResults.scrollTop + directoryResults.clientHeight; const right = directoryResults.scrollHeight - 1; if (left >= right) { that.loadMore(); } }); this.loadMore(); } } }; _converse.api.elements.define('converse-pade-muc-directory-dialog', MUCDirectoryDialog); _converse.api.listen.on('connected', async function() { converseConn = await _converse.api.connection.get(); }); _converse.api.listen.on('chatRoomViewInitialized', function (view) { console.debug("chatRoomViewInitialized", view); extendUI(); }); _converse.api.listen.on('chatBoxViewInitialized', function (view) { console.debug("chatBoxViewInitialized", view); extendUI(); }); _converse.api.listen.on('chatBoxClosed', function (chatbox) { console.debug("chatBoxClosed", chatbox); extendUI(); }); console.debug("muc directory plugin is ready"); } }); async function fetchMUCs() { let page = 1; while (page < 20) { const response = await fetch('https://search.jabber.network/api/1.0/rooms/unsafe?p=' + page++); const data = await response.json(); if (!data.items || data.items.length == 0) break; console.debug("search.jabber.network", data.items); for (item of data.items) { if (item.address && item.address != "null") { mucJids[item.address] = {jid: item.address}; } } } } function extendUI() { const section = document.body.querySelector('converse-rooms-list .d-flex.controlbox-padded'); if (section) { if (!section.parentNode.querySelector('.pade-muc-directory')) { const mucButton = newElement('a', null, '', 'controlbox-heading__btn', 'pade-muc-directory'); mucButton.title = "Find Group Chat"; section.appendChild(mucButton); mucButton.addEventListener('click', function(evt) { evt.stopPropagation(); const model = new converse.env.Model(); _converse.api.modal.show('converse-pade-muc-directory-dialog', { model }); }, false); } } } async function getRoomDetails(room, ele, filter) { //console.debug("getRoomDetails", room, filter); const stanza = await _converse.api.disco.info(room); mucJids[room].label = stanza.querySelector('identity').getAttribute("name") || room; mucJids[room].subject = getValue(stanza.querySelector('field[var="muc#roominfo_subject"] > value')); mucJids[room].occupants = getValue(stanza.querySelector('field[var="muc#roominfo_occupants"] > value')); mucJids[room].description = getValue(stanza.querySelector('field[var="muc#roominfo_description"] > value')); if (filter.length == 0 || (filter.length > 2 && (mucJids[room].jid.indexOf(filter) > -1 || mucJids[room].label.indexOf(filter) > -1 || mucJids[room].description.indexOf(filter) > -1))) { const stanza = converse.env.$iq({type: 'get', to: room}).c('vCard', {xmlns: 'vcard-temp'}); const iq = await _converse.api.sendIQ(stanza); const photo = iq.querySelector('vCard PHOTO'); if (photo) { const binval = photo.querySelector('BINVAL')?.innerHTML; const type = photo.querySelector('TYPE')?.innerHTML if (binval && binval != "" && type && type != "") { mucJids[room].avatar = 'data:' + type + ';base64,' + binval; createPanel(mucJids[room], ele); } else { mucJids[room].avatar = createAvatar(mucJids[room].label); createPanel(mucJids[room], ele); } } else { mucJids[room].avatar = createAvatar(mucJids[room].label); createPanel(mucJids[room], ele); } } } function createPanel(room, chatgrid) { console.debug("createPanel", room, chatgrid); const html = '
' + room.label + '

' + room.description + '

'; const panel = newElement('div', room.jid, html, 'pade-col'); panel.addEventListener('click', function(evt) { evt.stopPropagation(); const jid = evt.target.getAttribute('data-room-jid'); console.debug("createPanel click", jid, evt.target); if (jid) { //mucDirectoryDialog.modal.hide(); _converse.api.rooms.open(jid, {'bring_to_foreground': true}, true); } }); chatgrid.appendChild(panel); } function getValue(value) { return value && value.innerHTML != "" ? value.innerHTML : ' '; } function getRandomColor(nickname) { if (nickColors[nickname]) { return nickColors[nickname]; } else { var letters = '0123456789ABCDEF'; var color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } nickColors[nickname] = color; return color; } } function newElement(el, id, html, class1, class2, class3, class4, class5) { const ele = document.createElement(el); if (id) ele.id = id; if (html) ele.innerHTML = html; if (class1) ele.classList.add(class1); if (class2) ele.classList.add(class2); if (class3) ele.classList.add(class3); if (class4) ele.classList.add(class4); if (class5) ele.classList.add(class5); document.body.appendChild(ele); return ele; } function createAvatar(nickname, width, height, font) { if (_converse.vcards) { let vcard = _converse.vcards.findWhere({'jid': nickname}); if (!vcard) vcard = _converse.vcards.findWhere({'nickname': nickname}); if (vcard && vcard.get('image') && _converse.DEFAULT_IMAGE != vcard.get('image')) return "data:" + vcard.get('image_type') + ";base64," + vcard.get('image'); } if (!nickname) nickname = "Anonymous"; nickname = nickname.toLowerCase(); if (!width) width = 32; if (!height) height = 32; if (!font) font = "16px Arial"; var canvas = document.createElement('canvas'); canvas.style.display = 'none'; canvas.width = width; canvas.height = height; document.body.appendChild(canvas); var context = canvas.getContext('2d'); context.fillStyle = getRandomColor(nickname); context.fillRect(0, 0, canvas.width, canvas.height); context.font = font; context.fillStyle = "#fff"; var first, last, pos = nickname.indexOf("@"); if (pos > 0) nickname = nickname.substring(0, pos); var name = nickname.split(" "); if (name.length == 1) name = nickname.split("."); if (name.length == 1) name = nickname.split("-"); var l = name.length - 1; if (name && name[0] && name.first != '') { first = name[0][0]; last = name[l] && name[l] != '' && l > 0 ? name[l][0] : null; if (last) { var initials = first + last; context.fillText(initials.toUpperCase(), 3, 23); } else { var initials = first; context.fillText(initials.toUpperCase(), 10, 23); } var data = canvas.toDataURL(); document.body.removeChild(canvas); } return canvas.toDataURL(); } }));