Browse Source

Update the Jitsi Meet plugin to work with Converse 11.0.0

Use modern JavaScript syntax and features.
Update to use the newest modal functionality (it wasn't working otherwise).
Nicer rendering of the links to join a meeting.
JC Brand 1 month ago
parent
commit
2aa367f3ba
1 changed files with 411 additions and 383 deletions
  1. 411 383
      packages/jitsimeet/jitsimeet.js

+ 411 - 383
packages/jitsimeet/jitsimeet.js

@@ -1,419 +1,447 @@
-(function (root, factory) {
-    if (typeof define === 'function' && define.amd) {
-        define(["converse"], factory);
-    } else {
-        factory(converse);
-    }
-}(this, function (converse) {
-    var MEET_START_OPTIONS = {
-      INTO_CHAT_WINDOW : "into_chat_window",
-      INTO_NEW_TAB : "into_new_tab",
-      JUST_CREATE_LINK : "just_create_link"
-    };
-    var Strophe, $iq, $msg, $pres, $build, b64_sha1, _ , dayjs, _converse, html, _, __, Model, BootstrapModal, jitsimeet_confirm, jitsimeet_invitation, jitsimeet_tab_invitation;
-    var MeetDialog = null, meetDialog = null;
-
-    converse.plugins.add("jitsimeet", {
-        dependencies: [],
-
-        initialize: function () {
-            _converse = this._converse;
-
-            Strophe = converse.env.Strophe;
-            $iq = converse.env.$iq;
-            $msg = converse.env.$msg;
-            $pres = converse.env.$pres;
-            $build = converse.env.$build;
-            b64_sha1 = converse.env.b64_sha1;
-            dayjs = converse.env.dayjs;
-            html = converse.env.html;
-            Model = converse.env.Model;
-            BootstrapModal = converse.env.BootstrapModal;
-            _ = converse.env._;
-            __ = _converse.__;
-
-            _converse.api.settings.update({
-                jitsimeet_start_option: MEET_START_OPTIONS.INTO_CHAT_WINDOW,
-                jitsimeet_head_display_toggle: false,
-                jitsimeet_modal: false,
-                jitsimeet_url: 'https://meet.jit.si',
-            });
-
-            jitsimeet_confirm  = __('Meeting?');
-            jitsimeet_invitation = __('Please join meeting in room at');
-            jitsimeet_tab_invitation = __('Or open in new tab at');
-
-            _converse.api.listen.on('messageNotification', function (data)
-            {
-                console.debug("messageNotification", data);
-
-                var chatbox = data.chatbox;
-                var bodyElement = data.stanza.querySelector('body');
-
-                if (bodyElement)
-                {
-                    var body = bodyElement.innerHTML;
-                    var url = _converse.api.settings.get("jitsimeet_url");
-                    var pos = body.indexOf(url + "/");
-
-                    if (pos > -1)
-                    {
-                        var room = body.substring(pos + url.length + 1);
-                        var label = pos > 0 ? body.substring(0, pos) : jitsimeet_invitation;
-                        var from = chatbox.getDisplayName().trim();
-                        var avatar = _converse.api.settings.get("notification_icon");
-
-                        if (data.chatbox.vcard.attributes.image) avatar = data.chatbox.vcard.attributes.image;
-
-                        var prompt = new Notification(from,
-                        {
-                            'body': label + " " + room,
-                            'lang': _converse.locale,
-                            'icon': avatar,
-                            'requireInteraction': true
-                        });
-
-                        prompt.onclick = function(event)
-                        {
-                            event.preventDefault();
-
-                            var box_jid = Strophe.getBareJidFromJid(chatbox.get("contact_jid") || chatbox.get("jid") || chatbox.get("from"));
-                            var view = _converse.chatboxviews.get(box_jid);
-
-                            if (view)
-                            {
-                                doLocalVideo(view, room, url + "/" + room, label);
-                            }
-                        }
-                    }
-                }
-            });
-
-            MeetDialog = BootstrapModal.extend({
-                initialize() {
-                    BootstrapModal.prototype.initialize.apply(this, arguments);
-                    this.listenTo(this.model, 'change', this.render);
-                },
-                toHTML() {
-                  var view = this.model.get("view");
-                  var label = this.model.get("label");
-                  var room = this.model.get("room");
-                  var url = this.model.get("url");
-
-                  return html`
-                         <div class="modal-dialog modal-lg">
-                             <div class="modal-content">
-                                 <div class="modal-header">
-                                   <h4 class="modal-title">${label} ${room}</h4>
-                                 </div>
-                                 <div style="text-align: center;" class="modal-body"><iframe src="${url}" id="jitsimeet" allow="microphone; camera;" frameborder="0" seamless="seamless" allowfullscreen="true" scrolling="no" style="z-index: 2147483647;width:640px;height:480px;display: inline-block"></iframe></div>
-                                 <div class="modal-footer"> <button type="button" class="btn btn-danger btn-terminate" data-dismiss="modal">Close</button> </div>
-                             </div>
-                         </div>
-                `},
-                 afterRender() {
-                  var that = this;
-
-                  this.el.addEventListener('shown.bs.modal', function()
-                  {
-                     that.el.querySelector('.modal-body').innerHTML = '<iframe src="' + that.model.get("url") + '" id="jitsimeet" allow="microphone; camera;" frameborder="0" seamless="seamless" allowfullscreen="true" scrolling="no" style="z-index: 2147483647;width:640px;height:480px;display: inline-block"></iframe>';
-
-                  }, false);
-                },
-                events: {
-                    "click .btn-terminate": "terminateCall"
-                },
-
-                terminateCall() {
-                    this.el.querySelector('.modal-body').innerHTML = "about:blank"
-                }
-            });
-
-            _converse.api.listen.on('getToolbarButtons', function(toolbar_el, buttons)
-            {
-                console.debug("getToolbarButtons", toolbar_el.model.get("jid"));
-                let color = "fill:var(--chat-toolbar-btn-color);";
-                if (toolbar_el.model.get("type") === "chatroom") color = "fill:var(--muc-toolbar-btn-color);";
-
-                buttons.push(html`
-                    <button class="plugin-jitsimeet" title="${__('Jitsi Meet')}" @click=${performVideo}/>
-                        <svg style="width:18px; height:18px; ${color}" viewBox="0 0 32 32"><path d="M22.688 14l5.313-5.313v14.625l-5.313-5.313v4.688c0 .75-.625 1.313-1.375 1.313h-16C4.563 24 4 23.437 4 22.687V9.312c0-.75.563-1.313 1.313-1.313h16c.75 0 1.375.563 1.375 1.313V14z"></path></svg>
-                    </button>
-                `);
+const MEET_START_OPTIONS = {
+    INTO_CHAT_WINDOW: "into_chat_window",
+    INTO_NEW_TAB: "into_new_tab",
+    JUST_CREATE_LINK: "just_create_link",
+};
+
+function handleMessageNotification(_converse, data) {
+    console.debug("messageNotification", data);
+
+    const chatbox = data.chatbox;
+    const bodyElement = data.stanza.querySelector("body");
+    const { __ } = _converse;
+
+    if (bodyElement) {
+        const body = bodyElement.innerHTML;
+        const url = _converse.api.settings.get("jitsimeet_url");
+        const pos = body.indexOf(url + "/");
+
+        if (pos > -1) {
+            const room = body.substring(pos + url.length + 1);
+            const label = pos > 0 ? body.substring(0, pos) : __("New meeting");
+            const from = chatbox.getDisplayName().trim();
+            const avatar = _converse.api.settings.get("notification_icon");
+
+            if (chatbox.vcard.attributes.image) {
+                avatar = chatbox.vcard.attributes.image;
+            }
 
 
-                return buttons;
+            const prompt = new Notification(from, {
+                body: label + " " + room,
+                lang: _converse.locale,
+                icon: avatar,
+                requireInteraction: true,
             });
             });
 
 
-            _converse.api.listen.on('afterMessageBodyTransformed', function(text)
-            {
-                const pos = text.indexOf("https://");
-
-                if (pos > -1 && text.indexOf(_converse.api.settings.get("jitsimeet_url")) > -1)
-                {
-                    console.debug("afterMessageBodyTransformed", text);
-
-                    const url = text.substring(pos);
-                    const link_room = url.substring(url.lastIndexOf("/") + 1);
-                    const link_label = jitsimeet_invitation;
-                    const tab_label = jitsimeet_tab_invitation;
-
-                    text.references = [];
-                    text.addTemplateResult(0, text.length, html`<a 
-                        @click=${clickVideo} data-room="${link_room}" data-url="${url}"
-                        href="#">${link_label} ${link_room}</a><br/><a target="_blank" rel="noopener noreferrer"
-                        href="${url}">${tab_label} ${url}</a>`);
+            prompt.onclick = function (event) {
+                event.preventDefault();
+                const box_jid = Strophe.getBareJidFromJid(
+                    chatbox.get("contact_jid") ||
+                        chatbox.get("jid") ||
+                        chatbox.get("from")
+                );
+                const view = _converse.chatboxviews.get(box_jid);
+                if (view) {
+                    doLocalVideo(view, room, `${url}/${room}`, label);
                 }
                 }
-            });
-
-            console.debug("jitsimeet plugin is ready");
+            };
         }
         }
-    });
-
-    function __confirm(msg, callback) {
-      if (confirm(jitsimeet_confirm)) {
-          callback();
-      }
     }
     }
+}
 
 
-    function __displayError(error) {
-      alert(error);
-    }
+function getToolbarButtons(_converse, toolbar_el, buttons) {
+    const { html } = env;
+    const { __ } = _converse;
+    console.debug("getToolbarButtons", toolbar_el.model.get("jid"));
 
 
-    function getChatViewFromElement($el) {
-        return $el.closest('converse-chat.chatbox') || $el.closest('converse-muc.chatbox');
+    let style = "width:18px; height:18px; fill:var(--chat-color);";
+    if (toolbar_el.model.get("type") === "chatroom") {
+        style = "width:18px; height:18px; fill:var(--muc-color);";
     }
     }
 
 
-    function performVideo(ev)
-    {
-        ev.stopPropagation();
-        ev.preventDefault();
-
-        const chatView = getChatViewFromElement(ev.currentTarget);
-        __confirm(jitsimeet_confirm, function() {
-            doVideo(chatView);
-        });
+    buttons.push(html`
+        <button type="button" class="btn plugin-jitsimeet" title="${__("Jitsi Meet")}" @click="${(ev) => performVideo(_converse, ev)}"/>
+            <svg style="${style}" viewBox="0 0 32 32">
+                <path d="M22.688 14l5.313-5.313v14.625l-5.313-5.313v4.688c0 .75-.625 1.313-1.375 1.313h-16C4.563 24 4 23.437 4 22.687V9.312c0-.75.563-1.313 1.313-1.313h16c.75 0 1.375.563 1.375 1.313V14z"></path>
+            </svg>
+        </button>`);
+    return buttons;
+}
+
+function afterMessageBodyTransformed(_converse, text) {
+    const { api, __ } = _converse;
+    const pos = text.indexOf("https://");
+
+    if (pos > -1 && text.indexOf(api.settings.get("jitsimeet_url")) > -1) {
+        console.debug("afterMessageBodyTransformed", text);
+        const { html } = env;
+        const url = text.substring(pos);
+        const link_room = url.substring(url.lastIndexOf("/") + 1);
+
+        text.references = [];
+        text.addTemplateResult(
+            0,
+            text.length,
+            html`
+                <p>${__('A new meeting started:')} ${link_room}</p>
+                <button type="button"
+                    class="btn btn-primary"
+                    @click="${(ev) => clickVideo(_converse, ev)}"
+                    data-room="${link_room}"
+                    data-url="${url}">Open Meeting</button>
+                <button type="button"
+                    class="btn btn-secondary"
+                    @click="${() => window.open(url, '_blank')}">Open Meeting in New tab</button>`
+        );
     }
     }
-
-    function clickVideo(ev)
-    {
-        ev.stopPropagation();
-        ev.preventDefault();
-
-        var url = ev.target.getAttribute("data-url");
-        var room = ev.target.getAttribute("data-room");
-
-        if (ev.currentTarget) {
-          const chatView = getChatViewFromElement(ev.currentTarget);
-          doLocalVideo(chatView, room, url, jitsimeet_invitation);
-        }
+}
+
+function __displayError(error) {
+    alert(error);
+}
+
+function getChatViewFromElement(el) {
+    return (
+        el.closest("converse-chat.chatbox") ||
+        el.closest("converse-muc.chatbox")
+    );
+}
+
+function performVideo(_converse, ev) {
+    ev.stopPropagation();
+    ev.preventDefault();
+
+    const { __ } = _converse;
+    const chatView = getChatViewFromElement(ev.currentTarget);
+    const jitsimeet_confirm = __("Would you like to start a meeting?");
+    if (confirm(jitsimeet_confirm)) {
+        doVideo(_converse, chatView);
     }
     }
 
 
-    var doVideo = function doVideo(view)
-    {
-        const room = Strophe.getNodeFromJid(view.model.attributes.jid).toLowerCase().replace(/[\\]/g, '') + "-" + Math.random().toString(36).substr(2,9);
-        const url = _converse.api.settings.get("jitsimeet_url") + '/' + room;
+}
 
 
-        console.debug("doVideo", room, url, view);
+function clickVideo(_converse, ev) {
+    ev.stopPropagation();
+    ev.preventDefault();
 
 
-        view.model.sendMessage({'body': url});
-        const startOption = _converse.api.settings.get("jitsimeet_start_option");
-        if (startOption === MEET_START_OPTIONS.INTO_CHAT_WINDOW) {
-          doLocalVideo(view, room, url, jitsimeet_invitation);
-        } else if (startOption === MEET_START_OPTIONS.INTO_NEW_TAB) {
-          doNewTabVideo(url);
-        }
-    }
+    const url = ev.target.getAttribute("data-url");
+    const room = ev.target.getAttribute("data-room");
 
 
-    var doNewTabVideo = function doNewTabVideo(url)
-    {
-        console.debug("doNewTabVideo", url);
-        var newTabVideoLink = document.createElement('a');
-        Object.assign(newTabVideoLink, {
-            target: '_blank',
-            rel: 'noopener noreferrer',
-            href: url
-        })
-        .click()
+    if (ev.currentTarget) {
+        const chatView = getChatViewFromElement(ev.currentTarget);
+        doLocalVideo(_converse, chatView, room, url);
     }
     }
+}
+
+function doVideo(_converse, view) {
+    const { api } = _converse;
+    const room =
+        Strophe.getNodeFromJid(view.model.attributes.jid)
+            .toLowerCase()
+            .replace(/[\\]/g, "") +
+        "-" + Math.random().toString(36).substr(2, 9);
+    const url = api.settings.get("jitsimeet_url") + "/" + room;
+    console.debug("doVideo", room, url, view);
+
+    view.model.sendMessage({ body: url });
+    const startOption = api.settings.get("jitsimeet_start_option");
+    if (startOption === MEET_START_OPTIONS.INTO_CHAT_WINDOW) {
+        doLocalVideo(_converse, view, room, url);
+    } else if (startOption === MEET_START_OPTIONS.INTO_NEW_TAB) {
+        doNewTabVideo(url);
+    }
+};
+
+function doNewTabVideo(url) {
+    console.debug("doNewTabVideo", url);
+    const newTabVideoLink = document.createElement("a");
+    Object.assign(newTabVideoLink, {
+        target: "_blank",
+        rel: "noopener noreferrer",
+        href: url,
+    }).click();
+};
+
+function doLocalVideo(_converse, view, room, url, label) {
+    const { api } = _converse;
+    const chatModel = view.model;
+    console.debug("doLocalVideo", view, room, url, label);
+
+    const modal = api.settings.get("jitsimeet_modal") === true;
+
+    if (modal) {
+        const model = new converse.env.Model();
+        model.set({ view, url, label, room });
+        api.modal.show('converse-jitsimeet-dialog', { model });
+    } else {
+        const isOverlayedDisplay = _converse.api.settings.get("view_mode") === "overlayed";
+        const headDisplayToggle =
+            isOverlayedDisplay ||
+            _converse.api.settings.get("jitsimeet_head_display_toggle") ===
+                true;
+        const div = view.querySelector(headDisplayToggle ? ".chat-body" : ".box-flyout");
+
+        if (div) {
+            const jid = view.getAttribute("jid");
+            if (
+                Array.from(
+                    document.querySelectorAll("iframe.jitsimeet")
+                ).filter((f) => f.__jid === jid).length > 0
+            ) {
+                __displayError(__("A meet is already running into room"));
+                return;
+            }
 
 
-    var doLocalVideo = function doLocalVideo(view, room, url, label)
-    {
-        const chatModel = view.model;
-        console.debug("doLocalVideo", view, room, url, label);
-
-        var modal = _converse.api.settings.get("jitsimeet_modal") === true;
-
-        if (modal)
-        {
-            meetDialog = new MeetDialog({'model': new converse.env.Model({})});
-            meetDialog.model.set("view", view);
-            meetDialog.model.set("url", url);
-            meetDialog.model.set("label", label);
-            meetDialog.model.set("room", room);
-            meetDialog.show();
-        }
-        else {
-
-            const isOverlayedDisplay = _converse.api.settings.get("view_mode") === "overlayed";
-            const headDisplayToggle = isOverlayedDisplay || _converse.api.settings.get("jitsimeet_head_display_toggle") === true;
-            const div = view.querySelector(headDisplayToggle ? ".chat-body" : ".box-flyout");
-
-            if (div)
-            {
-                const jid = view.getAttribute("jid");
-                if(Array.from(document.querySelectorAll("iframe.jitsimeet")).filter(f => f.__jid === jid).length > 0) {
-                  __displayError(__('A meet is already running into room'));
-                  return;
-                }
-                const toggleHandler = function() {
-                  jitsiFrame.toggleHideShow();
-                };
-                const dynamicDisplayManager = new function() {
-                  let __resizeHandler;
-                  let __resizeWatchImpl;
-                  this.start = function() {
-                    const $chatBox = document.querySelector('.converse-chatboxes');
-                    const $anchor = document.querySelector('#conversejs.conversejs');
-                    __resizeHandler = function() {
-                      const currentView = _converse.chatboxviews.get(jid)
-                      if (currentView && headDisplayToggle) {
-                        const $head = currentView.querySelector(".chat-head");
-                        $head.removeEventListener('dblclick', toggleHandler);
-                        $head.addEventListener('dblclick', toggleHandler);
-                      }
-                      const currentDiv = currentView && currentView.querySelector(headDisplayToggle ? ".chat-body" : ".box-flyout");
-                      let top = currentDiv ? currentDiv.offsetTop : 0;
-                      let left = currentDiv ? currentDiv.offsetLeft : 0;
-                      let width = currentDiv ? currentDiv.offsetWidth : 0;
-                      let height = currentDiv ? currentDiv.offsetHeight : 0;
-                      let current = currentDiv && currentDiv.offsetParent;
-                      while (current && current !== $anchor) {
-                        top += current.offsetTop;
-                        left += current.offsetLeft;
-                        current = current.offsetParent;
-                      }
-                      jitsiFrame.style.top = top + "px";
-                      jitsiFrame.style.left = left + "px";
-                      jitsiFrame.style.width = width + "px";
-                      jitsiFrame.style.height = height + "px";
-                    };
-                    __resizeWatchImpl = new function() {
-                      let __resizeObserver;
-                      if (isOverlayedDisplay && typeof ResizeObserver === 'function') {
-                        __resizeObserver = new ResizeObserver(function(entries) {
-                          if (entries.length > 0) {
-                            __resizeHandler();
-                          }
-                        });
-                      }
-                      const __resizeWatchEvents = ['controlBoxOpened', 'controlBoxClosed', 'chatBoxBlurred',
-                        'chatBoxFocused', 'chatBoxMinimized', 'chatBoxMaximized',
-                        'chatBoxViewInitialized', 'chatRoomViewInitialized'];
-                      const __startResize = function() {
-                        jitsiFrame.style.pointerEvents = 'none';
-                        document.addEventListener('mousemove', __deferredResize);
-                      };
-                      const __endResize = function() {
-                        jitsiFrame.style.pointerEvents = '';
-                        document.removeEventListener('mousemove', __deferredResize);
-                      };
-                      let timeoutId;
-                      const __deferredResize = function() {
-                        clearTimeout(timeoutId);
-                        timeoutId = setTimeout(__resizeHandler, 0);
-                      };
-                      this.start = function() {
-                        _converse.api.listen.on('startDiagonalResize', __startResize);
-                        _converse.api.listen.on('startHorizontalResize', __startResize);
-                        _converse.api.listen.on('startVerticalResize', __startResize);
-                        document.addEventListener('mouseup', __endResize);
-                        window.addEventListener('resize', __resizeHandler);
-                        __resizeWatchEvents.forEach(c => _converse.api.listen.on(c, __deferredResize));
-                        if (__resizeObserver) {
-                          __resizeObserver.observe(div);
-                          __resizeObserver.observe($anchor);
-                          __resizeObserver.observe($chatBox);
+            const toggleHandler = () => jitsiFrame.toggleHideShow();
+
+            const dynamicDisplayManager = new (function () {
+                let __resizeHandler;
+                let __resizeWatchImpl;
+                this.start = function () {
+                    const $chatBox = document.querySelector(
+                        ".converse-chatboxes"
+                    );
+                    const $anchor = document.querySelector(
+                        "#conversejs.conversejs"
+                    );
+                    __resizeHandler = function () {
+                        const currentView = _converse.chatboxviews.get(jid);
+                        if (currentView && headDisplayToggle) {
+                            const head = currentView.querySelector(".chat-head");
+                            head.removeEventListener("dblclick", toggleHandler);
+                            head.addEventListener("dblclick", toggleHandler);
                         }
                         }
-                      };
-                      this.close = function() {
-                        _converse.api.listen.not('startDiagonalResize', __startResize);
-                        _converse.api.listen.not('startHorizontalResize', __startResize);
-                        _converse.api.listen.not('startVerticalResize', __startResize);
-                        document.removeEventListener('mouseup', __endResize);
-                        window.removeEventListener('resize', __resizeHandler);
-                        __resizeWatchEvents.forEach(c => _converse.api.listen.not(c, __deferredResize));
-                        if (__resizeObserver) {
-                          __resizeObserver.disconnect();
+                        const currentDiv =
+                            currentView &&
+                            currentView.querySelector(
+                                headDisplayToggle
+                                    ? ".chat-body"
+                                    : ".box-flyout"
+                            );
+                        let top = currentDiv ? currentDiv.offsetTop : 0;
+                        let left = currentDiv ? currentDiv.offsetLeft : 0;
+                        let width = currentDiv ? currentDiv.offsetWidth : 0;
+                        let height = currentDiv ? currentDiv.offsetHeight : 0;
+                        let current = currentDiv && currentDiv.offsetParent;
+                        while (current && current !== $anchor) {
+                            top += current.offsetTop;
+                            left += current.offsetLeft;
+                            current = current.offsetParent;
                         }
                         }
-                      };
+                        jitsiFrame.style.top = top + "px";
+                        jitsiFrame.style.left = left + "px";
+                        jitsiFrame.style.width = width + "px";
+                        jitsiFrame.style.height = height + "px";
                     };
                     };
+                    __resizeWatchImpl = new (function () {
+                        let __resizeObserver;
+                        if (
+                            isOverlayedDisplay &&
+                            typeof ResizeObserver === "function"
+                        ) {
+                            __resizeObserver = new ResizeObserver(
+                                function (entries) {
+                                    if (entries.length > 0) {
+                                        __resizeHandler();
+                                    }
+                                }
+                            );
+                        }
+                        const __resizeWatchEvents = [
+                            "controlBoxOpened",
+                            "controlBoxClosed",
+                            "chatBoxBlurred",
+                            "chatBoxFocused",
+                            "chatBoxMinimized",
+                            "chatBoxMaximized",
+                            "chatBoxViewInitialized",
+                            "chatRoomViewInitialized",
+                        ];
+                        const __startResize = function () {
+                            jitsiFrame.style.pointerEvents = "none";
+                            document.addEventListener("mousemove", __deferredResize);
+                        };
+                        const __endResize = function () {
+                            jitsiFrame.style.pointerEvents = "";
+                            document.removeEventListener("mousemove", __deferredResize);
+                        };
+                        let timeoutId;
+                        const __deferredResize = function () {
+                            clearTimeout(timeoutId);
+                            timeoutId = setTimeout(__resizeHandler, 0);
+                        };
+
+                        this.start = function () {
+                            _converse.api.listen.on("startDiagonalResize", __startResize);
+                            _converse.api.listen.on("startHorizontalResize", __startResize);
+                            _converse.api.listen.on("startVerticalResize", __startResize);
+                            document.addEventListener("mouseup", __endResize);
+                            window.addEventListener("resize", __resizeHandler);
+                            __resizeWatchEvents.forEach((c) => _converse.api.listen.on(c, __deferredResize));
+                            if (__resizeObserver) {
+                                __resizeObserver.observe(div);
+                                __resizeObserver.observe($anchor);
+                                __resizeObserver.observe($chatBox);
+                            }
+                        };
+
+                        this.close = function () {
+                            _converse.api.listen.not("startDiagonalResize", __startResize);
+                            _converse.api.listen.not("startHorizontalResize", __startResize);
+                            _converse.api.listen.not("startVerticalResize", __startResize);
+                            document.removeEventListener("mouseup", __endResize);
+                            window.removeEventListener("resize", __resizeHandler);
+                            __resizeWatchEvents.forEach((c) => _converse.api.listen.not(c, __deferredResize));
+                            if (__resizeObserver) {
+                                __resizeObserver.disconnect();
+                            }
+                        };
+                    })();
+
                     jitsiFrame.style.position = "absolute";
                     jitsiFrame.style.position = "absolute";
                     $anchor.appendChild(jitsiFrame);
                     $anchor.appendChild(jitsiFrame);
                     __resizeWatchImpl.start();
                     __resizeWatchImpl.start();
-                    _converse.api.listen.on('chatBoxClosed', closeJitsi);
+                    _converse.api.listen.on("chatBoxClosed", closeJitsi);
                     this.triggerChange();
                     this.triggerChange();
-                  };
-                  this.triggerChange = function() {
+                };
+                this.triggerChange = function () {
                     __resizeHandler();
                     __resizeHandler();
-                  };
-                  this.close = function() {
+                };
+                this.close = function () {
                     __resizeWatchImpl.close();
                     __resizeWatchImpl.close();
-                    _converse.api.listen.not('chatBoxClosed', closeJitsi);
-                  };
+                    _converse.api.listen.not("chatBoxClosed", closeJitsi);
                 };
                 };
-                let jitsiFrame = document.createElement('iframe');
-                let firstTime = true;
-                let closeJitsi = function(currentModel) {
-                  dynamicDisplayManager.triggerChange();
-                  if (currentModel && currentModel.cid !== chatModel.cid) {
+            })();
+
+            const jitsiFrame = document.createElement("iframe");
+            let firstTime = true;
+
+            function closeJitsi (currentModel) {
+                dynamicDisplayManager.triggerChange();
+                if (currentModel && currentModel.cid !== chatModel.cid) {
                     return;
                     return;
-                  }
-                  dynamicDisplayManager.close();
-                  jitsiFrame.remove();
                 }
                 }
-                let jitsiIframeCloseHandler = function ()
-                {
-                  console.debug("doVideo - load", this);
-                  if (!firstTime) // meeting closed and root url is loaded
-                  {
+                dynamicDisplayManager.close();
+                jitsiFrame.remove();
+            };
+
+            function jitsiIframeCloseHandler() {
+                console.debug("doVideo - load", this);
+                if (!firstTime) {
+                    // meeting closed and root url is loaded
                     closeJitsi();
                     closeJitsi();
-                  }
-                  if (firstTime) firstTime = false;   // ignore when jitsi-meet room url is loaded
-                };
-                jitsiFrame.toggleHideShow = function() {
-                  if (jitsiFrame.style.display === 'none') {
+                }
+                if (firstTime) {
+                    firstTime = false; // ignore when jitsi-meet room url is loaded
+                }
+            };
+
+            jitsiFrame.toggleHideShow = function () {
+                if (jitsiFrame.style.display === "none") {
                     jitsiFrame.show();
                     jitsiFrame.show();
-                  } else {
+                } else {
                     jitsiFrame.hide();
                     jitsiFrame.hide();
-                  }
-                };
-                jitsiFrame.show = function() {
-                  jitsiFrame.style.display = '';
-                };
-                jitsiFrame.hide = function() {
-                  jitsiFrame.style.display = 'none';
-                };
-                jitsiFrame.__jid = jid;
-                jitsiFrame.addEventListener("load", jitsiIframeCloseHandler);
-                jitsiFrame.setAttribute("src", url);
-                jitsiFrame.setAttribute("class", "jitsimeet");
-                jitsiFrame.setAttribute("allow", "microphone; camera;");
-                jitsiFrame.setAttribute("frameborder", "0");
-                jitsiFrame.setAttribute("seamless", "seamless");
-                jitsiFrame.setAttribute("allowfullscreen", "true");
-                jitsiFrame.setAttribute("scrolling", "no");
-                jitsiFrame.setAttribute("style", "z-index:1049;width:100%;height:100%;");
-                dynamicDisplayManager.start();
-                jitsiFrame.contentWindow.addEventListener("message", function (event) {
-                  if (_converse.api.settings.get("jitsimeet_url").indexOf(event.origin) === 0 && typeof event.data === 'string') {
-                    let data = JSON.parse(event.data);
-                    let jitsiEvent = data['jitsimeet_event'];
-                    if ('close' === jitsiEvent) {
-                      closeJitsi();
+                }
+            };
+            jitsiFrame.show = () => {
+                jitsiFrame.style.display = "";
+            };
+            jitsiFrame.hide = () => {
+                jitsiFrame.style.display = "none";
+            };
+            jitsiFrame.__jid = jid;
+            jitsiFrame.addEventListener("load", jitsiIframeCloseHandler);
+            jitsiFrame.setAttribute("src", url);
+            jitsiFrame.setAttribute("class", "jitsimeet");
+            jitsiFrame.setAttribute("allow", "microphone; camera;");
+            jitsiFrame.setAttribute("frameborder", "0");
+            jitsiFrame.setAttribute("seamless", "seamless");
+            jitsiFrame.setAttribute("allowfullscreen", "true");
+            jitsiFrame.setAttribute("scrolling", "no");
+            jitsiFrame.setAttribute("style", "z-index:1049;width:100%;height:100%;");
+            dynamicDisplayManager.start();
+
+            jitsiFrame.contentWindow.addEventListener(
+                "message",
+                function (event) {
+                    if (
+                        _converse.api.settings
+                            .get("jitsimeet_url")
+                            .indexOf(event.origin) === 0 &&
+                        typeof event.data === "string"
+                    ) {
+                        let data = JSON.parse(event.data);
+                        let jitsiEvent = data["jitsimeet_event"];
+                        if ("close" === jitsiEvent) {
+                            closeJitsi();
+                        }
                     }
                     }
-                  }
-                }, false);
-            }
+                },
+                false
+            );
+        }
+    } };
+
+function initialize() {
+    Strophe = converse.env.Strophe;
+    env = converse.env;
+    const _converse = this._converse;
+    const { api, __ } = _converse;
+    const { BaseModal } = _converse.exports;
+    const { html, render } = converse.env;
+
+    api.settings.extend({
+        jitsimeet_start_option: MEET_START_OPTIONS.INTO_CHAT_WINDOW,
+        jitsimeet_head_display_toggle: false,
+        jitsimeet_modal: false,
+        jitsimeet_url: "https://meet.jit.si",
+    });
+
+    api.listen.on("messageNotification", (data) => handleMessageNotification(_converse, data));
+    api.listen.on( "getToolbarButtons", (toolbar_el, buttons) => getToolbarButtons(_converse, toolbar_el, buttons));
+    api.listen.on("afterMessageBodyTransformed", (text) => afterMessageBodyTransformed(_converse, text));
+
+    class MeetDialog extends BaseModal {
+
+        initialize() {
+            super.initialize();
+            this.listenTo(this.model, "change", () => this.requestUpdate());
+            this.addEventListener('hidden.bs.modal', () => render('', this));
+        }
+
+        getModalTitle () {
+            return __('Meeting room: %1$s', this.model.get('room'));
+        }
+
+        renderModal() {
+            return html`
+                <iframe
+                    src="${this.model.get("url")}"
+                    id="jitsimeet"
+                    allow="microphone; camera;"
+                    frameborder="0"
+                    seamless="seamless"
+                    allowfullscreen="true"
+                    scrolling="no"
+                    style="z-index: 2147483647; width:460px; height:480px; display: inline-block"></iframe>`;
         }
         }
     }
     }
-}));
+
+    api.elements.define('converse-jitsimeet-dialog', MeetDialog);
+
+    console.debug("jitsimeet plugin is ready");
+};
+
+let converse = window.converse;
+
+if (typeof converse === "undefined") {
+    window.addEventListener(
+        'converse-loaded',
+        (ev) => {
+            converse = ev.detail?.converse || ev.converse;
+            converse.plugins.add("jitsimeet", { initialize });
+        }
+    );
+} else {
+    converse.plugins.add("jitsimeet", { initialize });
+}