diff --git a/css/converse.css b/css/converse.css index f49f8b70e..2415ee682 100644 --- a/css/converse.css +++ b/css/converse.css @@ -4371,6 +4371,321 @@ background-color: #e9ecef; border-left: 1px solid #ced4da; border-radius: 0 0.25rem 0.25rem 0; } +#conversejs .nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; } +#conversejs .nav-link { + display: block; + padding: 0.5rem 1rem; } + #conversejs .nav-link:hover, #conversejs .nav-link:focus { + text-decoration: none; } + #conversejs .nav-link.disabled { + color: #6c757d; } +#conversejs .nav-tabs { + border-bottom: 1px solid #dee2e6; } + #conversejs .nav-tabs .nav-item { + margin-bottom: -1px; } + #conversejs .nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; } + #conversejs .nav-tabs .nav-link:hover, #conversejs .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; } + #conversejs .nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; } + #conversejs .nav-tabs .nav-link.active, + #conversejs .nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #fff; + border-color: #dee2e6 #dee2e6 #fff; } + #conversejs .nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; } +#conversejs .nav-pills .nav-link { + border-radius: 0.25rem; } +#conversejs .nav-pills .nav-link.active, +#conversejs .nav-pills .show > .nav-link { + color: #fff; + background-color: #387592; } +#conversejs .nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; } +#conversejs .nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; } +#conversejs .tab-content > .tab-pane { + display: none; } +#conversejs .tab-content > .active { + display: block; } +#conversejs .navbar { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding: 0.5rem 1rem; } + #conversejs .navbar > .container, + #conversejs .navbar > .container-fluid { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; } +#conversejs .navbar-brand { + display: inline-block; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; } + #conversejs .navbar-brand:hover, #conversejs .navbar-brand:focus { + text-decoration: none; } +#conversejs .navbar-nav { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; } + #conversejs .navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; } + #conversejs .navbar-nav .dropdown-menu { + position: static; + float: none; } +#conversejs .navbar-text { + display: inline-block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; } +#conversejs .navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; } +#conversejs .navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 1.25rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.25rem; } + #conversejs .navbar-toggler:hover, #conversejs .navbar-toggler:focus { + text-decoration: none; } + #conversejs .navbar-toggler:not(:disabled):not(.disabled) { + cursor: pointer; } +#conversejs .navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + content: ""; + background: no-repeat center center; + background-size: 100% 100%; } +@media (max-width: 575.98px) { + #conversejs .navbar-expand-sm > .container, + #conversejs .navbar-expand-sm > .container-fluid { + padding-right: 0; + padding-left: 0; } } +@media (min-width: 576px) { + #conversejs .navbar-expand-sm { + flex-flow: row nowrap; + justify-content: flex-start; } + #conversejs .navbar-expand-sm .navbar-nav { + flex-direction: row; } + #conversejs .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; } + #conversejs .navbar-expand-sm .navbar-nav .dropdown-menu-right { + right: 0; + left: auto; } + #conversejs .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; } + #conversejs .navbar-expand-sm > .container, + #conversejs .navbar-expand-sm > .container-fluid { + flex-wrap: nowrap; } + #conversejs .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; } + #conversejs .navbar-expand-sm .navbar-toggler { + display: none; } + #conversejs .navbar-expand-sm .dropup .dropdown-menu { + top: auto; + bottom: 100%; } } +@media (max-width: 767.98px) { + #conversejs .navbar-expand-md > .container, + #conversejs .navbar-expand-md > .container-fluid { + padding-right: 0; + padding-left: 0; } } +@media (min-width: 768px) { + #conversejs .navbar-expand-md { + flex-flow: row nowrap; + justify-content: flex-start; } + #conversejs .navbar-expand-md .navbar-nav { + flex-direction: row; } + #conversejs .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; } + #conversejs .navbar-expand-md .navbar-nav .dropdown-menu-right { + right: 0; + left: auto; } + #conversejs .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; } + #conversejs .navbar-expand-md > .container, + #conversejs .navbar-expand-md > .container-fluid { + flex-wrap: nowrap; } + #conversejs .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; } + #conversejs .navbar-expand-md .navbar-toggler { + display: none; } + #conversejs .navbar-expand-md .dropup .dropdown-menu { + top: auto; + bottom: 100%; } } +@media (max-width: 991.98px) { + #conversejs .navbar-expand-lg > .container, + #conversejs .navbar-expand-lg > .container-fluid { + padding-right: 0; + padding-left: 0; } } +@media (min-width: 992px) { + #conversejs .navbar-expand-lg { + flex-flow: row nowrap; + justify-content: flex-start; } + #conversejs .navbar-expand-lg .navbar-nav { + flex-direction: row; } + #conversejs .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; } + #conversejs .navbar-expand-lg .navbar-nav .dropdown-menu-right { + right: 0; + left: auto; } + #conversejs .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; } + #conversejs .navbar-expand-lg > .container, + #conversejs .navbar-expand-lg > .container-fluid { + flex-wrap: nowrap; } + #conversejs .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; } + #conversejs .navbar-expand-lg .navbar-toggler { + display: none; } + #conversejs .navbar-expand-lg .dropup .dropdown-menu { + top: auto; + bottom: 100%; } } +@media (max-width: 1199.98px) { + #conversejs .navbar-expand-xl > .container, + #conversejs .navbar-expand-xl > .container-fluid { + padding-right: 0; + padding-left: 0; } } +@media (min-width: 1200px) { + #conversejs .navbar-expand-xl { + flex-flow: row nowrap; + justify-content: flex-start; } + #conversejs .navbar-expand-xl .navbar-nav { + flex-direction: row; } + #conversejs .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; } + #conversejs .navbar-expand-xl .navbar-nav .dropdown-menu-right { + right: 0; + left: auto; } + #conversejs .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; } + #conversejs .navbar-expand-xl > .container, + #conversejs .navbar-expand-xl > .container-fluid { + flex-wrap: nowrap; } + #conversejs .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; } + #conversejs .navbar-expand-xl .navbar-toggler { + display: none; } + #conversejs .navbar-expand-xl .dropup .dropdown-menu { + top: auto; + bottom: 100%; } } +#conversejs .navbar-expand { + flex-flow: row nowrap; + justify-content: flex-start; } + #conversejs .navbar-expand > .container, + #conversejs .navbar-expand > .container-fluid { + padding-right: 0; + padding-left: 0; } + #conversejs .navbar-expand .navbar-nav { + flex-direction: row; } + #conversejs .navbar-expand .navbar-nav .dropdown-menu { + position: absolute; } + #conversejs .navbar-expand .navbar-nav .dropdown-menu-right { + right: 0; + left: auto; } + #conversejs .navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; } + #conversejs .navbar-expand > .container, + #conversejs .navbar-expand > .container-fluid { + flex-wrap: nowrap; } + #conversejs .navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; } + #conversejs .navbar-expand .navbar-toggler { + display: none; } + #conversejs .navbar-expand .dropup .dropdown-menu { + top: auto; + bottom: 100%; } +#conversejs .navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); } + #conversejs .navbar-light .navbar-brand:hover, #conversejs .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); } +#conversejs .navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.5); } + #conversejs .navbar-light .navbar-nav .nav-link:hover, #conversejs .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); } + #conversejs .navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); } +#conversejs .navbar-light .navbar-nav .show > .nav-link, +#conversejs .navbar-light .navbar-nav .active > .nav-link, +#conversejs .navbar-light .navbar-nav .nav-link.show, +#conversejs .navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); } +#conversejs .navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.1); } +#conversejs .navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); } +#conversejs .navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.5); } + #conversejs .navbar-light .navbar-text a { + color: rgba(0, 0, 0, 0.9); } + #conversejs .navbar-light .navbar-text a:hover, #conversejs .navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); } +#conversejs .navbar-dark .navbar-brand { + color: #fff; } + #conversejs .navbar-dark .navbar-brand:hover, #conversejs .navbar-dark .navbar-brand:focus { + color: #fff; } +#conversejs .navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.5); } + #conversejs .navbar-dark .navbar-nav .nav-link:hover, #conversejs .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); } + #conversejs .navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); } +#conversejs .navbar-dark .navbar-nav .show > .nav-link, +#conversejs .navbar-dark .navbar-nav .active > .nav-link, +#conversejs .navbar-dark .navbar-nav .nav-link.show, +#conversejs .navbar-dark .navbar-nav .nav-link.active { + color: #fff; } +#conversejs .navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.5); + border-color: rgba(255, 255, 255, 0.1); } +#conversejs .navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"); } +#conversejs .navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.5); } + #conversejs .navbar-dark .navbar-text a { + color: #fff; } + #conversejs .navbar-dark .navbar-text a:hover, #conversejs .navbar-dark .navbar-text a:focus { + color: #fff; } #conversejs .card { position: relative; display: flex; @@ -6868,6 +7183,8 @@ body.reset { font-size: 14px; direction: ltr; z-index: 1031; } + #conversejs .nopadding { + padding: 0 !important; } #conversejs.converse-overlayed > .row { flex-direction: row-reverse; } #conversejs.converse-fullscreen .converse-chatboxes, #conversejs.converse-mobile .converse-chatboxes { @@ -7216,8 +7533,6 @@ body.reset { #conversejs .btn--small { font-size: 80%; font-weight: normal; } -#conversejs form .form-group { - margin-bottom: 2em; } #conversejs form .form-check-label { margin-top: 0.3rem; } #conversejs form .form-control::-webkit-input-placeholder { @@ -7289,16 +7604,11 @@ body.reset { color: #79a5ba; } #conversejs form.converse-form .text-muted.error { color: #A53214; } +#conversejs form.converse-form--modal { + padding-bottom: 0; } #conversejs form.converse-centered-form { text-align: center; } -#conversejs #user-profile-modal label { - font-weight: bold; } -#conversejs .fingerprint-trust { - display: flex; - justify-content: space-between; - font-size: 95%; } - #conversejs .chatbox-navback { display: none; } #conversejs .flyout { @@ -7857,10 +8167,6 @@ body.reset { padding: 0.3em 0; clear: left; width: 100%; } -#conversejs #converse-modals .set-xmpp-status { - margin: 1em; } - #conversejs #converse-modals .set-xmpp-status .custom-control-label { - margin-top: 0.25em; } #conversejs #controlbox { margin-right: 1.5em; } #conversejs #controlbox .box-flyout { @@ -8261,6 +8567,30 @@ body.reset { #conversejs.converse-overlayed .converse-chatboxes .chatbox .box-flyout { margin-left: 30px; } } +#conversejs #converse-modals .set-xmpp-status { + margin: 1em; } + #conversejs #converse-modals .set-xmpp-status .custom-control-label { + margin-top: 0.25em; } +#conversejs #converse-modals #omemo-tabpanel { + margin-top: 1em; } +#conversejs #converse-modals .btn { + font-weight: normal; } +#conversejs #converse-modals #user-profile-modal label { + font-weight: bold; } +#conversejs #converse-modals #user-profile-modal .list-group-item { + display: flex; + justify-content: left; + font-size: 95%; } + #conversejs #converse-modals #user-profile-modal .list-group-item input[type="checkbox"] { + margin-right: 1em; } +#conversejs #converse-modals .fingerprints { + width: 100%; + margin-bottom: 1em; } +#conversejs #converse-modals .fingerprint-trust { + display: flex; + justify-content: space-between; + font-size: 95%; } + #conversejs #converse-roster { text-align: left; width: 100%; diff --git a/dist/converse.js b/dist/converse.js index 1b64ad1a4..837766a7d 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -36,19 +36,34 @@ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? @@ -2560,13 +2575,7 @@ backbone.nativeview = __webpack_require__(/*! backbone.nativeview */ "./node_mod if (_.isFunction(this.beforeRender)) { this.beforeRender(); } - let new_vnode; - if (!_.isNil(this.toHTML)) { - new_vnode = tovnode.toVNode(parseHTMLToDOM(this.toHTML())); - } else { - new_vnode = tovnode.toVNode(this.toDOM()); - } - + const new_vnode = tovnode.toVNode(parseHTMLToDOM(this.toHTML())); new_vnode.data.hook = _.extend({ create: this.updateEventListeners.bind(this), update: this.updateEventListeners.bind(this) @@ -27145,13 +27154,12 @@ var map = { function webpackContext(req) { var id = webpackContextResolve(req); - var module = __webpack_require__(id); - return module; + return __webpack_require__(id); } function webpackContextResolve(req) { var id = map[req]; if(!(id + 1)) { // check for number or string - var e = new Error('Cannot find module "' + req + '".'); + var e = new Error("Cannot find module '" + req + "'"); e.code = 'MODULE_NOT_FOUND'; throw e; } @@ -59647,26 +59655,26 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /*! no static exports found */ /***/ (function(module, exports) { -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1, eval)("this"); -} catch (e) { - // This works if the window reference is available - if (typeof window === "object") g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || Function("return this")() || (1, eval)("this"); +} catch (e) { + // This works if the window reference is available + if (typeof window === "object") g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; /***/ }), @@ -59678,28 +59686,28 @@ module.exports = g; /*! no static exports found */ /***/ (function(module, exports) { -module.exports = function(module) { - if (!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if (!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; +module.exports = function(module) { + if (!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + if (!module.children) module.children = []; + Object.defineProperty(module, "loaded", { + enumerable: true, + get: function() { + return module.l; + } + }); + Object.defineProperty(module, "id", { + enumerable: true, + get: function() { + return module.i; + } + }); + module.webpackPolyfill = 1; + } + return module; +}; /***/ }), @@ -74045,6 +74053,43 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ dependencies: ["converse-chatview"], overrides: { + ProfileModal: { + events: { + 'change input.select-all': 'selectAll', + 'submit .fingerprint-removal': 'removeSelectedFingerprints' + }, + + initialize() { + const _converse = this.__super__._converse, + device_id = _converse.omemo_store.get('device_id'); + + this.devicelist = _converse.devicelists.get(_converse.bare_jid); + this.current_device = this.devicelist.devices.get(device_id); + this.other_devices = this.devicelist.devices.filter(d => d.get('id') !== device_id); + this.devicelist.devices.on('change:bundle', this.render, this); + return this.__super__.initialize.apply(this, arguments); + }, + + selectAll(ev) { + let sibling = ev.target.parentElement.nextElementSibling; + + while (sibling) { + sibling.firstElementChild.checked = ev.target.checked; + sibling = sibling.nextElementSibling; + } + }, + + removeSelectedFingerprints(ev) { + ev.preventDefault(); + ev.stopPropagation(); + + const checkboxes = ev.target.querySelectorAll('.fingerprint-removal-item input[type="checkbox"]:checked'), + device_ids = _.map(checkboxes, 'value'); + + this.devicelist.removeOwnDevices(device_ids); + } + + }, UserDetailsModal: { events: { 'click .fingerprint-trust .btn input': 'toggleDeviceTrust' @@ -74376,7 +74421,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ function generateFingerprint(device) { return new Promise((resolve, reject) => { device.getBundle().then(bundle => { - // TODO: only generate fingerprints when necessary + if (_.isNil(bundle)) { + resolve(); + } // TODO: only generate fingerprints when necessary + + crypto.subtle.digest('SHA-1', u.base64ToArrayBuffer(bundle['identity_key'])).then(fp => { bundle['fingerprint'] = u.arrayBufferToHex(fp); device.save('bundle', bundle); @@ -74388,10 +74437,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ }); } - _converse.getFingerprintsForContact = function (jid) { - return new Promise((resolve, reject) => { - _converse.getDevicesForContact(jid).then(devices => Promise.all(devices.map(d => generateFingerprint(d))).then(resolve).catch(reject)); - }); + _converse.generateFingerprints = function (jid) { + return _converse.getDevicesForContact(jid).then(devices => Promise.all(devices.map(d => generateFingerprint(d)))); }; _converse.getDevicesForContact = function (jid) { @@ -74628,24 +74675,23 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ }, fetchBundleFromServer() { - return new Promise((resolve, reject) => { - const stanza = $iq({ - 'type': 'get', - 'from': _converse.bare_jid, - 'to': this.get('jid') - }).c('pubsub', { - 'xmlns': Strophe.NS.PUBSUB - }).c('items', { - 'node': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}` - }); - - _converse.connection.sendIQ(stanza, iq => { - const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(), - bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(), - bundle = parseBundle(bundle_el); - this.save('bundle', bundle); - resolve(bundle); - }, reject, _converse.IQ_TIMEOUT); + const stanza = $iq({ + 'type': 'get', + 'from': _converse.bare_jid, + 'to': this.get('jid') + }).c('pubsub', { + 'xmlns': Strophe.NS.PUBSUB + }).c('items', { + 'node': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}` + }); + return _converse.api.sendIQ(stanza).then(iq => { + const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(), + bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(), + bundle = parseBundle(bundle_el); + this.save('bundle', bundle); + return bundle; + }).catch(iq => { + _converse.log(iq.outerHTML, Strophe.LogLevel.ERROR); }); }, @@ -74654,7 +74700,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ * this device, if the information is not at hand already. */ if (this.get('bundle')) { - return Promise.resolve(this.get('bundle').toJSON(), this); + return Promise.resolve(this.get('bundle'), this); } else { return this.fetchBundleFromServer(); } @@ -74745,6 +74791,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ _converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + }, + + removeOwnDevices(device_ids) {// TODO } }); @@ -74926,7 +74975,11 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ _converse.api.listen.on('userDetailsModalInitialized', contact => { const jid = contact.get('jid'); - _converse.getFingerprintsForContact(jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + _converse.generateFingerprints(jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + }); + + _converse.api.listen.on('profileModalInitialized', contact => { + _converse.generateFingerprints(_converse.bare_jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); }); } @@ -75117,31 +75170,40 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ events: { 'click .change-avatar': "openFileSelection", 'change input[type="file"': "updateFilePreview", - 'submit form': 'onFormSubmitted' + 'submit .profile-form': 'onFormSubmitted' }, initialize() { _converse.BootstrapModal.prototype.initialize.apply(this, arguments); this.model.on('change', this.render, this); + + _converse.emit('profileModalInitialized', this.model); }, toHTML() { return tpl_profile_modal(_.extend(this.model.toJSON(), this.model.vcard.toJSON(), { + '_': _, + '__': __, + '_converse': _converse, + 'alt_avatar': __('Your avatar image'), 'heading_profile': __('Your Profile'), 'label_close': __('Close'), 'label_email': __('Email'), 'label_fullname': __('Full Name'), - 'label_nickname': __('Nickname'), 'label_jid': __('XMPP Address (JID)'), + 'label_nickname': __('Nickname'), 'label_role': __('Role'), 'label_role_help': __('Use commas to separate multiple roles. Your roles are shown next to your name on your chat messages.'), - 'label_save': __('Save'), 'label_url': __('URL'), - 'alt_avatar': __('Your avatar image') + 'view': this })); }, + afterRender() { + this.tabs = _.map(this.el.querySelectorAll('.nav-item'), tab => new bootstrap.Tab(tab)); + }, + openFileSelection(ev) { ev.preventDefault(); this.el.querySelector('input[type="file"]').click(); @@ -81345,51 +81407,93 @@ __p += '\n\n
\n
\n'; +'\n \n
\n
\n \n
\n \n \n '; + if (o._converse.pluggable.plugins['converse-omemo'].enabled()) { ; +__p += '\n
\n
\n \n '; + if (o.view.other_devices) { ; +__p += '\n \n '; + } ; +__p += '\n
\n \n
\n
\n
\n '; + } ; +__p += '\n \n \n \n \n\n'; return __p }; @@ -82407,9 +82511,7 @@ __p += '\n '; o.view.devicelist.devices.each(function (device) { ; __p += '\n '; if (device.get('bundle') && device.get('bundle').fingerprint) { ; -__p += '\n
  • \n
    \n ' + -__e(device.get('bundle').fingerprint) + -'\n
    \n
  • \n '; +'\n \n \n ' + +__e(device.get('bundle').fingerprint) + +'\n \n \n '; } ; __p += '\n '; }); ; diff --git a/sass/_controlbox.scss b/sass/_controlbox.scss index 2b757545e..9951ad52a 100644 --- a/sass/_controlbox.scss +++ b/sass/_controlbox.scss @@ -60,15 +60,6 @@ width: 100%; } - #converse-modals { - .set-xmpp-status { - margin: 1em; - .custom-control-label { - margin-top: 0.25em; - } - } - } - #controlbox { .box-flyout { background-color: white; diff --git a/sass/_core.scss b/sass/_core.scss index a1c2969bc..e5727de03 100644 --- a/sass/_core.scss +++ b/sass/_core.scss @@ -61,6 +61,10 @@ body.reset { direction: ltr; z-index: 1031; // One more than bootstrap navbar + .nopadding { + padding: 0 !important; + } + &.converse-overlayed { > .row { flex-direction: row-reverse; diff --git a/sass/_forms.scss b/sass/_forms.scss index 675a2a71e..f5dd28a90 100644 --- a/sass/_forms.scss +++ b/sass/_forms.scss @@ -5,10 +5,6 @@ } form { - .form-group { - margin-bottom: 2em; - } - .form-check-label { margin-top: $form-check-input-margin-y; } @@ -108,6 +104,11 @@ } } } + + &.converse-form--modal { + padding-bottom: 0; + } + &.converse-centered-form { text-align: center; } diff --git a/sass/_modal.scss b/sass/_modal.scss new file mode 100644 index 000000000..119eac1e9 --- /dev/null +++ b/sass/_modal.scss @@ -0,0 +1,44 @@ +#conversejs { + #converse-modals { + .set-xmpp-status { + margin: 1em; + .custom-control-label { + margin-top: 0.25em; + } + } + + #omemo-tabpanel { + margin-top: 1em; + } + + .btn { + font-weight: normal; + } + + #user-profile-modal { + label { + font-weight: bold; + } + .list-group-item { + display: flex; + justify-content: left; + font-size: 95%; + + input[type="checkbox"] { + margin-right: 1em; + } + } + } + + .fingerprints { + width: 100%; + margin-bottom: 1em; + } + + .fingerprint-trust { + display: flex; + justify-content: space-between; + font-size: 95%; + } + } +} diff --git a/sass/_profile.scss b/sass/_profile.scss deleted file mode 100644 index 6aea5519e..000000000 --- a/sass/_profile.scss +++ /dev/null @@ -1,12 +0,0 @@ -#conversejs { - #user-profile-modal { - label { - font-weight: bold; - } - } - .fingerprint-trust { - display: flex; - justify-content: space-between; - font-size: 95%; - } -} diff --git a/sass/converse.scss b/sass/converse.scss index bae5115ea..7a2a8e699 100644 --- a/sass/converse.scss +++ b/sass/converse.scss @@ -26,6 +26,8 @@ @import "bootstrap/scss/button-group"; @import "bootstrap/scss/input-group"; @import "bootstrap/scss/custom-forms"; + @import "bootstrap/scss/nav"; + @import "bootstrap/scss/navbar"; @import "bootstrap/scss/card"; @import "bootstrap/scss/breadcrumb"; @import "bootstrap/scss/badge"; @@ -40,9 +42,9 @@ } @import "core"; @import "forms"; -@import "profile"; @import "chatbox"; @import "controlbox"; +@import "modal"; @import "roster"; @import "lists"; @import "chatrooms"; diff --git a/src/converse-omemo.js b/src/converse-omemo.js index 035b61d80..997b863c2 100644 --- a/src/converse-omemo.js +++ b/src/converse-omemo.js @@ -70,6 +70,41 @@ overrides: { + ProfileModal: { + events: { + 'change input.select-all': 'selectAll', + 'submit .fingerprint-removal': 'removeSelectedFingerprints' + }, + + initialize () { + const { _converse } = this.__super__, + device_id = _converse.omemo_store.get('device_id'); + + this.devicelist = _converse.devicelists.get(_converse.bare_jid); + this.current_device = this.devicelist.devices.get(device_id); + this.other_devices = this.devicelist.devices.filter(d => (d.get('id') !== device_id)); + + this.devicelist.devices.on('change:bundle', this.render, this); + return this.__super__.initialize.apply(this, arguments); + }, + + selectAll (ev) { + let sibling = ev.target.parentElement.nextElementSibling; + while (sibling) { + sibling.firstElementChild.checked = ev.target.checked; + sibling = sibling.nextElementSibling; + } + }, + + removeSelectedFingerprints (ev) { + ev.preventDefault(); + ev.stopPropagation(); + const checkboxes = ev.target.querySelectorAll('.fingerprint-removal-item input[type="checkbox"]:checked'), + device_ids = _.map(checkboxes, 'value'); + this.devicelist.removeOwnDevices(device_ids); + }, + }, + UserDetailsModal: { events: { 'click .fingerprint-trust .btn input': 'toggleDeviceTrust' @@ -415,7 +450,7 @@ }); } - _converse.getFingerprintsForContact = function (jid) { + _converse.generateFingerprints= function (jid) { return _converse.getDevicesForContact(jid) .then(devices => Promise.all(devices.map(d => generateFingerprint(d)))) } @@ -734,6 +769,10 @@ }); _converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + }, + + removeOwnDevices (device_ids) { + // TODO } }); @@ -893,7 +932,11 @@ _converse.api.listen.on('userDetailsModalInitialized', (contact) => { const jid = contact.get('jid'); - _converse.getFingerprintsForContact(jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + _converse.generateFingerprints(jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); + }); + + _converse.api.listen.on('profileModalInitialized', (contact) => { + _converse.generateFingerprints(_converse.bare_jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR)); }); } }); diff --git a/src/converse-profile.js b/src/converse-profile.js index 387178c39..ffb5a512e 100644 --- a/src/converse-profile.js +++ b/src/converse-profile.js @@ -48,32 +48,40 @@ events: { 'click .change-avatar': "openFileSelection", 'change input[type="file"': "updateFilePreview", - 'submit form': 'onFormSubmitted' + 'submit .profile-form': 'onFormSubmitted' }, initialize () { _converse.BootstrapModal.prototype.initialize.apply(this, arguments); this.model.on('change', this.render, this); + _converse.emit('profileModalInitialized', this.model); }, toHTML () { return tpl_profile_modal(_.extend( this.model.toJSON(), this.model.vcard.toJSON(), { + '_': _, + '__': __, + '_converse': _converse, + 'alt_avatar': __('Your avatar image'), 'heading_profile': __('Your Profile'), 'label_close': __('Close'), 'label_email': __('Email'), 'label_fullname': __('Full Name'), - 'label_nickname': __('Nickname'), 'label_jid': __('XMPP Address (JID)'), + 'label_nickname': __('Nickname'), 'label_role': __('Role'), 'label_role_help': __('Use commas to separate multiple roles. Your roles are shown next to your name on your chat messages.'), - 'label_save': __('Save'), 'label_url': __('URL'), - 'alt_avatar': __('Your avatar image') + 'view': this })); }, + afterRender () { + this.tabs = _.map(this.el.querySelectorAll('.nav-item'), (tab) => new bootstrap.Tab(tab)); + }, + openFileSelection (ev) { ev.preventDefault(); this.el.querySelector('input[type="file"]').click(); diff --git a/src/templates/profile_modal.html b/src/templates/profile_modal.html index e565385ba..ad5794606 100644 --- a/src/templates/profile_modal.html +++ b/src/templates/profile_modal.html @@ -5,54 +5,105 @@ -
    -
    diff --git a/src/templates/user_details_modal.html b/src/templates/user_details_modal.html index 99817aed2..3304b5b8a 100644 --- a/src/templates/user_details_modal.html +++ b/src/templates/user_details_modal.html @@ -40,7 +40,6 @@ {[ if (device.get('bundle') && device.get('bundle').fingerprint) { ]}
  • - {{{device.get('bundle').fingerprint}}}
    + {{{device.get('bundle').fingerprint}}}
  • {[ } ]}