diff --git a/package-lock.json b/package-lock.json index 92993d39f..3587e2984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11874,6 +11874,15 @@ "minimalistic-assert": "^1.0.1" } }, + "haunted": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/haunted/-/haunted-4.7.0.tgz", + "integrity": "sha512-ajsUengbSL2ELljJ2VLU2o5BfG/drzZV+BvSLALvIBx+24owmxC5iW7+SK/Y667JaVmratEPR010bYpGKAt7ow==", + "dev": true, + "requires": { + "lit-html": "^1.0.0" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", diff --git a/package.json b/package.json index b71f0dd3e..b8ee8875c 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "exports-loader": "^0.7.0", "fast-text-encoding": "^1.0.2", "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", diff --git a/sass/_controlbox.scss b/sass/_controlbox.scss index 35ce9b4fa..c1caf9f76 100644 --- a/sass/_controlbox.scss +++ b/sass/_controlbox.scss @@ -67,9 +67,21 @@ #controlbox { order: -1; - color: var(--controlbox-text-color); + converse-brand-heading { + width: 100%; + display: block; + } + + .brand-name-wrapper { + font-size: 200%; + } + + .brand-name-wrapper--fullscreen { + font-size: 100%; + } + .open-rooms-toggle, .open-rooms-toggle .fa { color: var(--groupchats-header-color) !important; &:hover { @@ -78,7 +90,7 @@ } .box-flyout { - background-color: white; + background-color: var(--controlbox-pane-background-color); } margin-right: calc(3 * var(--chat-gutter)); @@ -178,11 +190,7 @@ } #converse-login-panel { - flex-direction: column; - - .brand-heading { - color: var(--global-background-color); - } + flex-direction: row; } .toggle-register-login { @@ -411,10 +419,6 @@ } } - .brand-heading-container { - width: 100%; - } - .controlbox-head { display: flex; flex-direction: row-reverse; @@ -497,7 +501,7 @@ line-height: var(--line-height-huge); } - .brand-heading-container { + converse-brand-heading { @include make-col(12); margin-top: 5em; margin-bottom: 1em; diff --git a/sass/_core.scss b/sass/_core.scss index 70e93301a..7d3f8d69d 100644 --- a/sass/_core.scss +++ b/sass/_core.scss @@ -137,7 +137,7 @@ body.converse-fullscreen { width: 100%; } - .brand-heading-container { + converse-brand-heading { text-align: center; } @@ -147,43 +147,62 @@ body.converse-fullscreen { align-items: flex-start; font-family: var(--branding-font); color: var(--link-color); - margin-bottom: 1em; + margin-bottom: 0.75em; - .brand-name { - color: var(--link-color); - display: flex; - flex-direction: column; - align-items: center; - margin-top: -0.5em; - } + .brand-name-wrapper { + display: flex; + white-space: nowrap; + margin: auto; + } - .brand-name__text { - font-size: 120%; - vertical-align: text-bottom; - } + .brand-name { + color: var(--link-color); + display: flex; + flex-direction: column; + align-items: center; + margin-top: -0.25em; - .converse-svg-logo { - color: var(--link-color); - height: 1.5em; - margin-right: 0.25em; - margin-bottom: -0.25em; - .cls-1 { - isolation: isolate; - } - .cls-2 { - opacity: 0.5; - mix-blend-mode: multiply; - } - .cls-3 { - fill: var(--link-color); - } - .cls-4 { - fill: var(--link-color); - } - } - } + .byline { + font-family: var(--heading-font); + font-size: 0.3em; + margin-bottom: 0.75em; + margin-left: -2.7em; + opacity: 0.55; + word-spacing: 5px; + } + } - .brand-heading--inverse { + .brand-subtitle { + color: var(--text-color); + } + + .brand-name__text { + font-size: 120%; + vertical-align: text-bottom; + } + + .converse-svg-logo { + color: var(--link-color); + height: 1.5em; + margin-right: 0.25em; + margin-bottom: -0.25em; + .cls-1 { + isolation: isolate; + } + .cls-2 { + opacity: 0.5; + mix-blend-mode: multiply; + } + .cls-3 { + fill: var(--link-color); + } + .cls-4 { + fill: var(--link-color); + } + } + } + + .brand-heading--inverse { .converse-svg-logo { margin-bottom: 0em; margin-top: -0.2em; diff --git a/spec/chatbox.js b/spec/chatbox.js index 33fa3d262..6c07b40b6 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -260,27 +260,14 @@ describe("Chatboxes", function () { async function (done, _converse) { await mock.waitForRoster(_converse, 'current'); - await mock.openControlBox(_converse); - const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit'; await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length); await mock.openChatBoxFor(_converse, contact_jid); - const controlview = _converse.chatboxviews.get('controlbox'), // The controlbox is currently open - chatview = _converse.chatboxviews.get(contact_jid); - + const chatview = _converse.chatboxviews.get(contact_jid); spyOn(chatview, 'close').and.callThrough(); - spyOn(controlview, 'close').and.callThrough(); spyOn(_converse.api, "trigger").and.callThrough(); - // We need to rebind all events otherwise our spy won't be called - controlview.delegateEvents(); chatview.delegateEvents(); - - controlview.el.querySelector('.close-chatbox-button').click(); - expect(controlview.close).toHaveBeenCalled(); - await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve)); - expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); - chatview.el.querySelector('.close-chatbox-button').click(); expect(chatview.close).toHaveBeenCalled(); await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve)); diff --git a/spec/controlbox.js b/spec/controlbox.js index bba3bacbc..b9f80b15c 100644 --- a/spec/controlbox.js +++ b/spec/controlbox.js @@ -33,6 +33,27 @@ describe("The Controlbox", function () { done(); })); + + it("can be closed by clicking a DOM element with class 'close-chatbox-button'", + mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) { + + await mock.openControlBox(_converse); + const controlview = _converse.chatboxviews.get('controlbox'); + + spyOn(controlview, 'close').and.callThrough(); + spyOn(_converse.api, "trigger").and.callThrough(); + + // We need to rebind all events otherwise our spy won't be called + controlview.delegateEvents(); + + controlview.el.querySelector('.close-chatbox-button').click(); + expect(controlview.close).toHaveBeenCalled(); + await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve)); + expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object)); + done(); + })); + + describe("The \"Contacts\" section", function () { it("can be used to add contact and it checks for case-sensivity", diff --git a/src/components/brand-heading.js b/src/components/brand-heading.js new file mode 100644 index 000000000..4d0505f18 --- /dev/null +++ b/src/components/brand-heading.js @@ -0,0 +1,42 @@ +import { api } from "@converse/headless/converse-core"; +import { component } from 'haunted'; +import { html } from 'lit-html'; + +export const ConverseBrandHeading = (o) => { + const is_fullscreen = api.settings.get('view_mode') === 'fullscreen'; + return html` + + + + + converse.js + ${ is_fullscreen ? html`` : '' } + + + + ${ is_fullscreen ? html` +

${o.version_name}

+

Open Source XMPP chat client brought to you by Opkode

+

Translate it into your own language

` : '' } + `; +} + +api.elements.define('converse-brand-heading', component(ConverseBrandHeading, {'useShadowDOM': false})); diff --git a/src/converse-controlbox.js b/src/converse-controlbox.js index 51d39cf91..a1c2d9b58 100644 --- a/src/converse-controlbox.js +++ b/src/converse-controlbox.js @@ -4,16 +4,17 @@ * @license Mozilla Public License (MPLv2) */ import "converse-chatview"; +import "./components/brand-heading"; import bootstrap from "bootstrap.native"; import log from "@converse/headless/log"; -import tpl_brand_heading from "templates/converse_brand_heading.html"; -import tpl_controlbox from "templates/controlbox.html"; +import tpl_controlbox from "templates/controlbox.js"; import tpl_controlbox_toggle from "templates/controlbox_toggle.html"; import tpl_login_panel from "templates/login_panel.js"; import { Model } from '@converse/skeletor/src/model.js'; import { View } from "@converse/skeletor/src/view"; import { __ } from './i18n'; import { _converse, api, converse } from "@converse/headless/converse-core"; +import { render } from 'lit-html'; const { Strophe, dayjs } = converse.env; const u = converse.env.utils; @@ -198,7 +199,12 @@ converse.plugins.add('converse-controlbox', { this.model.set('closed', !api.settings.get('show_controlbox_by_default')); } } - this.el.innerHTML = tpl_controlbox(Object.assign(this.model.toJSON())); + + const tpl_result = tpl_controlbox({ + 'sticky_controlbox': api.settings.get('sticky_controlbox'), + ...this.model.toJSON() + }); + render(tpl_result, this.el); if (!this.model.get('closed')) { this.show(); @@ -221,22 +227,6 @@ converse.plugins.add('converse-controlbox', { } }, - createBrandHeadingHTML () { - return tpl_brand_heading({ - 'sticky_controlbox': api.settings.get('sticky_controlbox') - }); - }, - - insertBrandHeading () { - const heading_el = this.el.querySelector('.brand-heading-container'); - if (heading_el === null) { - const el = this.el.querySelector('.controlbox-head'); - el.insertAdjacentHTML('beforeend', this.createBrandHeadingHTML()); - } else { - heading_el.outerHTML = this.createBrandHeadingHTML(); - } - }, - renderLoginPanel () { this.el.classList.add("logged-out"); if (this.loginpanel) { @@ -248,7 +238,6 @@ converse.plugins.add('converse-controlbox', { const panes = this.el.querySelector('.controlbox-panes'); panes.innerHTML = ''; panes.appendChild(this.loginpanel.render().el); - this.insertBrandHeading(); } this.loginpanel.initPopovers(); return this; diff --git a/src/converse-fullscreen.js b/src/converse-fullscreen.js index 0cc5ca86b..0e6c64045 100644 --- a/src/converse-fullscreen.js +++ b/src/converse-fullscreen.js @@ -7,8 +7,7 @@ import "@converse/headless/converse-muc"; import "converse-chatview"; import "converse-controlbox"; import "converse-singleton"; -import { _converse, api, converse } from "@converse/headless/converse-core"; -import tpl_brand_heading from "templates/inverse_brand_heading.html"; +import { api, converse } from "@converse/headless/converse-core"; converse.plugins.add('converse-fullscreen', { @@ -17,30 +16,6 @@ converse.plugins.add('converse-fullscreen', { return _converse.isUniView(); }, - overrides: { - // overrides mentioned here will be picked up by converse.js's - // plugin architecture they will replace existing methods on the - // relevant objects or classes. - // - // new functions which don't exist yet can also be added. - - ControlBoxView: { - createBrandHeadingHTML() { - return tpl_brand_heading({ - 'version_name': _converse.VERSION_NAME - }); - }, - - insertBrandHeading () { - const el = _converse.root.getElementById('converse-login-panel'); - el.parentNode.insertAdjacentHTML( - 'afterbegin', - this.createBrandHeadingHTML() - ); - } - } - }, - initialize () { api.settings.extend({ chatview_avatar_height: 50, diff --git a/src/templates/controlbox.html b/src/templates/controlbox.html deleted file mode 100644 index fe0dceb37..000000000 --- a/src/templates/controlbox.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
- {[ if (!o.sticky_controlbox) { ]} - - {[ } ]} -
-
-
diff --git a/src/templates/controlbox.js b/src/templates/controlbox.js new file mode 100644 index 000000000..e4e79ab33 --- /dev/null +++ b/src/templates/controlbox.js @@ -0,0 +1,9 @@ +import { html } from 'lit-html'; + +export default (o) => html` +
+
+ ${o.sticky_controlbox ? '' : html`` } +
+
+
`; diff --git a/src/templates/converse_brand_heading.html b/src/templates/converse_brand_heading.html deleted file mode 100644 index 65cbef222..000000000 --- a/src/templates/converse_brand_heading.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - converse.js - - - diff --git a/src/templates/inverse_brand_heading.html b/src/templates/inverse_brand_heading.html deleted file mode 100644 index 5c96b2c9c..000000000 --- a/src/templates/inverse_brand_heading.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
-

- - - converse.js - - -

-

{{{o.version_name}}}

-

Open Source XMPP chat client brought to you by Opkode

-

Translate it into your own language

-
-
diff --git a/src/templates/login_panel.js b/src/templates/login_panel.js index 66f2c2db4..a4ea6848c 100644 --- a/src/templates/login_panel.js +++ b/src/templates/login_panel.js @@ -87,6 +87,7 @@ const form_fields = (o) => { export default (o) => html` +
diff --git a/src/templates/user_settings_modal.js b/src/templates/user_settings_modal.js index f10ff36b0..4f0f19e05 100644 --- a/src/templates/user_settings_modal.js +++ b/src/templates/user_settings_modal.js @@ -56,7 +56,7 @@ export default (o) => {
-
+
Converse

${o.version_name}

${unsafeHTML(xss.filterXSS(first_subtitle, {'whiteList': {'a': []}}))}