Browse Source

Upgrade to Webpack 3

Had to make various other changes due to incompatibilities.

- Use the new `lit` package instead of `lit-html` or `lit-element`
- Drop `haunted` since it breaks the rules by specifying `type: module`
  but then doesn't import with file extensions
- Use Sass Dart instead of node-sass (fixes #2445)
- Upgrade Karma
Shaun Wu 4 years ago
parent
commit
9ea8653ef7
100 changed files with 571 additions and 687 deletions
  1. 2 16
      .eslintrc.json
  2. 2 2
      Makefile
  3. 358 386
      package-lock.json
  4. 11 14
      package.json
  5. 3 3
      spec/emojis.js
  6. 4 4
      spec/http-file-upload.js
  7. 26 26
      spec/styling.js
  8. 1 2
      src/headless/core.js
  9. 0 6
      src/headless/package-lock.json
  10. 1 1
      src/headless/package.json
  11. 4 4
      src/headless/plugins/emoji/index.js
  12. 0 56
      src/headless/polyfill.js
  13. 1 1
      src/i18n/index.js
  14. 1 1
      src/modals/base.js
  15. 1 1
      src/modals/templates/add-contact.js
  16. 1 1
      src/modals/templates/alert.js
  17. 1 1
      src/modals/templates/buttons.js
  18. 1 1
      src/modals/templates/chat-status.js
  19. 1 1
      src/modals/templates/image.js
  20. 1 1
      src/modals/templates/message-versions.js
  21. 2 2
      src/modals/templates/muc-details.js
  22. 1 1
      src/modals/templates/muc-invite.js
  23. 1 1
      src/modals/templates/occupant.js
  24. 1 1
      src/modals/templates/profile.js
  25. 1 1
      src/modals/templates/prompt.js
  26. 1 1
      src/modals/templates/user-details.js
  27. 2 2
      src/modals/templates/user-settings.js
  28. 1 1
      src/plugins/bookmark-views/bookmarks-list.js
  29. 1 1
      src/plugins/bookmark-views/templates/form.js
  30. 1 1
      src/plugins/bookmark-views/templates/list.js
  31. 2 2
      src/plugins/chatboxviews/templates/chats.js
  32. 1 1
      src/plugins/chatboxviews/view.js
  33. 1 1
      src/plugins/chatview/bottom-panel.js
  34. 1 1
      src/plugins/chatview/heading.js
  35. 2 2
      src/plugins/chatview/templates/chat-head.js
  36. 1 1
      src/plugins/chatview/templates/chat.js
  37. 1 1
      src/plugins/chatview/templates/chatbox_message_form.js
  38. 1 1
      src/plugins/chatview/templates/toolbar.js
  39. 3 4
      src/plugins/chatview/tests/corrections.js
  40. 1 1
      src/plugins/chatview/tests/me-messages.js
  41. 4 4
      src/plugins/chatview/tests/message-images.js
  42. 19 19
      src/plugins/chatview/tests/messages.js
  43. 24 24
      src/plugins/chatview/tests/xss.js
  44. 1 1
      src/plugins/chatview/utils.js
  45. 1 1
      src/plugins/chatview/view.js
  46. 1 1
      src/plugins/controlbox/controlbox.js
  47. 1 1
      src/plugins/controlbox/loginpanel.js
  48. 1 1
      src/plugins/controlbox/templates/controlbox.js
  49. 1 1
      src/plugins/controlbox/templates/loginpanel.js
  50. 1 1
      src/plugins/controlbox/templates/navback.js
  51. 1 1
      src/plugins/controlbox/templates/toggle.js
  52. 1 1
      src/plugins/dragresize/templates/dragresize.js
  53. 1 2
      src/plugins/headlines-view/index.js
  54. 2 2
      src/plugins/headlines-view/templates/chat-head.js
  55. 1 1
      src/plugins/headlines-view/templates/headlines.js
  56. 1 1
      src/plugins/headlines-view/templates/panel.js
  57. 1 1
      src/plugins/headlines-view/view.js
  58. 1 1
      src/plugins/minimize/templates/chats-panel.js
  59. 1 1
      src/plugins/minimize/templates/trimmed_chat.js
  60. 3 3
      src/plugins/minimize/tests/minchats.js
  61. 2 2
      src/plugins/minimize/view.js
  62. 1 1
      src/plugins/muc-views/bottom-panel.js
  63. 1 1
      src/plugins/muc-views/muc.js
  64. 1 1
      src/plugins/muc-views/templates/ad-hoc-command-form.js
  65. 1 1
      src/plugins/muc-views/templates/ad-hoc-command.js
  66. 1 1
      src/plugins/muc-views/templates/ad-hoc.js
  67. 2 2
      src/plugins/muc-views/templates/add-muc.js
  68. 1 1
      src/plugins/muc-views/templates/moderator-tools.js
  69. 1 1
      src/plugins/muc-views/templates/muc-bottom-panel.js
  70. 1 1
      src/plugins/muc-views/templates/muc-chatarea.js
  71. 1 1
      src/plugins/muc-views/templates/muc-config-form.js
  72. 1 1
      src/plugins/muc-views/templates/muc-description.js
  73. 1 1
      src/plugins/muc-views/templates/muc-destroyed.js
  74. 1 1
      src/plugins/muc-views/templates/muc-disconnect.js
  75. 2 2
      src/plugins/muc-views/templates/muc-head.js
  76. 2 2
      src/plugins/muc-views/templates/muc-list.js
  77. 1 1
      src/plugins/muc-views/templates/muc-nickname-form.js
  78. 1 1
      src/plugins/muc-views/templates/muc-password-form.js
  79. 1 1
      src/plugins/muc-views/templates/muc-sidebar.js
  80. 1 1
      src/plugins/muc-views/templates/muc.js
  81. 1 1
      src/plugins/muc-views/templates/occupant.js
  82. 5 9
      src/plugins/muc-views/tests/corrections.js
  83. 5 5
      src/plugins/muc-views/tests/mentions.js
  84. 1 1
      src/plugins/muc-views/tests/styling.js
  85. 1 1
      src/plugins/muc-views/utils.js
  86. 1 1
      src/plugins/omemo/utils.js
  87. 7 9
      src/plugins/profile/index.js
  88. 1 1
      src/plugins/profile/statusview.js
  89. 1 1
      src/plugins/profile/templates/profile.js
  90. 1 1
      src/plugins/register/panel.js
  91. 1 1
      src/plugins/register/templates/register_panel.js
  92. 1 1
      src/plugins/register/templates/registration_form.js
  93. 1 1
      src/plugins/roomslist/templates/roomslist.js
  94. 1 1
      src/plugins/roomslist/view.js
  95. 1 1
      src/plugins/rootview/templates/root.js
  96. 1 1
      src/plugins/rosterview/contactview.js
  97. 1 1
      src/plugins/rosterview/filterview.js
  98. 1 1
      src/plugins/rosterview/rosterview.js
  99. 1 1
      src/plugins/rosterview/templates/group.js
  100. 1 1
      src/plugins/rosterview/templates/pending_contact.js

+ 2 - 16
.eslintrc.json

@@ -10,8 +10,8 @@
         "jasmine": true,
         "es6": true
     },
-    "plugins": ["lodash"],
-    "extends": ["eslint:recommended", "plugin:lodash/canonical"],
+    "plugins": [],
+    "extends": ["eslint:recommended"],
     "globals": {
         "Uint8Array": true,
         "Promise": true,
@@ -21,20 +21,6 @@
         "window": true
     },
     "rules": {
-        "lodash/prefer-lodash-chain": "off",
-        "lodash/prefer-lodash-method": "off",
-        "lodash/import-scope": "off",
-        "lodash/prefer-constant": "off",
-        "lodash/prefer-get": "off",
-        "lodash/prefer-includes": "off",
-        "lodash/prefer-invoke-map": "off",
-        "lodash/prefer-is-nil": "off",
-        "lodash/prefer-lodash-typecheck": "off",
-        "lodash/prefer-noop": "off",
-        "lodash/prefer-startswith": "off",
-        "lodash/preferred-alias": "off",
-        "lodash/matches-prop-shorthand": "off",
-        "lodash/prop-shorthand": "off",
         "accessor-pairs": "error",
         "array-bracket-spacing": "off",
         "array-callback-return": "error",

+ 2 - 2
Makefile

@@ -16,7 +16,7 @@ OXIPNG			?= oxipng
 PAPER		 	=
 RJS				?= ./node_modules/.bin/r.js
 NPX				?= ./node_modules/.bin/npx
-SASS			?= ./node_modules/.bin/node-sass
+SASS			?= ./node_modules/.bin/sass
 SED				?= sed
 SPHINXBUILD	 	?= ./bin/sphinx-build
 SPHINXOPTS		=
@@ -144,7 +144,7 @@ dist/converse.css:: node_modules
 	npm run dev
 
 dist/website.css:: node_modules src
-	$(SASS) --source-map true --include-path $(BOOTSTRAP) src/shared/styles/website.scss $@
+	$(SASS) --load-path=$(BOOTSTRAP) src/shared/styles/website.scss $@
 
 dist/website.min.css:: node_modules dist/website.css
 	$(CLEANCSS) dist/website.css > $@

File diff suppressed because it is too large
+ 358 - 386
package-lock.json


+ 11 - 14
package.json

@@ -65,7 +65,7 @@
   "devDependencies": {
     "@babel/cli": "^7.10.3",
     "@babel/core": "^7.10.5",
-    "@babel/plugin-proposal-class-properties": "^7.12.1",
+    "@babel/plugin-proposal-class-properties": "^7.13.0",
     "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
     "@babel/plugin-proposal-optional-chaining": "^7.12.1",
     "@babel/plugin-syntax-dynamic-import": "^7.2.0",
@@ -74,7 +74,7 @@
     "@fortawesome/fontawesome-free": "5.14.0",
     "autoprefixer": "^9.8.6",
     "babel-eslint": "^10.1.0",
-    "babel-loader": "^8.1.0",
+    "babel-loader": "^8.2.2",
     "babel-plugin-lodash": "^3.3.4",
     "bootstrap": "^4.6.0",
     "bootstrap.native": "^2.0.27",
@@ -82,33 +82,29 @@
     "clean-css-cli": "^4.3.0",
     "copy-webpack-plugin": "^6.3.2",
     "css-loader": "^3.5.3",
-    "dayjs": "1.8.30",
+    "dayjs": "1.10.4",
     "eslint": "^7.3.0",
-    "eslint-plugin-lodash": "^7.1.0",
     "exports-loader": "^0.7.0",
     "fast-text-encoding": "^1.0.3",
     "favico.js-slevomat": "^0.3.11",
     "file-loader": "^6.0.0",
-    "haunted": "^4.7.0",
     "html-webpack-plugin": "^4.3.0",
     "http-server": "^0.12.3",
     "imports-loader": "^0.8.0",
     "install": "^0.13.0",
     "jasmine": "^3.5.0",
     "jed": "1.1.1",
-    "jsdoc": "^3.6.4",
-    "karma": "^5.1.0",
+    "jsdoc": "^3.6.6",
+    "karma": "^6.3.2",
     "karma-chrome-launcher": "^3.1.0",
     "karma-cli": "^2.0.0",
     "karma-jasmine": "^3.1.1",
     "karma-jasmine-html-reporter": "^1.5.4",
-    "karma-webpack": "^4.0.2",
+    "karma-webpack": "^5.0.0",
     "lerna": "^3.22.1",
-    "lit-element": "^2.4.0",
-    "lit-html": "^1.2.1",
-    "mini-css-extract-plugin": "^0.9.0",
+    "lit": "^2.0.0-rc.1",
+    "mini-css-extract-plugin": "^1.5.1",
     "minimist": "^1.2.3",
-    "node-sass": "^4.14.1",
     "npm": "^6.14.9",
     "po-loader": "^0.5.0",
     "po2json": "^1.0.0-beta",
@@ -116,11 +112,12 @@
     "postcss-loader": "^3.0.0",
     "prettierx": "^0.12.1",
     "run-headless-chromium": "^0.1.1",
-    "sass-loader": "^8.0.2",
+    "sass": "^1.32.12",
+    "sass-loader": "^11.0.1",
     "sinon": "^9.2.4",
     "style-loader": "^0.23.1",
     "urijs": "^1.19.6",
-    "webpack": "^4.43.0",
+    "webpack": "^5.36.1",
     "webpack-cli": "^4.5.0",
     "webpack-dev-server": "^3.11.2",
     "webpack-merge": "^5.7.3",

+ 3 - 3
spec/emojis.js

@@ -355,7 +355,7 @@ describe("Emojis", function () {
             await new Promise(resolve => _converse.on('chatBoxViewInitialized', resolve));
             const view = _converse.api.chatviews.get(contact_jid);
             await new Promise(resolve => view.model.messages.once('rendered', resolve));
-            await u.waitUntil(() => view.querySelector('.chat-msg__text').innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => view.querySelector('.chat-msg__text').innerHTML.replace(/<!-.*?->/g, '') ===
                 '<img class="emoji" draggable="false" title=":innocent:" alt="😇" src="https://twemoji.maxcdn.com/v/12.1.6//72x72/1f607.png">');
 
             const last_msg_sel = 'converse-chat-message:last-child .chat-msg__text';
@@ -414,7 +414,7 @@ describe("Emojis", function () {
             await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')), 1000);
             const picker = await u.waitUntil(() => view.querySelector('converse-emoji-picker'), 1000);
             const custom_category = picker.querySelector('.pick-category[data-category="custom"]');
-            expect(custom_category.innerHTML.replace(/<!---->/g, '').trim()).toBe(
+            expect(custom_category.innerHTML.replace(/<!-.*?->/g, '').trim()).toBe(
                 '<img class="emoji" draggable="false" title=":xmpp:" alt=":xmpp:" src="/dist/images/custom_emojis/xmpp.png">');
 
             const textarea = view.querySelector('textarea.chat-textarea');
@@ -427,7 +427,7 @@ describe("Emojis", function () {
             });
             await new Promise(resolve => view.model.messages.once('rendered', resolve));
             const body = view.querySelector('converse-chat-message-body');
-            await u.waitUntil(() => body.innerHTML.replace(/<!---->/g, '').trim() ===
+            await u.waitUntil(() => body.innerHTML.replace(/<!-.*?->/g, '').trim() ===
                 'Running tests for <img class="emoji" draggable="false" title=":converse:" alt=":converse:" src="/dist/images/custom_emojis/converse.png">');
             done();
         }));

+ 4 - 4
spec/http-file-upload.js

@@ -305,11 +305,11 @@ describe("XEP-0363: HTTP File Upload", function () {
                         `</message>`);
                     const img_link_el = await u.waitUntil(() => view.querySelector('converse-chat-message-body .chat-image__link'), 1000);
                     // Check that the image renders
-                    expect(img_link_el.outerHTML.replace(/<!---->/g, '').trim()).toEqual(
+                    expect(img_link_el.outerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
                         `<a class="chat-image__link" target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                         `<img class="chat-image img-thumbnail" src="${base_url}/logo/conversejs-filled.svg"></a>`);
 
-                    expect(view.querySelector('.chat-msg .chat-msg__media').innerHTML.replace(/<!---->/g, '').trim()).toEqual(
+                    expect(view.querySelector('.chat-msg .chat-msg__media').innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
                         `<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                         `Download image file "conversejs-filled.svg"</a>`);
                     XMLHttpRequest.prototype.send = send_backup;
@@ -409,11 +409,11 @@ describe("XEP-0363: HTTP File Upload", function () {
                         `</message>`);
                     const img_link_el = await u.waitUntil(() => view.querySelector('converse-chat-message-body .chat-image__link'), 1000);
                     // Check that the image renders
-                    expect(img_link_el.outerHTML.replace(/<!---->/g, '').trim()).toEqual(
+                    expect(img_link_el.outerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
                         `<a class="chat-image__link" target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                         `<img class="chat-image img-thumbnail" src="${base_url}/logo/conversejs-filled.svg"></a>`);
 
-                    expect(view.querySelector('.chat-msg .chat-msg__media').innerHTML.replace(/<!---->/g, '').trim()).toEqual(
+                    expect(view.querySelector('.chat-msg .chat-msg__media').innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
                         `<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                         `Download image file "conversejs-filled.svg"</a>`);
 

+ 26 - 26
spec/styling.js

@@ -82,7 +82,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
         msg_el = view.querySelector('converse-chat-message-body');
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'This <span class="styling-directive">*</span>'+
                 '<b>message <span class="styling-directive">_</span><i>contains</i><span class="styling-directive">_</span></b>'+
                 '<span class="styling-directive">*</span>'+
@@ -96,7 +96,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'Here\'s a <span class="styling-directive">~</span><del>strikethrough section</del><span class="styling-directive">~</span>');
 
         // Span directives containing hyperlinks
@@ -106,7 +106,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<span class="styling-directive">~</span>'+
             '<del>Check out this site: <a target="_blank" rel="noopener" href="https://conversejs.org/">https://conversejs.org</a></del>'+
             '<span class="styling-directive">~</span>');
@@ -119,7 +119,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<span class="styling-directive">*</span>'+
             '<b><a target="_blank" rel="noopener" href="https://conversejs.org/logo/conversejs-filled.svg">https://conversejs.org/logo/conversejs-filled.svg</a></b>'+
             '<span class="styling-directive">*</span>');
@@ -131,7 +131,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 5);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<span class="styling-directive">~</span><del> Hello! <span title=":poop:">💩</span> </del><span class="styling-directive">~</span>');
 
         // Span directives don't cross lines
@@ -141,7 +141,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 6);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'This *is not a styling hint \n'+
             ' * <span class="styling-directive">_</span><i>But this is</i><span class="styling-directive">_</span>!');
 
@@ -151,7 +151,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 7);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '(There are three blocks in this body marked by parens,)\n'+
             ' (but there is no *formatting)\n'+
             ' (as spans* may not escape blocks.)\n'+
@@ -164,7 +164,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 8);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '_<span class="styling-directive">_</span><i> hello world </i><span class="styling-directive">_</span>');
 
         // Directives which are parts of words aren't matched
@@ -174,7 +174,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 9);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'Go to ~https://conversejs.org~now <span class="styling-directive">_</span><i>please</i><span class="styling-directive">_</span>');
 
         msg_text = `Go to _https://converse_js.org_ _please_`;
@@ -183,7 +183,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 10);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'Go to <span class="styling-directive">_</span>'+
             '<i><a target="_blank" rel="noopener" href="https://converse_js.org/">https://converse_js.org</a></i>'+
             '<span class="styling-directive">_</span> <span class="styling-directive">_</span><i>please</i><span class="styling-directive">_</span>');
@@ -207,7 +207,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'Here\'s a code block: \n'+
             '<div class="styling-directive">```</div><code class="block">Inside the code-block, &lt;code&gt;hello&lt;/code&gt; we don\'t enable *styling hints* like ~these~\n'+
             '</code><div class="styling-directive">```</div>'
@@ -219,7 +219,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<div class="styling-directive">```</div>'+
             '<code class="block">ignored\n(println "Hello, world!")\n</code>'+
             '<div class="styling-directive">```</div>\n'+
@@ -232,7 +232,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '```ignored\n (println "Hello, world!")\n ```\n\n'+
             ' This should not show up as monospace, '+
             '<span class="styling-directive">*</span><b>preformatted</b><span class="styling-directive">*</span> text ^');
@@ -255,7 +255,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 1);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>This is quoted text\nThis is also quoted</blockquote>\nThis is not quoted');
 
         msg_text = `> This is *quoted* text\n>This is \`also _quoted_\`\nThis is not quoted`;
@@ -264,7 +264,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>This is <span class="styling-directive">*</span><b>quoted</b><span class="styling-directive">*</span> text\n'+
             'This is <span class="styling-directive">`</span><code>also _quoted_</code><span class="styling-directive">`</span></blockquote>\n'+
             'This is not quoted');
@@ -275,7 +275,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-                await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') === "<blockquote><blockquote>This is doubly quoted text</blockquote></blockquote>");
+                await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === "<blockquote><blockquote>This is doubly quoted text</blockquote></blockquote>");
 
         msg_text = `>> This is doubly quoted text`;
         msg = mock.createChatMessage(_converse, contact_jid, msg_text)
@@ -283,7 +283,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-                await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') === "<blockquote><blockquote>This is doubly quoted text</blockquote></blockquote>");
+                await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === "<blockquote><blockquote>This is doubly quoted text</blockquote></blockquote>");
 
         msg_text = ">```\n>ignored\n> <span></span> (println \"Hello, world!\")\n>```\n> This should show up as monospace, preformatted text ^";
         msg = mock.createChatMessage(_converse, contact_jid, msg_text)
@@ -291,7 +291,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 5);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>'+
                 '<div class="styling-directive">```</div>'+
                 '<code class="block">ignored\n &lt;span&gt;&lt;/span&gt; (println "Hello, world!")\n'+
@@ -305,7 +305,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 6);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>```\n (println "Hello, world!")</blockquote>\n\n'+
             'The entire blockquote is a preformatted text block, but this line is plaintext!');
 
@@ -315,7 +315,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 7);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>Also, icons.js is loaded from /dist, instead of dist.</blockquote>\n'+
             '<a target="_blank" rel="noopener" href="https://conversejs.org/docs/html/configuration.html#assets-path">https://conversejs.org/docs/html/configuration.html#assets-path</a>');
 
@@ -325,7 +325,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 8);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>Where is it located?</blockquote>\n'+
             '<a target="_blank" rel="noopener" '+
                 'href="https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
@@ -336,7 +336,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 9);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>What do you think of it?</blockquote>\n <span title=":poop:">💩</span>');
 
         msg_text = '> What do you think of it?\n~hello~';
@@ -345,7 +345,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 10);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>What do you think of it?</blockquote>\n<span class="styling-directive">~</span><del>hello</del><span class="styling-directive">~</span>');
 
         msg_text = 'hello world > this is not a quote';
@@ -354,7 +354,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 11);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') === 'hello world &gt; this is not a quote');
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === 'hello world &gt; this is not a quote');
 
         msg_text = '> What do you think of it romeo?\n Did you see this romeo?';
         msg = $msg({
@@ -382,7 +382,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 12);
         msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             `<blockquote>What do you think of it <span class="mention">romeo</span>?</blockquote>\n Did you see this <span class="mention">romeo</span>?`);
         done();
     }));
@@ -421,7 +421,7 @@ describe("An incoming chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
         const msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') === '```\ncode```');
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') === '```\ncode```');
         done();
     }));
 });

+ 1 - 2
src/headless/core.js

@@ -2,7 +2,6 @@
  * @copyright The Converse.js contributors
  * @license Mozilla Public License (MPLv2)
  */
-import './polyfill';
 import Storage from '@converse/skeletor/src/storage.js';
 import _converse from '@converse/headless/shared/_converse';
 import advancedFormat from 'dayjs/plugin/advancedFormat';
@@ -36,7 +35,7 @@ import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
 import { TimeoutError } from '@converse/headless/shared/errors';
 import { createStore, replacePromise } from '@converse/headless/shared/utils';
 import { getOpenPromise } from '@converse/openpromise';
-import { html } from 'lit-element';
+import { html } from 'lit';
 import { sprintf } from 'sprintf-js';
 
 export { _converse };

+ 0 - 6
src/headless/package-lock.json

@@ -31,12 +31,6 @@
 				"immediate": "~3.0.5"
 			}
 		},
-		"lit-html": {
-			"version": "1.3.0",
-			"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.3.0.tgz",
-			"integrity": "sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q==",
-			"dev": true
-		},
 		"localforage": {
 			"version": "1.7.3",
 			"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz",

+ 1 - 1
src/headless/package.json

@@ -36,7 +36,7 @@
   },
   "gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2",
   "devDependencies": {
-    "@converse/skeletor": "0.0.3",
+    "@converse/skeletor": "conversejs/skeletor#fe855404babc08cbb1018231eb49a7b7e497539c",
     "filesize": "^6.1.0",
     "localforage": "^1.9.0",
     "localforage-driver-memory": "^1.0.5",

+ 4 - 4
src/headless/plugins/emoji/index.js

@@ -7,7 +7,7 @@ import { ASCII_REPLACE_REGEX, CODEPOINTS_REGEX } from './regexes.js';
 import { Model } from '@converse/skeletor/src/model.js';
 import { _converse, api, converse } from "../../core.js";
 import { getOpenPromise } from '@converse/openpromise';
-import { html } from 'lit-html';
+import { html } from 'lit';
 
 const u = converse.env.utils;
 
@@ -277,7 +277,7 @@ converse.plugins.add('converse-emoji', {
              * Returns an emoji represented by the passed in shortname.
              * Scans the passed in text for shortnames and replaces them with
              * emoji unicode glyphs or alternatively if it's a custom emoji
-             * without unicode representation then a lit-html TemplateResult
+             * without unicode representation then a lit TemplateResult
              * which represents image tag markup is returned.
              *
              * The shortname needs to be defined in `emojis.json`
@@ -291,13 +291,13 @@ converse.plugins.add('converse-emoji', {
              *  unicode codepoints. If so, the returned result will be an array
              *  with containing one string, because the emojis themselves will
              *  also be strings. If set to false, emojis will be represented by
-             *  lit-html TemplateResult objects.
+             *  lit TemplateResult objects.
              * @param { Boolean } options.add_title_wrapper - Whether unicode
              *  codepoints should be wrapped with a `<span>` element with a
              *  title, so that the shortname is shown upon hovering with the
              *  mouse.
              * @returns {Array} An array of at least one string, or otherwise
-             * strings and lit-html TemplateResult objects.
+             * strings and lit TemplateResult objects.
              */
             shortnamesToEmojis (str, options={unicode_only: false, add_title_wrapper: false}) {
                 str = convertASCII2Emoji(str);

+ 0 - 56
src/headless/polyfill.js

@@ -1,56 +0,0 @@
-function CustomEvent ( event, params ) {
-    params = params || { bubbles: false, cancelable: false, detail: undefined };
-    const evt = document.createEvent( 'CustomEvent' );
-    evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
-    return evt;
-}
-if ( typeof window.CustomEvent !== "function" ) {
-    CustomEvent.prototype = window.Event.prototype;
-    window.CustomEvent = CustomEvent;
-}
-
-if (!String.prototype.includes) {
-  String.prototype.includes = function(search, start) {
-        'use strict';
-        if (typeof start !== 'number') {
-            start = 0;
-        }
-        if (start + search.length > this.length) {
-            return false;
-        } else {
-            return this.indexOf(search, start) !== -1;  // eslint-disable-line lodash/prefer-includes
-        }
-  };
-}
-
-if (!String.prototype.endsWith) {
-  String.prototype.endsWith = function (searchString, position) {
-      const subjectString = this.toString();
-      if (position === undefined || position > subjectString.length) {
-          position = subjectString.length;
-      }
-      position -= searchString.length;
-      const lastIndex = subjectString.indexOf(searchString, position);
-      return lastIndex !== -1 && lastIndex === position;
-  };
-}
-
-if (!String.prototype.startsWith) {
-    String.prototype.startsWith = function (searchString, position) {
-        position = position || 0;
-        return this.substr(position, searchString.length) === searchString;
-    };
-}
-
-if (!String.prototype.splitOnce) {
-    String.prototype.splitOnce = function (delimiter) {
-        const components = this.split(delimiter);
-        return [components.shift(), components.join(delimiter)];
-    };
-}
-
-if (!String.prototype.trim) {
-    String.prototype.trim = function () {
-        return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
-    };
-}

+ 1 - 1
src/i18n/index.js

@@ -79,7 +79,7 @@ async function fetchTranslations (_converse) {
         return;
     }
     const { default: data } = await import(/*webpackChunkName: "locales/[request]" */ `../i18n/${locale}/LC_MESSAGES/converse.po`);
-    await import(/*webpackChunkName: "locales/dayjs/[request]" */ `dayjs/locale/${dayjs_locale}`);
+    await import(/*webpackChunkName: "locales/dayjs/[request]" */ `dayjs/locale/${dayjs_locale}.js`);
     dayjs.locale(getLocale(dayjs_locale, l => dayjs.locale(l)));
     jed_instance = new Jed(data);
 }

+ 1 - 1
src/modals/base.js

@@ -3,7 +3,7 @@ import log from "@converse/headless/log";
 import tpl_alert_component from "templates/alert.js";
 import { View } from '@converse/skeletor/src/view.js';
 import { api, converse } from "@converse/headless/core";
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 import './styles/_modal.scss';
 

+ 1 - 1
src/modals/templates/add-contact.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from '../../i18n';
 import { modal_header_close_button } from "./buttons.js"
 

+ 1 - 1
src/modals/templates/alert.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "./buttons.js"
 
 

+ 1 - 1
src/modals/templates/buttons.js

@@ -1,5 +1,5 @@
 import { __ } from '../../i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 export const modal_close_button = html`<button type="button" class="btn btn-secondary" data-dismiss="modal">${__('Close')}</button>`;

+ 1 - 1
src/modals/templates/chat-status.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "./buttons.js"
 
 

+ 1 - 1
src/modals/templates/image.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from '../../i18n';
 import { modal_close_button, modal_header_close_button } from "./buttons.js"
 

+ 1 - 1
src/modals/templates/message-versions.js

@@ -1,6 +1,6 @@
 import dayjs from 'dayjs';
 import { __ } from '../../i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_close_button, modal_header_close_button } from "./buttons.js"
 
 

+ 2 - 2
src/modals/templates/muc-details.js

@@ -1,7 +1,7 @@
 import { __ } from '../../i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_close_button, modal_header_close_button } from "./buttons.js"
-import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
+import { unsafeHTML } from 'lit/directives/unsafe-html.js';
 import xss from "xss/dist/xss";
 
 

+ 1 - 1
src/modals/templates/muc-invite.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from '../../i18n';
 import { modal_header_close_button } from "./buttons.js"
 

+ 1 - 1
src/modals/templates/occupant.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_close_button, modal_header_close_button } from "./buttons.js"
 import { renderAvatar } from 'shared/directives/avatar';
 

+ 1 - 1
src/modals/templates/profile.js

@@ -2,7 +2,7 @@ import "shared/components/image-picker.js";
 import spinner from "templates/spinner.js";
 import { __ } from 'i18n';
 import { _converse, converse } from  "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "./buttons.js";
 
 const u = converse.env.utils;

+ 1 - 1
src/modals/templates/prompt.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from '../../i18n';
 
 

+ 1 - 1
src/modals/templates/user-details.js

@@ -1,6 +1,6 @@
 import avatar from 'shared/templates/avatar.js';
 import { __ } from 'i18n';
-import { html } from 'lit-html';
+import { html } from 'lit';
 import { modal_close_button, modal_header_close_button } from './buttons.js'
 
 

+ 2 - 2
src/modals/templates/user-settings.js

@@ -1,9 +1,9 @@
 import xss from "xss/dist/xss";
 import { __ } from '../../i18n';
 import { api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "./buttons.js"
-import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
+import { unsafeHTML } from 'lit/directives/unsafe-html.js';
 
 
 const tpl_navigation = (o) => {

+ 1 - 1
src/plugins/bookmark-views/bookmarks-list.js

@@ -2,7 +2,7 @@ import tpl_bookmarks_list from './templates/list.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { _converse, api, converse } from '@converse/headless/core';
 import { initStorage } from '@converse/headless/shared/utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 const { Strophe } = converse.env;
 const u = converse.env.utils;

+ 1 - 1
src/plugins/bookmark-views/templates/form.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 

+ 1 - 1
src/plugins/bookmark-views/templates/list.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 

+ 2 - 2
src/plugins/chatboxviews/templates/chats.js

@@ -1,5 +1,5 @@
-import { html } from 'lit-html';
-import { repeat } from 'lit-html/directives/repeat.js';
+import { html } from 'lit';
+import { repeat } from 'lit/directives/repeat.js';
 import { _converse, api } from '@converse/headless/core';
 
 

+ 1 - 1
src/plugins/chatboxviews/view.js

@@ -2,7 +2,7 @@ import tpl_background_logo from '../../templates/background_logo.js';
 import tpl_chats from './templates/chats.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { api, _converse } from '@converse/headless/core';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
 class ConverseChats extends ElementView {

+ 1 - 1
src/plugins/chatview/bottom-panel.js

@@ -3,7 +3,7 @@ import tpl_toolbar from './templates/toolbar.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
-import { html, render } from 'lit-html';
+import { html, render } from 'lit';
 import { clearMessages, parseMessageForCommands } from './utils.js';
 
 const { u } = converse.env;

+ 1 - 1
src/plugins/chatview/heading.js

@@ -5,7 +5,7 @@ import { ElementView } from '@converse/skeletor/src/element.js';
 import { __ } from 'i18n';
 import { _converse, api } from "@converse/headless/core";
 import { getHeadingDropdownItem, getHeadingStandaloneButton } from 'plugins/chatview/utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
 export default class ChatHeading extends ElementView {

+ 2 - 2
src/plugins/chatview/templates/chat-head.js

@@ -1,7 +1,7 @@
 import { _converse } from '@converse/headless/core';
-import { html } from "lit-html";
+import { html } from "lit";
 import { renderAvatar } from 'shared/directives/avatar.js';
-import { until } from 'lit-html/directives/until.js';
+import { until } from 'lit/directives/until.js';
 
 
 export default (o) => {

+ 1 - 1
src/plugins/chatview/templates/chat.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default (o) => html`
     <div class="flyout box-flyout">

+ 1 - 1
src/plugins/chatview/templates/chatbox_message_form.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 export default (o) => html`

+ 1 - 1
src/plugins/chatview/templates/toolbar.js

@@ -1,6 +1,6 @@
 import 'shared/chat/toolbar.js';
 import { api } from '@converse/headless/core.js';
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default (o) => {
     const message_limit = api.settings.get('message_limit');

+ 3 - 4
src/plugins/chatview/tests/corrections.js

@@ -53,7 +53,7 @@ describe("A Chat Message", function () {
             keyCode: 13 // Enter
         });
         expect(_converse.connection.send).toHaveBeenCalled();
-        await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent.replace(/<!---->/g, '') === new_text);
+        await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent.replace(/<!-.*?->/g, '') === new_text);
 
         const msg = _converse.connection.send.calls.all()[0].args[0];
         expect(msg.toLocaleString())
@@ -107,7 +107,7 @@ describe("A Chat Message", function () {
             keyCode: 13 // Enter
         });
         await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-msg__text'))
-            .filter(m => m.textContent.replace(/<!---->/g, '') === new_text).length);
+            .filter(m => m.textContent.replace(/<!-.*?->/g, '') === new_text).length);
         expect(view.querySelectorAll('.chat-msg').length).toBe(2);
 
         textarea.value =  'Arise, fair sun, and kill the envious moon';
@@ -345,8 +345,7 @@ describe("A Chat Message", function () {
             await u.waitUntil(() => u.isVisible(modal.el), 1000);
             const older_msgs = modal.el.querySelectorAll('.older-msg');
             expect(older_msgs.length).toBe(2);
-            expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-            expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
+            expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
             expect(view.model.messages.models.length).toBe(1);
             done();
         }));

+ 1 - 1
src/plugins/chatview/tests/me-messages.js

@@ -49,7 +49,7 @@ describe("A Groupchat Message", function () {
                 .c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'13', 'end':'19', 'type':'mention', 'uri':'xmpp:romeo@montague.lit'}).nodeTree;
         await view.model.handleMessageStanza(msg);
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
-        await u.waitUntil(() => sizzle('.chat-msg__text:last', view).pop().innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => sizzle('.chat-msg__text:last', view).pop().innerHTML.replace(/<!-.*?->/g, '') ===
             'mentions <span class="mention mention--self badge badge-info">romeo</span>');
         done();
     }));

+ 4 - 4
src/plugins/chatview/tests/message-images.js

@@ -16,7 +16,7 @@ describe("A Chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length, 1000)
         expect(view.model.sendMessage).toHaveBeenCalled();
         let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
-        expect(msg.innerHTML.replace(/<!---->/g, '').trim()).toEqual(
+        expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
             `<a class="chat-image__link" target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                 `<img class="chat-image img-thumbnail" src="https://conversejs.org/logo/conversejs-filled.svg">`+
             `</a>`);
@@ -26,7 +26,7 @@ describe("A Chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 2, 1000);
         expect(view.model.sendMessage).toHaveBeenCalled();
         msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
-        expect(msg.innerHTML.replace(/<!---->/g, '').trim()).toEqual(
+        expect(msg.innerHTML.replace(/<!-.*?->/g, '').trim()).toEqual(
             `<a class="chat-image__link" target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg?param1=val1&amp;param2=val2">`+
                 `<img class="chat-image img-thumbnail" src="${message.replace(/&/g, '&amp;')}">`+
             `</a>`);
@@ -91,7 +91,7 @@ describe("A Chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length, 1000)
         expect(view.model.sendMessage).toHaveBeenCalled();
         const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
-        await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '').trim() ==
+        await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() ==
             `<a target="_blank" rel="noopener" href="https://conversejs.org/logo/non-existing.svg">https://conversejs.org/logo/non-existing.svg</a>`, 1000);
         done();
     }));
@@ -114,7 +114,7 @@ describe("A Chat Message", function () {
         expect(view.model.sendMessage).toHaveBeenCalled();
         await u.waitUntil(() => view.querySelector('.chat-content .chat-msg'), 1000);
         const msg = view.querySelector('.chat-content .chat-msg .chat-msg__text');
-        await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '').trim() ==
+        await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() ==
             `<a target="_blank" rel="noopener" href="https://pbs.twimg.com/media/string?format=jpg&amp;name=small">https://pbs.twimg.com/media/string?format=jpg&amp;name=small</a>`, 1000);
         done();
     }));

+ 19 - 19
src/plugins/chatview/tests/messages.js

@@ -512,7 +512,7 @@ describe("A Chat Message", function () {
         expect(view.model.sendMessage).toHaveBeenCalled();
         const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
         expect(msg.textContent).toEqual(message);
-        expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
+        expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('&lt;p&gt;This message contains &lt;em&gt;some&lt;/em&gt; &lt;b&gt;markup&lt;/b&gt;&lt;/p&gt;');
         done();
     }));
 
@@ -531,7 +531,7 @@ describe("A Chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
         const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
         expect(msg.textContent).toEqual(message);
-        await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
             'This message contains a hyperlink: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
         done();
     }));
@@ -549,7 +549,7 @@ describe("A Chat Message", function () {
         await mock.sendMessage(view, message);
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
         let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
-        await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
             'This message contains a hyperlink with forbidden query params: <a target="_blank" rel="noopener" href="https://www.opkode.com/?id=0">https://www.opkode.com/?id=0</a>');
 
         // Test assigning a string to filter_url_query_params
@@ -559,7 +559,7 @@ describe("A Chat Message", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
         msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
         expect(msg.textContent).toEqual(message);
-        await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
             'Another message with a hyperlink with forbidden query params: '+
             '<a target="_blank" rel="noopener" href="https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1">https://www.opkode.com/?id=0&amp;utm_content=1&amp;s=1</a>');
         done();
@@ -577,7 +577,7 @@ describe("A Chat Message", function () {
             </message>`);
         _converse.connection._dataRecv(mock.createRequest(stanza));
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length);
-        expect(view.querySelector('.chat-msg__text').innerHTML.replace(/<!---->/g, '')).toBe('Hey\nHave you heard the news?');
+        expect(view.querySelector('.chat-msg__text').innerHTML.replace(/<!-.*?->/g, '')).toBe('Hey\nHave you heard the news?');
         stanza = u.toStanza(`
             <message from="${contact_jid}"
                      type="chat"
@@ -586,7 +586,7 @@ describe("A Chat Message", function () {
             </message>`);
         _converse.connection._dataRecv(mock.createRequest(stanza));
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 2);
-        const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!---->/g, '');
+        const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!-.*?->/g, '');
         expect(text).toBe('Hey\n\u200B\nHave you heard the news?');
         stanza = u.toStanza(`
             <message from="${contact_jid}"
@@ -596,7 +596,7 @@ describe("A Chat Message", function () {
             </message>`);
         _converse.connection._dataRecv(mock.createRequest(stanza));
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
-        expect(view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!---->/g, '')).toBe('Hey\nHave you heard\nthe news?');
+        expect(view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!-.*?->/g, '')).toBe('Hey\nHave you heard\nthe news?');
 
         stanza = u.toStanza(`
             <message from="${contact_jid}"
@@ -607,7 +607,7 @@ describe("A Chat Message", function () {
         _converse.connection._dataRecv(mock.createRequest(stanza));
         await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 4);
         await u.waitUntil(() => {
-            const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!---->/g, '');
+            const text = view.querySelector('converse-chat-message:last-child .chat-msg__text').innerHTML.replace(/<!-.*?->/g, '');
             return text === 'Hey\nHave you heard\n\u200B\nthe news?\n<a target="_blank" rel="noopener" href="https://conversejs.org/">https://conversejs.org</a>';
         });
         done();
@@ -1301,7 +1301,7 @@ describe("A Chat Message", function () {
             expect(u.hasClass('chat-msg__text', msg)).toBe(true);
             expect(msg.textContent).toEqual('Have you heard this funny audio?');
             let media = view.querySelector('.chat-msg .chat-msg__media');
-            expect(media.innerHTML.replace(/<!---->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
+            expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
                 `<audio controls="" src="https://montague.lit/audio.mp3"></audio>    `+
                 `<a target="_blank" rel="noopener" href="https://montague.lit/audio.mp3">Download audio file "audio.mp3"</a>`);
 
@@ -1316,9 +1316,9 @@ describe("A Chat Message", function () {
             _converse.connection._dataRecv(mock.createRequest(stanza));
             await new Promise(resolve => view.model.messages.once('rendered', resolve));
             msg = view.querySelector('.chat-msg:last-child .chat-msg__text');
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('Have you heard this funny audio?'); // Emtpy
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('Have you heard this funny audio?'); // Emtpy
             media = view.querySelector('.chat-msg:last-child .chat-msg__media');
-            expect(media.innerHTML.replace(/<!---->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
+            expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "").trim()).toEqual(
                 `<audio controls="" src="https://montague.lit/audio.mp3"></audio>    `+
                 `<a target="_blank" rel="noopener" href="https://montague.lit/audio.mp3">`+
                 `Download audio file "audio.mp3"</a>`);
@@ -1349,8 +1349,8 @@ describe("A Chat Message", function () {
             expect(msg.classList.length).toBe(1);
             expect(msg.textContent).toEqual('Have you seen this funny video?');
             let media = view.querySelector('.chat-msg .chat-msg__media');
-            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
-                `<!----><video controls="" preload="metadata" style="max-height: 50vh" src="https://montague.lit/video.mp4"></video><!---->`);
+            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual(
+                `<video controls="" preload="metadata" style="max-height: 50vh" src="https://montague.lit/video.mp4"></video>`);
 
 
             // If the <url> and <body> contents is the same, don't duplicate.
@@ -1364,10 +1364,10 @@ describe("A Chat Message", function () {
             _converse.connection._dataRecv(mock.createRequest(stanza));
             await new Promise(resolve => view.model.messages.once('rendered', resolve));
             msg = view.querySelector('.chat-msg:last-child .chat-msg__text');
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('Have you seen this funny video?');
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('Have you seen this funny video?');
             media = view.querySelector('.chat-msg:last-child .chat-msg__media');
-            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
-                `<!----><video controls="" preload="metadata" style="max-height: 50vh" src="https://montague.lit/video.mp4"></video><!---->`);
+            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual(
+                `<video controls="" preload="metadata" style="max-height: 50vh" src="https://montague.lit/video.mp4"></video>`);
             done();
         }));
 
@@ -1395,8 +1395,8 @@ describe("A Chat Message", function () {
             expect(u.hasClass('chat-msg__text', msg)).toBe(true);
             expect(msg.textContent).toEqual('Have you downloaded this funny file?');
             const media = view.querySelector('.chat-msg .chat-msg__media');
-            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
-                `<!----><a target="_blank" rel="noopener" href="https://montague.lit/funny.pdf"><!---->Download file "funny.pdf"<!----></a><!---->`);
+            expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "").replace(/<!-.*?->/g, '')).toEqual(
+                `<a target="_blank" rel="noopener" href="https://montague.lit/funny.pdf">Download file "funny.pdf"</a>`);
             done();
         }));
 
@@ -1428,7 +1428,7 @@ describe("A Chat Message", function () {
             expect(u.hasClass('chat-msg__text', msg)).toBe(true);
             expect(msg.textContent).toEqual('Have you seen this funny image?');
             const media = view.querySelector('.chat-msg .chat-msg__media');
-            expect(media.innerHTML.replace(/<!---->/g, '').replace(/(\r\n|\n|\r)/gm, "")).toEqual(
+            expect(media.innerHTML.replace(/<!-.*?->/g, '').replace(/(\r\n|\n|\r)/gm, "")).toEqual(
                 `<a target="_blank" rel="noopener" href="${base_url}/logo/conversejs-filled.svg">`+
                 `Download image file "conversejs-filled.svg"</a>`);
             done();

+ 24 - 24
src/plugins/chatview/tests/xss.js

@@ -19,44 +19,44 @@ describe("XSS", function () {
             await mock.sendMessage(view, message);
             let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;img src=x onerror=alert('XSS');&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;img src=x onerror=alert('XSS');&gt;");
             expect(window.alert).not.toHaveBeenCalled();
 
             message = "<img src=x onerror=alert('XSS')//";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;img src=x onerror=alert('XSS')//");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;img src=x onerror=alert('XSS')//");
 
             message = "<img src=x onerror=alert(String.fromCharCode(88,83,83));>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
 
             message = "<img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));&gt;");
 
             message = "<img src=x:alert(alt) onerror=eval(src) alt=xss>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;img src=x:alert(alt) onerror=eval(src) alt=xss&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;img src=x:alert(alt) onerror=eval(src) alt=xss&gt;");
 
             message = "><img src=x onerror=alert('XSS');>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert('XSS');&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert('XSS');&gt;");
 
             message = "><img src=x onerror=alert(String.fromCharCode(88,83,83));>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&gt;&lt;img src=x onerror=alert(String.fromCharCode(88,83,83));&gt;");
 
             expect(window.alert).not.toHaveBeenCalled();
             done();
@@ -75,43 +75,43 @@ describe("XSS", function () {
             await mock.sendMessage(view, message);
             let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('&lt;svgonload=alert(1)&gt;');
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('&lt;svgonload=alert(1)&gt;');
 
             message = "<svg/onload=alert('XSS')>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;svg/onload=alert('XSS')&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;svg/onload=alert('XSS')&gt;");
 
             message = "<svg onload=alert(1)//";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;svg onload=alert(1)//");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;svg onload=alert(1)//");
 
             message = "<svg/onload=alert(String.fromCharCode(88,83,83))>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;");
 
             message = "<svg id=alert(1) onload=eval(id)>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual("&lt;svg id=alert(1) onload=eval(id)&gt;");
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual("&lt;svg id=alert(1) onload=eval(id)&gt;");
 
             message = '"><svg/onload=alert(String.fromCharCode(88,83,83))>';
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;');
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(String.fromCharCode(88,83,83))&gt;');
 
             message = '"><svg/onload=alert(/XSS/)';
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(/XSS/)');
+            expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual('"&gt;&lt;svg/onload=alert(/XSS/)');
 
             expect(window.alert).not.toHaveBeenCalled();
             done();
@@ -132,43 +132,43 @@ describe("XSS", function () {
 
             let msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            expect(msg.innerHTML.replace(/<!---->/g, ''))
+            expect(msg.innerHTML.replace(/<!-.*?->/g, ''))
                 .toEqual('http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever');
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
                 '<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
 
             message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
                 '<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
 
             message = "https://en.wikipedia.org/wiki/Ender's_Game";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') === '<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') === '<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">'+message+'</a>');
 
             message = "<https://bugs.documentfoundation.org/show_bug.cgi?id=123737>";
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
                 `&lt;<a target="_blank" rel="noopener" href="https://bugs.documentfoundation.org/show_bug.cgi?id=123737">https://bugs.documentfoundation.org/show_bug.cgi?id=123737</a>&gt;`);
 
             message = '<http://www.opkode.com/"onmouseover="alert(1)"whatever>';
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
                 '&lt;<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>&gt;');
 
             message = `https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2`
             await mock.sendMessage(view, message);
             msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
             expect(msg.textContent).toEqual(message);
-            await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') ===
+            await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') ===
                 `<a target="_blank" rel="noopener" href="https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=%213m6%211e1%213m4%211sQ7SdHo_bPLPlLlU8GSGWaQ%212e0%217i13312%218i6656%214m5%213m4%211s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08%218m2%213d52.3773668%214d4.5489388%215m1%211e2">https://www.google.com/maps/place/Kochstraat+6,+2041+CE+Zandvoort/@52.3775999,4.548971,3a,15y,170.85h,88.39t/data=!3m6!1e1!3m4!1sQ7SdHo_bPLPlLlU8GSGWaQ!2e0!7i13312!8i6656!4m5!3m4!1s0x47c5ec1e56f845ad:0x1de0bc4a5771fb08!8m2!3d52.3773668!4d4.5489388!5m1!1e2</a>`);
             done();
         }));
@@ -211,19 +211,19 @@ describe("XSS", function () {
             function checkNonParsedURL (url) {
                 const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
                 expect(msg.textContent).toEqual(url);
-                expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual(url);
+                expect(msg.innerHTML.replace(/<!-.*?->/g, '')).toEqual(url);
             }
 
             async function checkParsedURL ({ entered, href }) {
                 const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
                 expect(msg.textContent).toEqual(entered);
-                await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '') === `<a target="_blank" rel="noopener" href="${href}">${entered}</a>`);
+                await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '') === `<a target="_blank" rel="noopener" href="${href}">${entered}</a>`);
             }
 
             async function checkParsedXMPPURL ({ entered, href }) {
                 const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
                 expect(msg.textContent.trim()).toEqual(entered);
-                await u.waitUntil(() => msg.innerHTML.replace(/<!---->/g, '').trim() === `<a target="_blank" rel="noopener" href="${href}">${entered}</a>`);
+                await u.waitUntil(() => msg.innerHTML.replace(/<!-.*?->/g, '').trim() === `<a target="_blank" rel="noopener" href="${href}">${entered}</a>`);
             }
 
             await mock.sendMessage(view, bad_urls[0]);

+ 1 - 1
src/plugins/chatview/utils.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { _converse } from "@converse/headless/core";
-import { html } from 'lit-html';
+import { html } from 'lit';
 
 
 export async function getHeadingDropdownItem (promise_or_data) {

+ 1 - 1
src/plugins/chatview/view.js

@@ -1,6 +1,6 @@
 import 'plugins/chatview/heading.js';
 import 'plugins/chatview/bottom-panel.js';
-import { html, render } from 'lit-html';
+import { html, render } from 'lit';
 import BaseChatView from 'shared/chat/baseview.js';
 import tpl_chat from './templates/chat.js';
 import { __ } from 'i18n';

+ 1 - 1
src/plugins/controlbox/controlbox.js

@@ -1,7 +1,7 @@
 import tpl_controlbox from './templates/controlbox.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { _converse, api, converse } from '@converse/headless/core';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 const u = converse.env.utils;
 

+ 1 - 1
src/plugins/controlbox/loginpanel.js

@@ -4,7 +4,7 @@ import { ElementView } from "@converse/skeletor/src/element";
 import { Model } from '@converse/skeletor/src/model.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 const u = converse.env.utils;
 const { Strophe } = converse.env;

+ 1 - 1
src/plugins/controlbox/templates/controlbox.js

@@ -1,4 +1,4 @@
-import { html } from 'lit-html';
+import { html } from 'lit';
 import { _converse, api } from "@converse/headless/core";
 
 export default o => html`

+ 1 - 1
src/plugins/controlbox/templates/loginpanel.js

@@ -2,7 +2,7 @@ import 'shared/components/brand-heading.js';
 import tpl_spinner from 'templates/spinner.js';
 import { __ } from 'i18n';
 import { _converse, api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 const trust_checkbox = (checked) => {

+ 1 - 1
src/plugins/controlbox/templates/navback.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { navigateToControlBox } from '../utils.js';
 
 export default  (jid) => {

+ 1 - 1
src/plugins/controlbox/templates/toggle.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default  (o) => {
     const i18n_toggle = api.connection.connected() ? __('Chat Contacts') : __('Toggle chat');

+ 1 - 1
src/plugins/dragresize/templates/dragresize.js

@@ -1,4 +1,4 @@
-import { html } from 'lit-html';
+import { html } from 'lit';
 import { onStartDiagonalResize, onStartHorizontalResize, onStartVerticalResize } from '../utils.js';
 
 export default () => html`

+ 1 - 2
src/plugins/headlines-view/index.js

@@ -5,7 +5,7 @@
  */
 import '../chatview/index.js';
 import './view.js';
-import { HeadlinesPanelMixin, HeadlinesPanel } from './panel.js';
+import { HeadlinesPanel } from './panel.js';
 import { _converse, converse } from '@converse/headless/core';
 
 import './styles/headlines.scss';
@@ -25,7 +25,6 @@ converse.plugins.add('converse-headlines-view', {
     dependencies: ['converse-headlines', 'converse-chatview'],
 
     initialize () {
-        _converse.ControlBoxView && Object.assign(_converse.ControlBoxView.prototype, HeadlinesPanelMixin);
         _converse.HeadlinesPanel = HeadlinesPanel;
     }
 });

+ 2 - 2
src/plugins/headlines-view/templates/chat-head.js

@@ -1,6 +1,6 @@
 import { _converse } from '@converse/headless/core';
-import { html } from "lit-html";
-import { until } from 'lit-html/directives/until.js';
+import { html } from "lit";
+import { until } from 'lit/directives/until.js';
 
 
 export default (o) => {

+ 1 - 1
src/plugins/headlines-view/templates/headlines.js

@@ -1,5 +1,5 @@
 import '../heading.js';
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default (o) => html`
     <div class="flyout box-flyout">

+ 1 - 1
src/plugins/headlines-view/templates/panel.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import tpl_headline_list from "templates/headline_list.js";
 
 

+ 1 - 1
src/plugins/headlines-view/view.js

@@ -1,7 +1,7 @@
 import BaseChatView from 'shared/chat/baseview.js';
 import tpl_headlines from './templates/headlines.js';
 import { _converse, api } from '@converse/headless/core';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
 class HeadlinesView extends BaseChatView {

+ 1 - 1
src/plugins/minimize/templates/chats-panel.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 export default (o) =>

+ 1 - 1
src/plugins/minimize/templates/trimmed_chat.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 

+ 3 - 3
src/plugins/minimize/tests/minchats.js

@@ -198,7 +198,7 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
         _converse.minimize.minimize(view.model);
         const unread_count = selectUnreadMsgCount();
         expect(u.isVisible(unread_count)).toBeTruthy();
-        expect(unread_count.innerHTML.replace(/<!---->/g, '')).toBe('1');
+        expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1');
         done();
     }));
 
@@ -216,7 +216,7 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
         await u.waitUntil(() => view.model.messages.length);
         const unread_count = selectUnreadMsgCount();
         expect(u.isVisible(unread_count)).toBeTruthy();
-        expect(unread_count.innerHTML.replace(/<!---->/g, '')).toBe('1');
+        expect(unread_count.innerHTML.replace(/<!-.*?->/g, '')).toBe('1');
         done();
     }));
 
@@ -233,7 +233,7 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
         await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg').length, 1000);
         expect(view.model.sendMessage).toHaveBeenCalled();
         const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
-        await u.waitUntil(() => msg.innerHTML.replace(/\<!----\>/g, '') ===
+        await u.waitUntil(() => msg.innerHTML.replace(/\<!-.*?-\>/g, '') ===
             '<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&amp;'+
             'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&amp;mlon=-122.399677#map=18/37.786971/-122.399677</a>');
         done();

+ 2 - 2
src/plugins/minimize/view.js

@@ -3,10 +3,10 @@ import tpl_chats_panel from './templates/chats-panel.js';
 import { ElementView } from '@converse/skeletor/src/element.js';
 import { _converse, api } from '@converse/headless/core';
 import { initStorage } from '@converse/headless/shared/utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
-class MinimizedChats extends ElementView {
+export default class MinimizedChats extends ElementView {
 
     async initialize () {
         this.model = _converse.chatboxes;

+ 1 - 1
src/plugins/muc-views/bottom-panel.js

@@ -5,7 +5,7 @@ import tpl_muc_bottom_panel from './templates/muc-bottom-panel.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
 import { getAutoCompleteListItem, parseMessageForMUCCommands } from './utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
 export default class MUCBottomPanel extends BottomPanel {

+ 1 - 1
src/plugins/muc-views/muc.js

@@ -5,7 +5,7 @@ import tpl_muc from './templates/muc.js';
 import { Model } from '@converse/skeletor/src/model.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from '@converse/headless/core';
-import { html, render } from "lit-html";
+import { html, render } from "lit";
 
 /**
  * Mixin which turns a ChatBoxView into a ChatRoomView

+ 1 - 1
src/plugins/muc-views/templates/ad-hoc-command-form.js

@@ -1,5 +1,5 @@
 import { __ } from 'i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default (o, command) => {
     const i18n_hide = __('Hide');

+ 1 - 1
src/plugins/muc-views/templates/ad-hoc-command.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import tpl_command_form from './ad-hoc-command-form.js';
 
 export default (o, command) => html`

+ 1 - 1
src/plugins/muc-views/templates/ad-hoc.js

@@ -1,7 +1,7 @@
 import tpl_command from './ad-hoc-command.js';
 import { __ } from 'i18n';
 import { getAutoCompleteList } from '../utils.js';
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 export default (o) => {

+ 2 - 2
src/plugins/muc-views/templates/add-muc.js

@@ -1,8 +1,8 @@
 import xss from "xss/dist/xss";
 import { __ } from 'i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "modals/templates/buttons.js"
-import { unsafeHTML } from "lit-html/directives/unsafe-html.js";
+import { unsafeHTML } from "lit/directives/unsafe-html.js";
 
 
 const nickname_input = (o) => {

+ 1 - 1
src/plugins/muc-views/templates/moderator-tools.js

@@ -1,6 +1,6 @@
 import spinner from "templates/spinner.js";
 import { __ } from 'i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 import { modal_header_close_button } from "modals/templates/buttons.js"
 
 

+ 1 - 1
src/plugins/muc-views/templates/muc-bottom-panel.js

@@ -1,7 +1,7 @@
 import tpl_muc_nickname_form from './muc-nickname-form.js';
 import { __ } from 'i18n';
 import { api, converse } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 const tpl_can_edit = () => html`

+ 1 - 1
src/plugins/muc-views/templates/muc-chatarea.js

@@ -3,7 +3,7 @@ import '../sidebar.js';
 import 'shared/chat/chat-content.js';
 import 'shared/chat/help-messages.js';
 import { _converse } from '@converse/headless/core';
-import { html } from "lit-html";
+import { html } from "lit";
 
 export default (o) => html`
     <div class="chat-area">

+ 1 - 1
src/plugins/muc-views/templates/muc-config-form.js

@@ -1,7 +1,7 @@
 import tpl_spinner from 'templates/spinner.js';
 import { __ } from 'i18n';
 import { api, converse } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 const { sizzle } = converse.env;
 const u = converse.env.utils;

+ 1 - 1
src/plugins/muc-views/templates/muc-description.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 export default  (o) => {

+ 1 - 1
src/plugins/muc-views/templates/muc-destroyed.js

@@ -1,5 +1,5 @@
 import { __ } from 'i18n';
-import { html } from "lit-html";
+import { html } from "lit";
 
 const tpl_moved = (o) => {
     const i18n_moved = __('The conversation has moved to a new address. Click the link below to enter.');

+ 1 - 1
src/plugins/muc-views/templates/muc-disconnect.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 export default (messages) => {

+ 2 - 2
src/plugins/muc-views/templates/muc-head.js

@@ -2,8 +2,8 @@ import 'shared/components/dropdown.js';
 import 'shared/components/rich-text.js';
 import { __ } from 'i18n';
 import { _converse } from "@converse/headless/core";
-import { html } from "lit-html";
-import { until } from 'lit-html/directives/until.js';
+import { html } from "lit";
+import { until } from 'lit/directives/until.js';
 
 const tpl_standalone_btns = (o) => o.standalone_btns.reverse().map(b => until(b, ''));
 

+ 2 - 2
src/plugins/muc-views/templates/muc-list.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
-import { html } from "lit-html";
-import { repeat } from 'lit-html/directives/repeat.js';
+import { html } from "lit";
+import { repeat } from 'lit/directives/repeat.js';
 import { modal_close_button, modal_header_close_button } from "modals/templates/buttons.js"
 import spinner from "templates/spinner.js";
 

+ 1 - 1
src/plugins/muc-views/templates/muc-nickname-form.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 function submitNickname (ev, model) {
     ev.preventDefault();

+ 1 - 1
src/plugins/muc-views/templates/muc-password-form.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 

+ 1 - 1
src/plugins/muc-views/templates/muc-sidebar.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 import tpl_occupant from "./occupant.js";
 

+ 1 - 1
src/plugins/muc-views/templates/muc.js

@@ -5,7 +5,7 @@ import '../disconnected.js';
 import '../heading.js';
 import '../nickname-form.js';
 import '../password-form.js';
-import { html } from "lit-html";
+import { html } from "lit";
 import { getChatRoomBodyTemplate } from '../utils.js';
 
 

+ 1 - 1
src/plugins/muc-views/templates/occupant.js

@@ -1,4 +1,4 @@
-import { html } from "lit-html";
+import { html } from "lit";
 import { __ } from 'i18n';
 
 

+ 5 - 9
src/plugins/muc-views/tests/corrections.js

@@ -64,10 +64,8 @@ describe("A Groupchat Message", function () {
         await u.waitUntil(() => u.isVisible(modal.el), 1000);
         const older_msgs = modal.el.querySelectorAll('.older-msg');
         expect(older_msgs.length).toBe(2);
-        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
-        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
+        expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
+        expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true);
         done();
     }));
 
@@ -158,10 +156,8 @@ describe("A Groupchat Message", function () {
         await u.waitUntil(() => u.isVisible(modal.el), 1000);
         const older_msgs = modal.el.querySelectorAll('.older-msg');
         expect(older_msgs.length).toBe(2);
-        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
-        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
+        expect(older_msgs[0].textContent.includes('But soft, what light through yonder airlock breaks?')).toBe(true);
+        expect(older_msgs[1].textContent.includes('But soft, what light through yonder chimney breaks?')).toBe(true);
         done();
     }));
 
@@ -211,7 +207,7 @@ describe("A Groupchat Message", function () {
         });
         expect(_converse.connection.send).toHaveBeenCalled();
         await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-msg__text'))
-            .filter(m => m.textContent.replace(/<!---->/g, '') === new_text).length);
+            .filter(m => m.textContent.replace(/<!-.*?->/g, '') === new_text).length);
 
         const msg = _converse.connection.send.calls.all()[0].args[0];
         expect(msg.toLocaleString())

+ 5 - 5
src/plugins/muc-views/tests/mentions.js

@@ -58,7 +58,7 @@ describe("An incoming groupchat message", function () {
                 .c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'11', 'end':'14', 'type':'mention', 'uri':'xmpp:romeo@montague.lit'}).up()
                 .c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'15', 'end':'23', 'type':'mention', 'uri':'xmpp:mr.robot@montague.lit'}).nodeTree;
         await view.model.handleMessageStanza(msg);
-        await u.waitUntil(() => view.querySelector('.chat-msg__text')?.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => view.querySelector('.chat-msg__text')?.innerHTML.replace(/<!-.*?->/g, '') ===
             'hello <span class="mention">z3r0</span> '+
             '<span class="mention mention--self badge badge-info">tom</span> '+
             '<span class="mention">mr.robot</span>, how are you?');
@@ -75,7 +75,7 @@ describe("An incoming groupchat message", function () {
         await view.model.handleMessageStanza(msg);
         message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
         expect(message.classList.length).toEqual(1);
-        expect(message.innerHTML.replace(/<!---->/g, '')).toBe(
+        expect(message.innerHTML.replace(/<!-.*?->/g, '')).toBe(
             'hello <span class="mention">z3r0</span> '+
             '<span class="mention mention--self badge badge-info">tom</span> '+
             '<span class="mention">mr.robot</span>, how are you?');
@@ -113,7 +113,7 @@ describe("An incoming groupchat message", function () {
                 .c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'16', 'end':'24', 'type':'mention', 'uri':'xmpp:mr.robot@montague.lit'}).nodeTree;
 
         await view.model.handleMessageStanza(msg);
-        await u.waitUntil(() => view.querySelector('.chat-msg__text')?.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => view.querySelector('.chat-msg__text')?.innerHTML.replace(/<!-.*?->/g, '') ===
             '<blockquote>hello <span class="mention">z3r0</span> <span class="mention mention--self badge badge-info">tom</span> <span class="mention">mr.robot</span>, how are you?</blockquote>');
         const message = view.querySelector('.chat-msg__text');
         expect(message.classList.length).toEqual(1);
@@ -380,7 +380,7 @@ describe("A sent groupchat message", function () {
 
             const last_msg_sel = 'converse-chat-message:last-child .chat-msg__text';
             await u.waitUntil(() =>
-                view.querySelector(last_msg_sel).innerHTML.replace(/<!---->/g, '') ===
+                view.querySelector(last_msg_sel).innerHTML.replace(/<!-.*?->/g, '') ===
                     'hello <span class="mention">z3r0</span> <span class="mention">gibson</span> <span class="mention">mr.robot</span>, how are you?'
             );
 
@@ -496,7 +496,7 @@ describe("A sent groupchat message", function () {
         const bottom_panel = view.querySelector('converse-muc-bottom-panel');
         bottom_panel.onKeyDown(enter_event);
         const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
-        expect(message.innerHTML.replace(/<!---->/g, '')).toEqual(
+        expect(message.innerHTML.replace(/<!-.*?->/g, '')).toEqual(
             `Welcome <span class="mention">gibson</span> <span title=":poop:">💩</span> `+
             `We have a guide on how to do that here: `+
             `<a target="_blank" rel="noopener" href="https://conversejs.org/docs/html/index.html">https://conversejs.org/docs/html/index.html</a>`);

+ 1 - 1
src/plugins/muc-views/tests/styling.js

@@ -25,7 +25,7 @@ describe("A outgoing groupchat Message", function () {
 
         const msg_el = Array.from(view.querySelectorAll('converse-chat-message-body')).pop();
         expect(msg_el.innerText).toBe(msg_text);
-        await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
+        await u.waitUntil(() => msg_el.innerHTML.replace(/<!-.*?->/g, '') ===
             'This <span class="styling-directive">*</span><b>message mentions <span class="mention mention--self badge badge-info">romeo</span></b><span class="styling-directive">*</span>');
         done();
     }));

+ 1 - 1
src/plugins/muc-views/utils.js

@@ -2,7 +2,7 @@ import log from "@converse/headless/log";
 import tpl_spinner from 'templates/spinner.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 import { parseMessageForCommands } from 'plugins/chatview/utils.js';
 import { setAffiliation } from '@converse/headless/plugins/muc/affiliations/utils.js';
 

+ 1 - 1
src/plugins/omemo/utils.js

@@ -3,7 +3,7 @@ import difference from 'lodash-es/difference';
 import log from '@converse/headless/log';
 import { __ } from 'i18n';
 import { _converse, converse, api } from '@converse/headless/core';
-import { html } from 'lit-html';
+import { html } from 'lit';
 import { initStorage } from '@converse/headless/shared/utils.js';
 
 const { Strophe, sizzle, u } = converse.env;

+ 7 - 9
src/plugins/profile/index.js

@@ -2,13 +2,13 @@
  * @copyright The Converse.js contributors
  * @license Mozilla Public License (MPLv2)
  */
-import "modals/chat-status.js";
-import "modals/profile.js";
-import "../modal.js";
-import "@converse/headless/plugins/status";
-import "@converse/headless/plugins/vcard";
-import XMPPStatusView from './statusview.js';
-import { _converse, api, converse } from "@converse/headless/core";
+import '../modal.js';
+import './statusview.js';
+import '@converse/headless/plugins/status';
+import '@converse/headless/plugins/vcard';
+import 'modals/chat-status.js';
+import 'modals/profile.js';
+import { api, converse } from '@converse/headless/core';
 
 
 converse.plugins.add('converse-profile', {
@@ -20,7 +20,5 @@ converse.plugins.add('converse-profile', {
             'allow_adhoc_commands': true,
             'show_client_info': true
         });
-
-        _converse.XMPPStatusView = XMPPStatusView;
     }
 });

+ 1 - 1
src/plugins/profile/statusview.js

@@ -3,7 +3,7 @@ import tpl_profile from './templates/profile.js';
 import { ElementViewWithAvatar } from 'shared/avatar.js';
 import { __ } from 'i18n';
 import { _converse, api } from '@converse/headless/core';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 
 function getPrettyStatus (stat) {

+ 1 - 1
src/plugins/profile/templates/profile.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 export default (o) => {

+ 1 - 1
src/plugins/register/panel.js

@@ -9,7 +9,7 @@ import utils from "@converse/headless/utils/form";
 import { ElementView } from "@converse/skeletor/src/element";
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 // Strophe methods for building stanzas
 const { Strophe, sizzle, $iq } = converse.env;

+ 1 - 1
src/plugins/register/templates/register_panel.js

@@ -2,7 +2,7 @@ import tpl_registration_form from './registration_form.js';
 import tpl_spinner from 'templates/spinner.js';
 import { __ } from 'i18n';
 import { api } from '@converse/headless/core';
-import { html } from 'lit-html';
+import { html } from 'lit';
 
 const tpl_form_request = () => {
     const default_domain = api.settings.get('registration_domain');

+ 1 - 1
src/plugins/register/templates/registration_form.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { api } from '@converse/headless/core';
-import { html } from 'lit-html';
+import { html } from 'lit';
 
 export default o => {
     const i18n_choose_provider = __('Choose a different provider');

+ 1 - 1
src/plugins/roomslist/templates/roomslist.js

@@ -2,7 +2,7 @@ import AddMUCModal from 'plugins/muc-views/modals/add-muc.js';
 import MUCListModal from 'plugins/muc-views/modals/muc-list.js';
 import { __ } from 'i18n';
 import { _converse, api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 
 const bookmark = (o) => {

+ 1 - 1
src/plugins/roomslist/view.js

@@ -5,7 +5,7 @@ import { Model } from '@converse/skeletor/src/model.js';
 import { __ } from 'i18n';
 import { _converse, api, converse } from "@converse/headless/core";
 import { initStorage } from '@converse/headless/shared/utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 const { Strophe } = converse.env;
 const u = converse.env.utils;

+ 1 - 1
src/plugins/rootview/templates/root.js

@@ -1,6 +1,6 @@
 import 'shared/components/font-awesome.js';
 import { api } from '@converse/headless/core';
-import { html } from 'lit-html';
+import { html } from 'lit';
 
 export default () => {
     let extra_classes = api.settings.get('singleton') ? 'converse-singleton' : '';

+ 1 - 1
src/plugins/rosterview/contactview.js

@@ -9,7 +9,7 @@ import { _converse, api, converse } from "@converse/headless/core";
 const u = converse.env.utils;
 
 
-class RosterContact extends CustomElement {
+export default class RosterContact extends CustomElement {
 
     static get properties () {
         return {

+ 1 - 1
src/plugins/rosterview/filterview.js

@@ -4,7 +4,7 @@ import { ElementView } from '@converse/skeletor/src/element.js';
 import { Model } from '@converse/skeletor/src/model.js';
 import { _converse, api } from "@converse/headless/core";
 import { initStorage } from '@converse/headless/shared/utils.js';
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 export const RosterFilter = Model.extend({
     initialize () {

+ 1 - 1
src/plugins/rosterview/rosterview.js

@@ -3,7 +3,7 @@ import tpl_roster from "./templates/roster.js";
 import { ElementView } from "@converse/skeletor/src/element";
 import { Model } from '@converse/skeletor/src/model.js';
 import { _converse, api, converse } from "@converse/headless/core";
-import { render } from 'lit-html';
+import { render } from 'lit';
 
 const u = converse.env.utils;
 

+ 1 - 1
src/plugins/rosterview/templates/group.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { _converse, converse } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 import { toggleGroup } from '../utils.js';
 
 const { u } = converse.env;

+ 1 - 1
src/plugins/rosterview/templates/pending_contact.js

@@ -1,6 +1,6 @@
 import { __ } from 'i18n';
 import { api } from "@converse/headless/core";
-import { html } from "lit-html";
+import { html } from "lit";
 
 const tpl_pending_contact = o => html`<span class="pending-contact-name" title="JID: ${o.jid}">${o.display_name}</span>`;
 

Some files were not shown because too many files changed in this diff