Work on turning chat views into custom elements
The eventual goal is to avoid UI-related stanza processing if the relevant chats aren't in the DOM. With the current architecture, chatboxes are created (and the stanzas related to them processed) even if `#conversejs` isn't in the DOM. * Initial work on making controlbox an element * Create a shared base class * Ceate ChatBoxViews proxy * Update sass now that certain classes are moved to converse-chats element
This commit is contained in:
parent
eb65f75f45
commit
1949356ede
|
@ -24,6 +24,9 @@ The [afterMessageBodyTransformed](https://conversejs.org/docs/html/api/-_convers
|
|||
When leaving a MUC, the message history is deleted. This means that decrypted
|
||||
OMEMO messages are gone and cannot be recovered on that device. See [muc_clear_messages_on_leave](https://conversejs.org/docs/html/configuration.html#muc-clear-messages-on-leave).
|
||||
|
||||
Removed events:
|
||||
* `chatBoxInsertedIntoDOM`
|
||||
|
||||
## 7.0.2 (2020-11-23)
|
||||
|
||||
- Updated translations: de, nb, gl, tr
|
||||
|
|
|
@ -4483,9 +4483,9 @@
|
|||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.0.0.tgz",
|
||||
"integrity": "sha512-J4bfM7lf8oZvEAdpS71oTvC1ofKxfEZgU5vKVwzZKi4QPiL82udjpseJwxPid9Pu2FNmyRQOX4iEj6W1iOSnPw==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-2.0.1.tgz",
|
||||
"integrity": "sha512-9AuC04PUnZrjoLiw3uPtwGh9FE4Q3rTqs51oNlQ0rkwgE8ftYsOC+lsrQyvCvWm85smBbSc0FNRKKumvGyb44Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@octokit/plugin-enterprise-rest": {
|
||||
|
@ -4629,12 +4629,12 @@
|
|||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.1.1.tgz",
|
||||
"integrity": "sha512-btm3D6S7VkRrgyYF31etUtVY/eQ1KzrNRqhFt25KSe2mKlXuLXJilglRC6eDA2P6ou94BUnk/Kz5MPEolXgoiw==",
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.1.2.tgz",
|
||||
"integrity": "sha512-LPCpcLbcky7fWfHCTuc7tMiSHFpFlrThJqVdaHgowBTMS0ijlZFfonQC/C1PrZOjD4xRCYgBqH9yttEATGE/nw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^2.0.0",
|
||||
"@octokit/openapi-types": "^2.0.1",
|
||||
"@types/node": ">= 8"
|
||||
}
|
||||
},
|
||||
|
@ -7099,9 +7099,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"conventional-changelog-writer": {
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.18.tgz",
|
||||
"integrity": "sha512-mAQDCKyB9HsE8Ko5cCM1Jn1AWxXPYV0v8dFPabZRkvsiWUul2YyAqbIaoMKF88Zf2ffnOPSvKhboLf3fnjo5/A==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz",
|
||||
"integrity": "sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"compare-func": "^2.0.0",
|
||||
|
@ -11272,9 +11272,9 @@
|
|||
}
|
||||
},
|
||||
"git-url-parse": {
|
||||
"version": "11.4.0",
|
||||
"resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.0.tgz",
|
||||
"integrity": "sha512-KlIa5jvMYLjXMQXkqpFzobsyD/V2K5DRHl5OAf+6oDFPlPLxrGDVQlIdI63c4/Kt6kai4kALENSALlzTGST3GQ==",
|
||||
"version": "11.4.3",
|
||||
"resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.3.tgz",
|
||||
"integrity": "sha512-LZTTk0nqJnKN48YRtOpR8H5SEfp1oM2tls90NuZmBxN95PnCvmuXGzqQ4QmVirBgKx2KPYfPGteX3/raWjKenQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"git-up": "^4.0.0"
|
||||
|
@ -13709,9 +13709,9 @@
|
|||
}
|
||||
},
|
||||
"meow": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz",
|
||||
"integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-8.1.0.tgz",
|
||||
"integrity": "sha512-fNWkgM1UVMey2kf24yLiccxLihc5W+6zVus3/N0b+VfnJgxV99E9u04X6NAiKdg6ED7DAQBX5sy36NM0QJZkWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/minimist": "^1.2.0",
|
||||
|
@ -22460,9 +22460,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz",
|
||||
"integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==",
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
|
||||
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
transition: .3s cubic-bezier(.4,.2,.5,1.4);
|
||||
transform-origin: 1.43em -.43em;
|
||||
}
|
||||
|
||||
|
||||
.suggestion-box > ul[hidden],
|
||||
.suggestion-box > ul:empty {
|
||||
opacity: 0;
|
||||
|
@ -109,31 +109,33 @@
|
|||
transition-timing-function: ease;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.suggestion-box > ul > li[aria-selected="true"] {
|
||||
background: var(--completion-dark-color);
|
||||
color: var(--inverse-link-color);
|
||||
}
|
||||
|
||||
|
||||
.suggestion-box li:hover mark {
|
||||
background: var(--completion-light-color);
|
||||
color: var(--inverse-link-color);
|
||||
}
|
||||
|
||||
|
||||
.suggestion-box li[aria-selected="true"] mark {
|
||||
background: var(--completion-normal-color);
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.suggestion-box__results--above {
|
||||
bottom: 4.5em;
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.suggestion-box__results--above {
|
||||
bottom: 3.5em;
|
||||
converse-chats {
|
||||
.converse-fullscreen {
|
||||
.suggestion-box__results--above {
|
||||
bottom: 4.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.converse-overlayed {
|
||||
.suggestion-box__results--above {
|
||||
bottom: 3.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,8 +396,8 @@
|
|||
|
||||
/* ******************* Overlay and embedded styles *************************** */
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-overlayed {
|
||||
converse-chats.converse-embedded,
|
||||
converse-chats.converse-overlayed {
|
||||
.controlbox-head {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
@ -416,7 +416,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
converse-chats.converse-overlayed {
|
||||
|
||||
.chat-head, .box-flyout {
|
||||
border-top-left-radius: var(--chatbox-border-radius);
|
||||
|
@ -467,7 +467,7 @@
|
|||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs.converse-overlayed {
|
||||
converse-chats.converse-overlayed {
|
||||
> .row {
|
||||
flex-direction: column;
|
||||
&.no-gutters {
|
||||
|
@ -478,8 +478,8 @@
|
|||
}
|
||||
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-fullscreen {
|
||||
converse-chats.converse-embedded,
|
||||
converse-chats.converse-fullscreen {
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
border:none;
|
||||
|
@ -527,7 +527,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded {
|
||||
converse-chats.converse-embedded {
|
||||
.chat-head {
|
||||
font-size: var(--font-size-huge);
|
||||
}
|
||||
|
@ -558,7 +558,7 @@
|
|||
|
||||
/* ******************* Fullpage styles *************************** */
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
converse-chats.converse-fullscreen {
|
||||
.chatbox-btn {
|
||||
font-size: var(--fullpage-chatbox-button-size);
|
||||
margin: 0 0.3em;
|
||||
|
@ -595,7 +595,7 @@
|
|||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs:not(.converse-embedded) {
|
||||
converse-chats:not(.converse-embedded) {
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
@ -617,9 +617,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-mobile,
|
||||
#conversejs.converse-overlayed,
|
||||
#conversejs.converse-fullscreen {
|
||||
converse-chats.converse-mobile,
|
||||
converse-chats.converse-overlayed,
|
||||
converse-chats.converse-fullscreen {
|
||||
.chatbox {
|
||||
.box-flyout {
|
||||
.chatbox-navback {
|
||||
|
|
|
@ -396,126 +396,128 @@
|
|||
|
||||
/* ******************* Overlay styles *************************** */
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.chatbox {
|
||||
&.chatroom {
|
||||
min-width: var(--chatroom-width) !important;
|
||||
width: var(--chatroom-width);
|
||||
.box-flyout {
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
.chatbox {
|
||||
&.chatroom {
|
||||
min-width: var(--chatroom-width) !important;
|
||||
width: var(--chatroom-width);
|
||||
}
|
||||
.chatbox-title__text {
|
||||
@include make-col(7);
|
||||
}
|
||||
.chatbox-title__buttons {
|
||||
@include make-col(5);
|
||||
}
|
||||
.box-flyout {
|
||||
min-width: var(--chatroom-width) !important;
|
||||
width: var(--chatroom-width);
|
||||
}
|
||||
.chatbox-title__text {
|
||||
@include make-col(7);
|
||||
}
|
||||
.chatbox-title__buttons {
|
||||
@include make-col(5);
|
||||
}
|
||||
|
||||
.chat-head__desc {
|
||||
font-size: 80%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.chatroom-body {
|
||||
.occupants {
|
||||
.occupants-heading {
|
||||
padding: 0;
|
||||
}
|
||||
.occupant-list {
|
||||
border-bottom: none;
|
||||
}
|
||||
ul {
|
||||
.occupant {
|
||||
.occupant-nick-badge {
|
||||
.occupant-badges {
|
||||
display: none;
|
||||
.chat-head__desc {
|
||||
font-size: 80%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.chatroom-body {
|
||||
.occupants {
|
||||
.occupants-heading {
|
||||
padding: 0;
|
||||
}
|
||||
.occupant-list {
|
||||
border-bottom: none;
|
||||
}
|
||||
ul {
|
||||
.occupant {
|
||||
.occupant-nick-badge {
|
||||
.occupant-badges {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.occupant-status {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
.occupant-status {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-area {
|
||||
min-width: var(--overlayed-chat-width);
|
||||
.chat-area {
|
||||
min-width: var(--overlayed-chat-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-fullscreen,
|
||||
#conversejs.converse-mobile {
|
||||
.converse-embedded,
|
||||
.converse-fullscreen,
|
||||
.converse-mobile {
|
||||
|
||||
.chatroom {
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
.chatroom {
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
|
||||
.chatroom-body {
|
||||
.chat-area {
|
||||
&.full {
|
||||
.new-msgs-indicator {
|
||||
max-width: 100%;
|
||||
.chatroom-body {
|
||||
.chat-area {
|
||||
&.full {
|
||||
.new-msgs-indicator {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
padding: var(--occupants-padding);
|
||||
.occupants-heading {
|
||||
font-size: var(--font-size-large);
|
||||
}
|
||||
ul {
|
||||
&.occupant-list {
|
||||
li {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-invite {
|
||||
span {
|
||||
.invited-contact {
|
||||
margin: 0 0 0.5em -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.converse-embedded {
|
||||
.chatroom {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
.occupants-heading {
|
||||
font-size: 120%;
|
||||
}
|
||||
.chat-content {
|
||||
.chat-message {
|
||||
margin: 0.5em;
|
||||
font-size: 120%;
|
||||
}
|
||||
}
|
||||
.sendXMPPMessage {
|
||||
.chat-textarea {
|
||||
padding: 0.5em;
|
||||
font-size: 110%;
|
||||
}
|
||||
}
|
||||
.chatroom-body {
|
||||
height: 100%;
|
||||
.chatroom-form-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
padding: var(--occupants-padding);
|
||||
.occupants-heading {
|
||||
font-size: var(--font-size-large);
|
||||
.occupant-list {
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
ul {
|
||||
&.occupant-list {
|
||||
li {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-invite {
|
||||
span {
|
||||
.invited-contact {
|
||||
margin: 0 0 0.5em -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded {
|
||||
.chatroom {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
.occupants-heading {
|
||||
font-size: 120%;
|
||||
}
|
||||
.chat-content {
|
||||
.chat-message {
|
||||
margin: 0.5em;
|
||||
font-size: 120%;
|
||||
}
|
||||
}
|
||||
.sendXMPPMessage {
|
||||
.chat-textarea {
|
||||
padding: 0.5em;
|
||||
font-size: 110%;
|
||||
}
|
||||
}
|
||||
.chatroom-body {
|
||||
height: 100%;
|
||||
.chatroom-form-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
.occupant-list {
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -524,9 +526,9 @@
|
|||
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs.converse-mobile,
|
||||
#conversejs.converse-overlayed,
|
||||
#conversejs.converse-fullscreen {
|
||||
converse-chats.converse-mobile,
|
||||
converse-chats.converse-overlayed,
|
||||
converse-chats.converse-fullscreen {
|
||||
.chatbox {
|
||||
.box-flyout {
|
||||
.chat-head-chatroom {
|
||||
|
|
|
@ -384,192 +384,218 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.toggle-controlbox {
|
||||
order: -1;
|
||||
text-align: center;
|
||||
background-color: var(--link-color);
|
||||
border-top-left-radius: var(--button-border-radius);
|
||||
border-top-right-radius: var(--button-border-radius);
|
||||
color: #0a0a0a;
|
||||
float: right;
|
||||
height: 100%;
|
||||
margin: 0 var(--chat-gutter);
|
||||
padding: 1em;
|
||||
span {
|
||||
color: var(--inverse-link-color);
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
.toggle-controlbox {
|
||||
order: -1;
|
||||
text-align: center;
|
||||
background-color: var(--link-color);
|
||||
border-top-left-radius: var(--button-border-radius);
|
||||
border-top-right-radius: var(--button-border-radius);
|
||||
color: #0a0a0a;
|
||||
float: right;
|
||||
height: 100%;
|
||||
margin: 0 var(--chat-gutter);
|
||||
padding: 1em;
|
||||
span {
|
||||
color: var(--inverse-link-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#controlbox {
|
||||
min-width: var(--controlbox-width) !important;
|
||||
width: var(--controlbox-width);
|
||||
.box-flyout {
|
||||
#controlbox {
|
||||
min-width: var(--controlbox-width) !important;
|
||||
width: var(--controlbox-width);
|
||||
}
|
||||
.box-flyout {
|
||||
min-width: var(--controlbox-width) !important;
|
||||
width: var(--controlbox-width);
|
||||
}
|
||||
|
||||
.login-trusted {
|
||||
white-space: nowrap;
|
||||
font-size: 90%;
|
||||
}
|
||||
.login-trusted {
|
||||
white-space: nowrap;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
#converse-login-trusted {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
&:not(.logged-out) {
|
||||
.controlbox-head {
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-login-trusted {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
&:not(.logged-out) {
|
||||
.controlbox-head {
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
|
||||
.controlbox-head {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
|
||||
.brand-heading {
|
||||
color: var(--controlbox-text-color);
|
||||
font-size: 2em;
|
||||
}
|
||||
.chatbox-btn {
|
||||
color: var(--controlbox-head-color);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col(12);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#converse-register {
|
||||
.button-cancel {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.controlbox-panes {
|
||||
border-radius: var(--chatbox-border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-fullscreen{
|
||||
.toggle-controlbox {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-fullscreen,
|
||||
#conversejs.converse-mobile {
|
||||
#controlbox {
|
||||
@include make-col-ready();
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(4);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(3);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(2);
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
|
||||
.controlbox-pane {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#converse-login-panel {
|
||||
border-radius: 0;
|
||||
.converse-form {
|
||||
padding: 3em 2em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-register-login {
|
||||
line-height: var(--line-height-huge);
|
||||
}
|
||||
|
||||
converse-brand-logo {
|
||||
@include make-col(12);
|
||||
margin-top: 5em;
|
||||
margin-bottom: 1em;
|
||||
.brand-heading {
|
||||
width: 100%;
|
||||
font-size: 500%;
|
||||
padding: 0.7em 0 0 0;
|
||||
opacity: 0.8;
|
||||
color: var(--brand-heading-color);
|
||||
}
|
||||
.brand-subtitle {
|
||||
font-size: 90%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
.brand-heading {
|
||||
font-size: 300%;
|
||||
color: var(--controlbox-text-color);
|
||||
font-size: 2em;
|
||||
}
|
||||
.chatbox-btn {
|
||||
color: var(--controlbox-head-color);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col(12);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#converse-register {
|
||||
.button-cancel {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.controlbox-panes {
|
||||
border-radius: var(--chatbox-border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.converse-embedded,
|
||||
.converse-fullscreen{
|
||||
.toggle-controlbox {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.converse-embedded,
|
||||
.converse-fullscreen,
|
||||
.converse-mobile {
|
||||
#controlbox {
|
||||
@include make-col-ready();
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(4);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(3);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(2);
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
|
||||
.controlbox-pane {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#converse-login-panel {
|
||||
border-radius: 0;
|
||||
.converse-form {
|
||||
padding: 3em 2em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-register-login {
|
||||
line-height: var(--line-height-huge);
|
||||
}
|
||||
|
||||
converse-brand-logo {
|
||||
@include make-col(12);
|
||||
margin-top: 5em;
|
||||
margin-bottom: 1em;
|
||||
.brand-heading {
|
||||
width: 100%;
|
||||
font-size: 500%;
|
||||
padding: 0.7em 0 0 0;
|
||||
opacity: 0.8;
|
||||
color: var(--brand-heading-color);
|
||||
}
|
||||
.brand-subtitle {
|
||||
font-size: 90%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
.brand-heading {
|
||||
font-size: 300%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
@include fade-in;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.box-flyout {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background-color: var(--controlbox-head-color);
|
||||
|
||||
.controlbox-head {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col-ready();
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(6);
|
||||
@include make-col-offset(3);
|
||||
}
|
||||
.title, .instructions {
|
||||
margin: 1em 0;
|
||||
}
|
||||
input[type=submit],
|
||||
input[type=button] {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
@include fade-in;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
}
|
||||
.converse-fullscreen {
|
||||
.controlbox-panes {
|
||||
padding-top: 1em;
|
||||
}
|
||||
.box-flyout {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.converse-overlayed {
|
||||
.brand-heading {
|
||||
padding-top: 0.8rem;
|
||||
padding-left: 0.8rem;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background-color: var(--controlbox-head-color);
|
||||
|
||||
.controlbox-head {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col-ready();
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
.converse-svg-logo {
|
||||
height: 1em;
|
||||
}
|
||||
#controlbox {
|
||||
#converse-login-panel {
|
||||
height: 100%;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(6);
|
||||
@include make-col-offset(3);
|
||||
}
|
||||
.title, .instructions {
|
||||
margin: 1em 0;
|
||||
}
|
||||
input[type=submit],
|
||||
input[type=button] {
|
||||
width: auto;
|
||||
.controlbox-panes {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -628,28 +654,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.controlbox-panes {
|
||||
padding-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.brand-heading {
|
||||
padding-top: 0.8rem;
|
||||
padding-left: 0.8rem;
|
||||
width: 100%;
|
||||
}
|
||||
.converse-svg-logo {
|
||||
height: 1em;
|
||||
}
|
||||
#controlbox {
|
||||
#converse-login-panel {
|
||||
height: 100%;
|
||||
}
|
||||
.controlbox-panes {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,32 +114,32 @@ body.converse-fullscreen {
|
|||
overflow-y: none;
|
||||
}
|
||||
|
||||
&.converse-overlayed {
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
}
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
height: 3em;
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
}
|
||||
|
||||
&.converse-fullscreen,
|
||||
&.converse-mobile {
|
||||
.converse-chatboxes {
|
||||
width: 100vw;
|
||||
left: -15px; // Hack due to padding added by bootstrap
|
||||
}
|
||||
}
|
||||
&.converse-overlayed {
|
||||
height: 3em;
|
||||
}
|
||||
&.converse-embedded {
|
||||
box-sizing: border-box;
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
bottom: auto;
|
||||
height: 100%; // When embedded, it fills the containing element
|
||||
position: relative;
|
||||
right: auto;
|
||||
width: 100%;
|
||||
.converse-fullscreen,
|
||||
.converse-mobile {
|
||||
.converse-chatboxes {
|
||||
width: 100vw;
|
||||
left: -15px; // Hack due to padding added by bootstrap
|
||||
}
|
||||
}
|
||||
.converse-embedded {
|
||||
box-sizing: border-box;
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
bottom: auto;
|
||||
height: 100%; // When embedded, it fills the containing element
|
||||
position: relative;
|
||||
right: auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
converse-brand-heading {
|
||||
|
|
108
sass/_emoji.scss
108
sass/_emoji.scss
|
@ -185,73 +185,74 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 18em;
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
.emoji-picker__header {
|
||||
.emoji-category {
|
||||
img {
|
||||
height: var(--font-size) !important;
|
||||
width: var(--font-size) !important;
|
||||
}
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 18em;
|
||||
}
|
||||
}
|
||||
converse-emoji-picker {
|
||||
.emoji-picker {
|
||||
.insert-emoji {
|
||||
a {
|
||||
font-size: var(--font-size);
|
||||
line-height: calc(var(--font-size) * 1.5);
|
||||
padding: 0;
|
||||
height: calc(var(--font-size) * 1.5);
|
||||
width: calc(var(--font-size) * 1.5);
|
||||
}
|
||||
img {
|
||||
height: var(--font-size);
|
||||
width: var(--font-size);
|
||||
}
|
||||
}
|
||||
}
|
||||
.emoji-skintone-picker {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
.chatbox {
|
||||
.emoji-picker__header {
|
||||
.emoji-category {
|
||||
font-size: var(--font-size-small);
|
||||
img {
|
||||
height: var(--font-size) !important;
|
||||
width: var(--font-size) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.emoji-picker__lists {
|
||||
height: 7em;
|
||||
converse-emoji-picker {
|
||||
.emoji-picker {
|
||||
.insert-emoji {
|
||||
a {
|
||||
font-size: var(--font-size);
|
||||
line-height: calc(var(--font-size) * 1.5);
|
||||
padding: 0;
|
||||
height: calc(var(--font-size) * 1.5);
|
||||
width: calc(var(--font-size) * 1.5);
|
||||
}
|
||||
img {
|
||||
height: var(--font-size);
|
||||
width: var(--font-size);
|
||||
}
|
||||
}
|
||||
}
|
||||
.emoji-skintone-picker {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
.emoji-picker__header {
|
||||
.emoji-category {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
}
|
||||
.emoji-picker__lists {
|
||||
height: 7em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-embedded {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 20em;
|
||||
.converse-embedded {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 20em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 22em;
|
||||
.converse-fullscreen {
|
||||
converse-emoji-dropdown {
|
||||
.dropdown-menu {
|
||||
min-width: 22em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
.toggle-smiley {
|
||||
}
|
||||
converse-emoji-picker {
|
||||
.emoji-picker__lists {
|
||||
height: 12em;
|
||||
.chatbox {
|
||||
.toggle-smiley {
|
||||
}
|
||||
converse-emoji-picker {
|
||||
.emoji-picker__lists {
|
||||
height: 12em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -266,4 +267,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -383,22 +383,25 @@
|
|||
border-bottom: var(--chatroom-separator-border-bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.message {
|
||||
&.chat-msg {
|
||||
&.chat-msg--followup {
|
||||
.chat-msg__content {
|
||||
margin-left: 0;
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
.message {
|
||||
&.chat-msg {
|
||||
&.chat-msg--followup {
|
||||
.chat-msg__content {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#conversejs:not(.converse-embedded) {
|
||||
converse-chats:not(.converse-embedded) {
|
||||
.message {
|
||||
&.chat-msg {
|
||||
.chat-msg__author {
|
||||
|
|
|
@ -1,90 +1,92 @@
|
|||
#conversejs.converse-overlayed {
|
||||
#minimized-chats {
|
||||
order: 100;
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
#minimized-chats {
|
||||
order: 100;
|
||||
|
||||
width: var(--minimized-chats-width);
|
||||
margin-bottom: 0;
|
||||
border-top-left-radius: var(--chatbox-border-radius);
|
||||
border-top-right-radius: var(--chatbox-border-radius);
|
||||
color: var(--inverse-link-color);
|
||||
margin-right: var(--chat-gutter);
|
||||
padding: 0;
|
||||
|
||||
.badge {
|
||||
bottom: 8px;
|
||||
border: 1px solid var(--overlayed-badge-color);
|
||||
}
|
||||
|
||||
#toggle-minimized-chats {
|
||||
width: var(--minimized-chats-width);
|
||||
margin-bottom: 0;
|
||||
border-top-left-radius: var(--chatbox-border-radius);
|
||||
border-top-right-radius: var(--chatbox-border-radius);
|
||||
background-color: var(--link-color);
|
||||
padding: 1em 0 0 0;
|
||||
text-align: center;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
overflow-y: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
height: 45px;
|
||||
width: 9em;
|
||||
}
|
||||
color: var(--inverse-link-color);
|
||||
margin-right: var(--chat-gutter);
|
||||
padding: 0;
|
||||
|
||||
a.restore-chat {
|
||||
cursor: pointer;
|
||||
padding: 1px 0 1px 5px;
|
||||
color: var(--chat-head-text-color);
|
||||
line-height: 15px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
.badge {
|
||||
bottom: 8px;
|
||||
border: 1px solid var(--overlayed-badge-color);
|
||||
}
|
||||
}
|
||||
|
||||
a.restore-chat:visited {
|
||||
color: var(--chat-head-text-color);
|
||||
}
|
||||
|
||||
.minimized-chats-flyout {
|
||||
flex-direction: column-reverse;
|
||||
bottom: 45px;
|
||||
width: var(--minimized-chats-width);
|
||||
|
||||
.chat-head {
|
||||
min-height: 0;
|
||||
padding: 0.3em;
|
||||
border-radius: var(--chatbox-border-radius);
|
||||
height: 35px;
|
||||
margin-bottom: 0.2em;
|
||||
width: 100%;
|
||||
max-width: 9em;
|
||||
flex-wrap: nowrap;
|
||||
#toggle-minimized-chats {
|
||||
border-top-left-radius: var(--chatbox-border-radius);
|
||||
border-top-right-radius: var(--chatbox-border-radius);
|
||||
background-color: var(--link-color);
|
||||
padding: 1em 0 0 0;
|
||||
text-align: center;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
overflow-y: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
height: 45px;
|
||||
width: 9em;
|
||||
}
|
||||
&.minimized {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-message-count {
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
border: 1px solid;
|
||||
text-shadow: 1px 1px 0 var(--text-shadow-color);
|
||||
color: var(--warning-color);
|
||||
border-radius: 5px;
|
||||
padding: 2px 4px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 116px;
|
||||
bottom: 10px;
|
||||
}
|
||||
.unread-message-count-hidden,
|
||||
.chat-head-message-count-hidden {
|
||||
display: none;
|
||||
a.restore-chat {
|
||||
cursor: pointer;
|
||||
padding: 1px 0 1px 5px;
|
||||
color: var(--chat-head-text-color);
|
||||
line-height: 15px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.restore-chat:visited {
|
||||
color: var(--chat-head-text-color);
|
||||
}
|
||||
|
||||
.minimized-chats-flyout {
|
||||
flex-direction: column-reverse;
|
||||
bottom: 45px;
|
||||
width: var(--minimized-chats-width);
|
||||
|
||||
.chat-head {
|
||||
min-height: 0;
|
||||
padding: 0.3em;
|
||||
border-radius: var(--chatbox-border-radius);
|
||||
height: 35px;
|
||||
margin-bottom: 0.2em;
|
||||
width: 100%;
|
||||
max-width: 9em;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
&.minimized {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-message-count {
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
border: 1px solid;
|
||||
text-shadow: 1px 1px 0 var(--text-shadow-color);
|
||||
color: var(--warning-color);
|
||||
border-radius: 5px;
|
||||
padding: 2px 4px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 116px;
|
||||
bottom: 10px;
|
||||
}
|
||||
.unread-message-count-hidden,
|
||||
.chat-head-message-count-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,21 +187,23 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 235px;
|
||||
converse-chats {
|
||||
.converse-overlayed {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 235px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatroom {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 280px;
|
||||
.chatroom {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 280px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
await u.waitUntil(() => view.model.messages.last()?.get('received'));
|
||||
|
||||
// Test that pressing @ brings up all options
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
const at_event = {
|
||||
'target': textarea,
|
||||
'preventDefault': function preventDefault () {},
|
||||
|
@ -53,11 +53,11 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = '@';
|
||||
view.onKeyUp(at_event);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -95,7 +95,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
await u.waitUntil(() => view.model.messages.last()?.get('received'));
|
||||
|
||||
// Test that pressing @ brings up all options
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
const at_event = {
|
||||
'target': textarea,
|
||||
'preventDefault': function preventDefault () {},
|
||||
|
@ -108,11 +108,11 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = '\n@';
|
||||
view.onKeyUp(at_event);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -150,7 +150,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
await u.waitUntil(() => view.model.messages.last()?.get('received'));
|
||||
|
||||
// Test that pressing @ brings up all options
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
const at_event = {
|
||||
'target': textarea,
|
||||
'preventDefault': function preventDefault () {},
|
||||
|
@ -163,11 +163,11 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = '(@';
|
||||
view.onKeyUp(at_event);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 4);
|
||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('dick');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('harry');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('jane');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(4)').textContent).toBe('tom');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -191,7 +191,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
})));
|
||||
});
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
const at_event = {
|
||||
'target': textarea,
|
||||
'preventDefault': function preventDefault() { },
|
||||
|
@ -204,17 +204,17 @@ describe("The nickname autocomplete feature", function () {
|
|||
view.onKeyDown(at_event);
|
||||
textarea.value = '@ber';
|
||||
view.onKeyUp(at_event);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 3);
|
||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('bernard');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('naber');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('helberlo');
|
||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 3);
|
||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('bernard');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('naber');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(3)').textContent).toBe('helberlo');
|
||||
|
||||
// Test that when the query index is equal, results should be sorted by length
|
||||
textarea.value = '@jo';
|
||||
view.onKeyUp(at_event);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.suggestion-box__results li').length === 2);
|
||||
expect(view.el.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
|
||||
expect(view.el.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
|
||||
await u.waitUntil(() => view.querySelectorAll('.suggestion-box__results li').length === 2);
|
||||
expect(view.querySelector('.suggestion-box__results li:first-child').textContent).toBe('john');
|
||||
expect(view.querySelector('.suggestion-box__results li:nth-child(2)').textContent).toBe('jones');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -239,7 +239,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.model.occupants.length).toBe(2);
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = "hello som";
|
||||
|
||||
// Press tab
|
||||
|
@ -252,9 +252,9 @@ describe("The nickname autocomplete feature", function () {
|
|||
}
|
||||
view.onKeyDown(tab_event);
|
||||
view.onKeyUp(tab_event);
|
||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||
|
||||
const backspace_event = {
|
||||
'target': textarea,
|
||||
|
@ -267,7 +267,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = textarea.value.slice(0, textarea.value.length-1)
|
||||
view.onKeyUp(backspace_event);
|
||||
}
|
||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === true);
|
||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === true);
|
||||
|
||||
presence = $pres({
|
||||
'to': 'romeo@montague.lit/orchard',
|
||||
|
@ -284,8 +284,8 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = "hello s s";
|
||||
view.onKeyDown(tab_event);
|
||||
view.onKeyUp(tab_event);
|
||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||
|
||||
const up_arrow_event = {
|
||||
'target': textarea,
|
||||
|
@ -295,9 +295,9 @@ describe("The nickname autocomplete feature", function () {
|
|||
}
|
||||
view.onKeyDown(up_arrow_event);
|
||||
view.onKeyUp(up_arrow_event);
|
||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
||||
expect(view.el.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(2);
|
||||
expect(view.querySelector('.suggestion-box__results li[aria-selected="false"]').textContent).toBe('some1');
|
||||
expect(view.querySelector('.suggestion-box__results li[aria-selected="true"]').textContent).toBe('some2');
|
||||
|
||||
view.onKeyDown({
|
||||
'target': textarea,
|
||||
|
@ -322,7 +322,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
textarea.value = "hello z";
|
||||
view.onKeyDown(tab_event);
|
||||
view.onKeyUp(tab_event);
|
||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||
|
||||
view.onKeyDown(tab_event);
|
||||
view.onKeyUp(tab_event);
|
||||
|
@ -351,7 +351,7 @@ describe("The nickname autocomplete feature", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
expect(view.model.occupants.length).toBe(2);
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = "hello @some1 ";
|
||||
|
||||
// Press backspace
|
||||
|
@ -365,9 +365,9 @@ describe("The nickname autocomplete feature", function () {
|
|||
view.onKeyDown(backspace_event);
|
||||
textarea.value = "hello @some1"; // Mimic backspace
|
||||
view.onKeyUp(backspace_event);
|
||||
await u.waitUntil(() => view.el.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.el.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||
expect(view.el.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||
await u.waitUntil(() => view.querySelector('.suggestion-box__results').hidden === false);
|
||||
expect(view.querySelectorAll('.suggestion-box__results li').length).toBe(1);
|
||||
expect(view.querySelector('.suggestion-box__results li').textContent).toBe('some1');
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -28,13 +28,13 @@ describe("A chat room", function () {
|
|||
|
||||
spyOn(view, 'renderBookmarkForm').and.callThrough();
|
||||
spyOn(view, 'closeForm').and.callThrough();
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-bookmark') !== null);
|
||||
const toggle = view.el.querySelector('.toggle-bookmark');
|
||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
|
||||
const toggle = view.querySelector('.toggle-bookmark');
|
||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||
toggle.click();
|
||||
expect(view.renderBookmarkForm).toHaveBeenCalled();
|
||||
|
||||
view.el.querySelector('.button-cancel').click();
|
||||
view.querySelector('.button-cancel').click();
|
||||
expect(view.closeForm).toHaveBeenCalled();
|
||||
expect(u.hasClass('on-button', toggle), false);
|
||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||
|
@ -74,13 +74,13 @@ describe("A chat room", function () {
|
|||
* </iq>
|
||||
*/
|
||||
expect(view.model.get('bookmarked')).toBeFalsy();
|
||||
const form = view.el.querySelector('.chatroom-form');
|
||||
const form = view.querySelector('.chatroom-form');
|
||||
form.querySelector('input[name="name"]').value = 'Play's the Thing';
|
||||
form.querySelector('input[name="autojoin"]').checked = 'checked';
|
||||
form.querySelector('input[name="nick"]').value = 'JC';
|
||||
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
view.el.querySelector('.muc-bookmark-form .btn-primary').click();
|
||||
view.querySelector('.muc-bookmark-form .btn-primary').click();
|
||||
|
||||
const sent_stanza = await u.waitUntil(
|
||||
() => IQ_stanzas.filter(s => sizzle('iq publish[node="storage:bookmarks"]', s).length).pop());
|
||||
|
@ -124,8 +124,8 @@ describe("A chat room", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.model.get('bookmarked'));
|
||||
expect(view.model.get('bookmarked')).toBeTruthy();
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-bookmark')?.title === 'Unbookmark this groupchat');
|
||||
expect(u.hasClass('on-button', view.el.querySelector('.toggle-bookmark')), true);
|
||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark')?.title === 'Unbookmark this groupchat');
|
||||
expect(u.hasClass('on-button', view.querySelector('.toggle-bookmark')), true);
|
||||
// We ignore this IQ stanza... (unless it's an error stanza), so
|
||||
// nothing to test for here.
|
||||
done();
|
||||
|
@ -211,7 +211,7 @@ describe("A chat room", function () {
|
|||
);
|
||||
await _converse.api.rooms.open(`lounge@montague.lit`);
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
expect(view.el.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
|
||||
expect(view.querySelector('.chatbox-title__text .fa-bookmark')).toBe(null);
|
||||
_converse.bookmarks.create({
|
||||
'jid': view.model.get('jid'),
|
||||
'autojoin': false,
|
||||
|
@ -219,9 +219,9 @@ describe("A chat room", function () {
|
|||
'nick': ' some1'
|
||||
});
|
||||
view.model.set('bookmarked', true);
|
||||
await u.waitUntil(() => view.el.querySelector('.chatbox-title__text .fa-bookmark') !== null);
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') !== null);
|
||||
view.model.set('bookmarked', false);
|
||||
await u.waitUntil(() => view.el.querySelector('.chatbox-title__text .fa-bookmark') === null);
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -233,7 +233,7 @@ describe("A chat room", function () {
|
|||
const muc_jid = 'theplay@conference.shakespeare.lit';
|
||||
await _converse.api.rooms.open(muc_jid);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-bookmark'));
|
||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
|
||||
|
||||
spyOn(view, 'toggleBookmark').and.callThrough();
|
||||
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
|
||||
|
@ -249,12 +249,12 @@ describe("A chat room", function () {
|
|||
expect(_converse.bookmarks.length).toBe(1);
|
||||
await u.waitUntil(() => _converse.chatboxes.length >= 1);
|
||||
expect(view.model.get('bookmarked')).toBeTruthy();
|
||||
await u.waitUntil(() => view.el.querySelector('.chatbox-title__text .fa-bookmark') !== null);
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') !== null);
|
||||
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
|
||||
const bookmark_icon = view.el.querySelector('.toggle-bookmark');
|
||||
const bookmark_icon = view.querySelector('.toggle-bookmark');
|
||||
bookmark_icon.click();
|
||||
expect(view.toggleBookmark).toHaveBeenCalled();
|
||||
await u.waitUntil(() => view.el.querySelector('.chatbox-title__text .fa-bookmark') === null);
|
||||
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null);
|
||||
expect(_converse.bookmarks.length).toBe(0);
|
||||
|
||||
// Check that an IQ stanza is sent out, containing no
|
||||
|
@ -594,20 +594,20 @@ describe("Bookmarks", function () {
|
|||
'jid': 'first@conference.shakespeare.lit'
|
||||
}).c('nick').t('JC');
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
|
||||
expect(view.el.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(2);
|
||||
view.el.querySelector('.bookmarks.rooms-list .open-room').click();
|
||||
await u.waitUntil(() => view.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length);
|
||||
expect(view.querySelectorAll('#chatrooms div.bookmarks.rooms-list .room-item').length).toBe(2);
|
||||
view.querySelector('.bookmarks.rooms-list .open-room').click();
|
||||
await u.waitUntil(() => _converse.chatboxes.length === 2);
|
||||
expect((await api.rooms.get('first@conference.shakespeare.lit')).get('hidden')).toBe(false);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.list-container--bookmarks .available-chatroom:not(.hidden)').length === 1);
|
||||
view.el.querySelector('.list-container--bookmarks .available-chatroom:not(.hidden) .open-room').click();
|
||||
await u.waitUntil(() => view.querySelectorAll('.list-container--bookmarks .available-chatroom:not(.hidden)').length === 1);
|
||||
view.querySelector('.list-container--bookmarks .available-chatroom:not(.hidden) .open-room').click();
|
||||
await u.waitUntil(() => _converse.chatboxes.length === 3);
|
||||
expect((await api.rooms.get('first@conference.shakespeare.lit')).get('hidden')).toBe(true);
|
||||
expect((await api.rooms.get('theplay@conference.shakespeare.lit')).get('hidden')).toBe(false);
|
||||
|
||||
view.el.querySelector('.list-container--openrooms .open-room:first-child').click();
|
||||
await u.waitUntil(() => view.el.querySelector('.list-item.open').getAttribute('data-room-jid') === 'first@conference.shakespeare.lit');
|
||||
view.querySelector('.list-container--openrooms .open-room:first-child').click();
|
||||
await u.waitUntil(() => view.querySelector('.list-item.open').getAttribute('data-room-jid') === 'first@conference.shakespeare.lit');
|
||||
expect((await api.rooms.get('first@conference.shakespeare.lit')).get('hidden')).toBe(false);
|
||||
expect((await api.rooms.get('theplay@conference.shakespeare.lit')).get('hidden')).toBe(true);
|
||||
done();
|
||||
|
@ -689,19 +689,19 @@ describe("When hide_open_bookmarks is true and a bookmarked room is opened", fun
|
|||
|
||||
const u = converse.env.utils;
|
||||
const bmarks_view = _converse.bookmarksview;
|
||||
await u.waitUntil(() => bmarks_view.el.querySelectorAll(".open-room").length, 500);
|
||||
const room_els = bmarks_view.el.querySelectorAll(".open-room");
|
||||
await u.waitUntil(() => bmarks_view.querySelectorAll(".open-room").length, 500);
|
||||
const room_els = bmarks_view.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
|
||||
const bookmark = _converse.bookmarksview.el.querySelector(".open-room");
|
||||
const bookmark = _converse.bookmarksview.querySelector(".open-room");
|
||||
bookmark.click();
|
||||
await u.waitUntil(() => _converse.chatboxviews.get(jid));
|
||||
|
||||
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
|
||||
expect(u.hasClass('hidden', _converse.bookmarksview.querySelector(".available-chatroom"))).toBeTruthy();
|
||||
// Check that it reappears once the room is closed
|
||||
const view = _converse.chatboxviews.get(jid);
|
||||
view.close();
|
||||
await u.waitUntil(() => !u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom")));
|
||||
await u.waitUntil(() => !u.hasClass('hidden', _converse.bookmarksview.querySelector(".available-chatroom")));
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
102
spec/chatbox.js
102
spec/chatbox.js
|
@ -40,7 +40,7 @@ describe("Chatboxes", function () {
|
|||
await _converse.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => view.content.querySelectorAll('.chat-msg').length);
|
||||
const msg_txt_sel = 'converse-chat-message:last-child .chat-msg__body';
|
||||
await u.waitUntil(() => view.el.querySelector(msg_txt_sel).textContent.trim() === 'hello world');
|
||||
await u.waitUntil(() => view.querySelector(msg_txt_sel).textContent.trim() === 'hello world');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -58,7 +58,7 @@ describe("Chatboxes", function () {
|
|||
}
|
||||
await u.waitUntil(() => sizzle('converse-chat-message', view.el).length === 10);
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = '/clear';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -84,8 +84,8 @@ describe("Chatboxes", function () {
|
|||
spyOn(_converse.minimize, 'trimChats');
|
||||
expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length, 700);
|
||||
const online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group li').length, 700);
|
||||
const online_contacts = _converse.rosterview.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
|
||||
expect(online_contacts.length).toBe(17);
|
||||
let el = online_contacts[0];
|
||||
el.click();
|
||||
|
@ -153,7 +153,7 @@ describe("Chatboxes", function () {
|
|||
const view = await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const el = sizzle('a.open-chat:contains("'+view.model.getDisplayName()+'")', _converse.rosterview.el).pop();
|
||||
await u.waitUntil(() => u.isVisible(el));
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
await u.waitUntil(() => u.isVisible(textarea));
|
||||
textarea.blur();
|
||||
spyOn(view.model, 'maybeShow').and.callThrough();
|
||||
|
@ -209,14 +209,14 @@ describe("Chatboxes", function () {
|
|||
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const chatview = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(chatview, 'close').and.callThrough();
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
// We need to rebind all events otherwise our spy won't be called
|
||||
chatview.delegateEvents();
|
||||
chatview.el.querySelector('.close-chatbox-button').click();
|
||||
chatview.querySelector('.close-chatbox-button').click();
|
||||
expect(chatview.close).toHaveBeenCalled();
|
||||
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
|
||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxClosed', jasmine.any(Object));
|
||||
|
@ -231,7 +231,7 @@ describe("Chatboxes", function () {
|
|||
spyOn(_converse.minimize, 'trimChats');
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
|
||||
mock.closeControlBox();
|
||||
|
@ -274,19 +274,19 @@ describe("Chatboxes", function () {
|
|||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const toolbar = view.el.querySelector('.chat-toolbar');
|
||||
const toolbar = view.querySelector('.chat-toolbar');
|
||||
const counter = toolbar.querySelector('.message-limit');
|
||||
expect(counter.textContent).toBe('200');
|
||||
view.insertIntoTextArea('hello world');
|
||||
expect(counter.textContent).toBe('188');
|
||||
|
||||
toolbar.querySelector('.toggle-emojis').click();
|
||||
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__lists'));
|
||||
const picker = await u.waitUntil(() => view.querySelector('.emoji-picker__lists'));
|
||||
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji a'));
|
||||
item.click()
|
||||
expect(counter.textContent).toBe('179');
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
const ev = {
|
||||
target: textarea,
|
||||
preventDefault: function preventDefault () {},
|
||||
|
@ -314,7 +314,7 @@ describe("Chatboxes", function () {
|
|||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const counter = view.el.querySelector('.chat-toolbar .message-limit');
|
||||
const counter = view.querySelector('.chat-toolbar .message-limit');
|
||||
expect(counter).toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
@ -336,7 +336,7 @@ describe("Chatboxes", function () {
|
|||
_converse.visible_toolbar_buttons.call = false;
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
let view = _converse.chatboxviews.get(contact_jid);
|
||||
toolbar = view.el.querySelector('.chat-toolbar');
|
||||
toolbar = view.querySelector('.chat-toolbar');
|
||||
call_button = toolbar.querySelector('.toggle-call');
|
||||
expect(call_button === null).toBeTruthy();
|
||||
view.close();
|
||||
|
@ -345,7 +345,7 @@ describe("Chatboxes", function () {
|
|||
_converse.visible_toolbar_buttons.call = true; // enable the button
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
toolbar = view.el.querySelector('.chat-toolbar');
|
||||
toolbar = view.querySelector('.chat-toolbar');
|
||||
call_button = toolbar.querySelector('.toggle-call');
|
||||
call_button.click();
|
||||
expect(_converse.api.trigger).toHaveBeenCalledWith('callButtonClicked', jasmine.any(Object));
|
||||
|
@ -390,7 +390,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openControlBox(_converse);
|
||||
u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
spyOn(_converse.connection, 'send');
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
|
@ -413,7 +413,7 @@ describe("Chatboxes", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
view.model.minimize();
|
||||
|
@ -447,14 +447,14 @@ describe("Chatboxes", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
expect(view.model.get('chat_state')).toBe('active');
|
||||
spyOn(_converse.connection, 'send');
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
@ -469,7 +469,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
// The notification is not sent again
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
@ -486,14 +486,14 @@ describe("Chatboxes", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
expect(view.model.get('chat_state')).toBe('active');
|
||||
spyOn(_converse.connection, 'send');
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
@ -511,7 +511,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
||||
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
|
||||
// <composing> state
|
||||
|
@ -525,7 +525,7 @@ describe("Chatboxes", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
let csn = mock.cur_names[1] + ' is typing';
|
||||
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
|
||||
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === csn);
|
||||
expect(view.model.messages.length).toEqual(0);
|
||||
|
||||
// <paused> state
|
||||
|
@ -537,7 +537,7 @@ describe("Chatboxes", function () {
|
|||
}).c('paused', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
csn = mock.cur_names[1] + ' has stopped typing';
|
||||
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
|
||||
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === csn);
|
||||
|
||||
msg = $msg({
|
||||
from: sender_jid,
|
||||
|
@ -547,7 +547,7 @@ describe("Chatboxes", function () {
|
|||
}).c('body').t('hello world').tree();
|
||||
await _converse.handleMessageStanza(msg);
|
||||
const msg_el = await u.waitUntil(() => view.content.querySelector('.chat-msg'));
|
||||
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === '');
|
||||
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === '');
|
||||
expect(msg_el.querySelector('.chat-msg__text').textContent).toBe('hello world');
|
||||
done();
|
||||
}));
|
||||
|
@ -584,7 +584,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
await u.waitUntil(() => u.shouldCreateMessage.calls.count());
|
||||
expect(view.model.messages.length).toEqual(0);
|
||||
const el = view.el.querySelector('.chat-content__notifications');
|
||||
const el = view.querySelector('.chat-content__notifications');
|
||||
expect(el.textContent).toBe('');
|
||||
done();
|
||||
}));
|
||||
|
@ -600,7 +600,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length, 700);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group li').length, 700);
|
||||
_converse.TIMEOUTS.PAUSED = 200; // Make the timeout shorter so that we can test
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
|
@ -608,7 +608,7 @@ describe("Chatboxes", function () {
|
|||
spyOn(view.model, 'setChatState').and.callThrough();
|
||||
expect(view.model.get('chat_state')).toBe('active');
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
@ -632,14 +632,14 @@ describe("Chatboxes", function () {
|
|||
// out if the user simply types longer than the
|
||||
// timeout.
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.setChatState).toHaveBeenCalled();
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
expect(view.model.get('chat_state')).toBe('composing');
|
||||
|
@ -653,7 +653,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
// TODO: only show paused state if the previous state was composing
|
||||
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
|
@ -669,7 +669,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
const csn = mock.cur_names[1] + ' has stopped typing';
|
||||
await u.waitUntil( () => view.el.querySelector('.chat-content__notifications').innerText === csn);
|
||||
await u.waitUntil( () => view.querySelector('.chat-content__notifications').innerText === csn);
|
||||
expect(view.model.messages.length).toEqual(0);
|
||||
done();
|
||||
}));
|
||||
|
@ -703,7 +703,7 @@ describe("Chatboxes", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
await u.waitUntil(() => u.shouldCreateMessage.calls.count());
|
||||
expect(view.model.messages.length).toEqual(0);
|
||||
const el = view.el.querySelector('.chat-content__notifications');
|
||||
const el = view.querySelector('.chat-content__notifications');
|
||||
expect(el.textContent).toBe('');
|
||||
done();
|
||||
done();
|
||||
|
@ -725,7 +725,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 1000);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 1000);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
await u.waitUntil(() => view.model.get('chat_state') === 'active');
|
||||
|
@ -733,7 +733,7 @@ describe("Chatboxes", function () {
|
|||
expect(messages.length).toBe(1);
|
||||
expect(view.model.get('chat_state')).toBe('active');
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
keyCode: 1
|
||||
});
|
||||
await u.waitUntil(() => view.model.get('chat_state') === 'composing', 600);
|
||||
|
@ -804,7 +804,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
const view = await mock.openChatBoxFor(_converse, contact_jid);
|
||||
expect(view.model.get('chat_state')).toBe('active');
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
@ -831,7 +831,7 @@ describe("Chatboxes", function () {
|
|||
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-event').length).toBe(0);
|
||||
// Insert <composing> message, to also check that
|
||||
// text messages are inserted correctly with
|
||||
// temporary chat events in the chat contents.
|
||||
|
@ -843,7 +843,7 @@ describe("Chatboxes", function () {
|
|||
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
|
||||
.tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
|
||||
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
|
||||
expect(csntext).toEqual(mock.cur_names[1] + ' is typing');
|
||||
expect(view.model.messages.length).toBe(0);
|
||||
|
||||
|
@ -855,7 +855,7 @@ describe("Chatboxes", function () {
|
|||
}).c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
|
||||
await u.waitUntil(() => !view.el.querySelector('.chat-content__notifications').textContent);
|
||||
await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -881,7 +881,7 @@ describe("Chatboxes", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
|
||||
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
|
||||
expect(csntext).toEqual(mock.cur_names[1] + ' has gone away');
|
||||
done();
|
||||
}));
|
||||
|
@ -899,7 +899,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
// See XEP-0085 https://xmpp.org/extensions/xep-0085.html#definitions
|
||||
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
|
||||
// Original message
|
||||
|
@ -928,7 +928,7 @@ describe("Chatboxes", function () {
|
|||
}).c('composing', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
|
||||
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
|
||||
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
|
||||
expect(csntext).toEqual(mock.cur_names[1] + ' is typing');
|
||||
|
||||
// Edited message
|
||||
|
@ -943,7 +943,7 @@ describe("Chatboxes", function () {
|
|||
.c('replace', {'xmlns': Strophe.NS.MESSAGE_CORRECT, 'id': original_id }).tree();
|
||||
|
||||
await _converse.handleMessageStanza(edited);
|
||||
await u.waitUntil(() => !view.el.querySelector('.chat-content__notifications').textContent);
|
||||
await u.waitUntil(() => !view.querySelector('.chat-content__notifications').textContent);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -970,16 +970,16 @@ describe("Chatboxes", function () {
|
|||
expect(view.model.messages.length === 1).toBeTruthy();
|
||||
let stored_messages = await view.model.messages.browserStorage.findAll();
|
||||
expect(stored_messages.length).toBe(1);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg'));
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg'));
|
||||
|
||||
message = '/clear';
|
||||
spyOn(view, 'clearMessages').and.callThrough();
|
||||
spyOn(window, 'confirm').and.callFake(function () {
|
||||
return true;
|
||||
});
|
||||
view.el.querySelector('.chat-textarea').value = message;
|
||||
view.querySelector('.chat-textarea').value = message;
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
preventDefault: function preventDefault () {},
|
||||
keyCode: 13
|
||||
});
|
||||
|
@ -1158,7 +1158,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current', 1);
|
||||
let msg, indicator_el;
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 500);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const chatbox = _converse.chatboxes.get(sender_jid);
|
||||
chatbox.save('scrolled', true);
|
||||
|
@ -1185,7 +1185,7 @@ describe("Chatboxes", function () {
|
|||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
||||
let indicator_el, msg;
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 500);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const chatbox = _converse.chatboxes.get(sender_jid);
|
||||
var chatboxview = _converse.chatboxviews.get(sender_jid);
|
||||
|
@ -1214,7 +1214,7 @@ describe("Chatboxes", function () {
|
|||
await mock.waitForRoster(_converse, 'current', 1);
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 500);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const chatbox = _converse.chatboxes.get(sender_jid);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
|
@ -1240,7 +1240,7 @@ describe("Chatboxes", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current', 1);
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 500);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const chatbox = _converse.chatboxes.get(sender_jid);
|
||||
const msgFactory = () => mock.createChatMessage(_converse, sender_jid, 'This message will be received as unread, but eventually will be read');
|
||||
|
@ -1264,7 +1264,7 @@ describe("Chatboxes", function () {
|
|||
|
||||
await mock.waitForRoster(_converse, 'current', 1);
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 500);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 500);
|
||||
await mock.openChatBoxFor(_converse, sender_jid);
|
||||
const chatbox = _converse.chatboxes.get(sender_jid);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
|
|
|
@ -45,7 +45,7 @@ describe("The Controlbox", function () {
|
|||
// We need to rebind all events otherwise our spy won't be called
|
||||
controlview.delegateEvents();
|
||||
|
||||
controlview.el.querySelector('.close-chatbox-button').click();
|
||||
controlview.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));
|
||||
|
@ -76,9 +76,9 @@ describe("The Controlbox", function () {
|
|||
ask: 'subscribe',
|
||||
fullname: mock.pend_names[0]
|
||||
});
|
||||
await u.waitUntil(() => _.filter(_converse.rosterview.el.querySelectorAll('.roster-group li'), u.isVisible).length, 700);
|
||||
await u.waitUntil(() => _.filter(_converse.rosterview.querySelectorAll('.roster-group li'), u.isVisible).length, 700);
|
||||
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
||||
expect(_.filter(_converse.rosterview.el.querySelectorAll('li'), u.isVisible).length).toBe(1);
|
||||
expect(_.filter(_converse.rosterview.querySelectorAll('li'), u.isVisible).length).toBe(1);
|
||||
expect(_converse.rosterview.update).toHaveBeenCalled();
|
||||
done();
|
||||
}));
|
||||
|
@ -98,7 +98,7 @@ describe("The Controlbox", function () {
|
|||
chatview.model.set({'minimized': true});
|
||||
|
||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count') === null).toBeTruthy();
|
||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator') === null).toBeTruthy();
|
||||
expect(_converse.rosterview.querySelector('.msgs-indicator') === null).toBeTruthy();
|
||||
|
||||
let msg = $msg({
|
||||
from: sender_jid,
|
||||
|
@ -108,10 +108,10 @@ describe("The Controlbox", function () {
|
|||
}).c('body').t('hello').up()
|
||||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
|
||||
_converse.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll(".msgs-indicator").length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll(".msgs-indicator").length);
|
||||
spyOn(chatview.model, 'handleUnreadMessage').and.callThrough();
|
||||
await u.waitUntil(() => _converse.chatboxviews.el.querySelector('.restore-chat .message-count')?.textContent === '1');
|
||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('1');
|
||||
expect(_converse.rosterview.querySelector('.msgs-indicator').textContent).toBe('1');
|
||||
|
||||
msg = $msg({
|
||||
from: sender_jid,
|
||||
|
@ -123,10 +123,10 @@ describe("The Controlbox", function () {
|
|||
_converse.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => chatview.model.handleUnreadMessage.calls.count());
|
||||
await u.waitUntil(() => _converse.chatboxviews.el.querySelector('.restore-chat .message-count')?.textContent === '2');
|
||||
expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2');
|
||||
expect(_converse.rosterview.querySelector('.msgs-indicator').textContent).toBe('2');
|
||||
chatview.model.set({'minimized': false});
|
||||
expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count')).toBe(null);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelector('.msgs-indicator') === null);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelector('.msgs-indicator') === null);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -140,8 +140,8 @@ describe("The Controlbox", function () {
|
|||
|
||||
mock.openControlBox(_converse);
|
||||
var view = _converse.xmppstatusview;
|
||||
expect(u.hasClass('online', view.el.querySelector('.xmpp-status span:first-child'))).toBe(true);
|
||||
expect(view.el.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
|
||||
expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
|
||||
expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -152,7 +152,7 @@ describe("The Controlbox", function () {
|
|||
|
||||
await mock.openControlBox(_converse);
|
||||
var cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.change-status').click()
|
||||
cbview.querySelector('.change-status').click()
|
||||
const modal = _converse.api.modal.get('modal-status-change');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
const view = _converse.xmppstatusview;
|
||||
|
@ -166,10 +166,10 @@ describe("The Controlbox", function () {
|
|||
`<priority>0</priority>`+
|
||||
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||
`</presence>`);
|
||||
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
||||
const first_child = view.querySelector('.xmpp-status span:first-child');
|
||||
expect(u.hasClass('online', first_child)).toBe(false);
|
||||
expect(u.hasClass('dnd', first_child)).toBe(true);
|
||||
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
|
||||
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -180,7 +180,7 @@ describe("The Controlbox", function () {
|
|||
|
||||
await mock.openControlBox(_converse);
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.change-status').click()
|
||||
cbview.querySelector('.change-status').click()
|
||||
const modal = _converse.api.modal.get('modal-status-change');
|
||||
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -197,9 +197,9 @@ describe("The Controlbox", function () {
|
|||
`<c hash="sha-1" node="https://conversejs.org" ver="PxXfr6uz8ClMWIga0OB/MhKNH/M=" xmlns="http://jabber.org/protocol/caps"/>`+
|
||||
`</presence>`);
|
||||
|
||||
const first_child = view.el.querySelector('.xmpp-status span:first-child');
|
||||
const first_child = view.querySelector('.xmpp-status span:first-child');
|
||||
expect(u.hasClass('online', first_child)).toBe(true);
|
||||
expect(view.el.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
|
||||
expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -216,7 +216,7 @@ describe("The 'Add Contact' widget", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
cbview.querySelector('.add-contact').click()
|
||||
const modal = _converse.api.modal.get('add-contact-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
expect(modal.el.querySelector('form.add-xmpp-contact')).not.toBe(null);
|
||||
|
@ -249,7 +249,7 @@ describe("The 'Add Contact' widget", function () {
|
|||
await mock.waitForRoster(_converse, 'all', 0);
|
||||
mock.openControlBox(_converse);
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
cbview.querySelector('.add-contact').click()
|
||||
const modal = _converse.api.modal.get('add-contact-modal');
|
||||
expect(modal.jid_auto_complete).toBe(undefined);
|
||||
expect(modal.name_auto_complete).toBe(undefined);
|
||||
|
@ -296,7 +296,7 @@ describe("The 'Add Contact' widget", function () {
|
|||
XMLHttpRequest.and.callFake(() => xhr);
|
||||
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
cbview.querySelector('.add-contact').click()
|
||||
const modal = _converse.api.modal.get('add-contact-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
||||
|
@ -366,7 +366,7 @@ describe("The 'Add Contact' widget", function () {
|
|||
XMLHttpRequest.and.callFake(() => xhr);
|
||||
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
cbview.querySelector('.add-contact').click()
|
||||
modal = _converse.api.modal.get('add-contact-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ describe("Converse", function() {
|
|||
expect(chat.get('box_id')).toBe(`box-${jid}`);
|
||||
|
||||
const view = _converse.chatboxviews.get(jid);
|
||||
await u.waitUntil(() => u.isVisible(view.el));
|
||||
await u.waitUntil(() => u.isVisible(view));
|
||||
// Test for multiple JIDs
|
||||
mock.openChatBoxFor(_converse, jid2);
|
||||
await u.waitUntil(() => _converse.chatboxes.length == 3);
|
||||
|
@ -325,7 +325,7 @@ describe("Converse", function() {
|
|||
['close', 'endOTR', 'focus', 'get', 'initiateOTR', 'is_chatroom', 'maximize', 'minimize', 'open', 'set']
|
||||
);
|
||||
const view = _converse.chatboxviews.get(jid);
|
||||
await u.waitUntil(() => u.isVisible(view.el));
|
||||
await u.waitUntil(() => u.isVisible(view));
|
||||
// Test for multiple JIDs
|
||||
const list = await _converse.api.chats.open([jid, jid2]);
|
||||
expect(Array.isArray(list)).toBeTruthy();
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("A Chat Message", function () {
|
|||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid)
|
||||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
expect(textarea.value).toBe('');
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -30,8 +30,8 @@ describe("A Chat Message", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
||||
|
@ -42,8 +42,8 @@ describe("A Chat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
textarea.value = 'But soft, what light through yonder window breaks?';
|
||||
|
@ -76,8 +76,8 @@ describe("A Chat Message", function () {
|
|||
expect(keys.length).toBe(1);
|
||||
expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.querySelector('.chat-msg')) === false), 500);
|
||||
|
||||
// Test that pressing the down arrow cancels message correction
|
||||
await u.waitUntil(() => textarea.value === '')
|
||||
|
@ -87,8 +87,8 @@ describe("A Chat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -96,8 +96,8 @@ describe("A Chat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.querySelector('.chat-msg')) === false), 500);
|
||||
|
||||
textarea.value = 'It is the east, and Juliet is the one.';
|
||||
view.onKeyDown({
|
||||
|
@ -106,7 +106,7 @@ describe("A Chat Message", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
|
||||
textarea.value = 'Arise, fair sun, and kill the envious moon';
|
||||
view.onKeyDown({
|
||||
|
@ -115,7 +115,7 @@ describe("A Chat Message", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -147,7 +147,7 @@ describe("A Chat Message", function () {
|
|||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => textarea.value === '');
|
||||
const messages = view.el.querySelectorAll('.chat-msg');
|
||||
const messages = view.querySelectorAll('.chat-msg');
|
||||
expect(messages.length).toBe(3);
|
||||
expect(messages[0].querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder window breaks?');
|
||||
|
@ -173,7 +173,7 @@ describe("A Chat Message", function () {
|
|||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
view.onKeyDown({
|
||||
|
@ -183,14 +183,14 @@ describe("A Chat Message", function () {
|
|||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
expect(textarea.value).toBe('');
|
||||
|
||||
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .chat-msg__action').length === 2);
|
||||
let action = view.el.querySelector('.chat-msg .chat-msg__action');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg .chat-msg__action').length === 2);
|
||||
let action = view.querySelector('.chat-msg .chat-msg__action');
|
||||
expect(action.textContent.trim()).toBe('Edit');
|
||||
|
||||
action.style.opacity = 1;
|
||||
|
@ -198,8 +198,8 @@ describe("A Chat Message", function () {
|
|||
|
||||
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')));
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
textarea.value = 'But soft, what light through yonder window breaks?';
|
||||
|
@ -231,26 +231,26 @@ describe("A Chat Message", function () {
|
|||
expect(keys.length).toBe(1);
|
||||
expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')) === false);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
|
||||
// Test that clicking the pencil icon a second time cancels editing.
|
||||
action = view.el.querySelector('.chat-msg .chat-msg__action');
|
||||
action = view.querySelector('.chat-msg .chat-msg__action');
|
||||
action.style.opacity = 1;
|
||||
action.click();
|
||||
|
||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === true);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')) === true);
|
||||
|
||||
action = view.el.querySelector('.chat-msg .chat-msg__action');
|
||||
action = view.querySelector('.chat-msg .chat-msg__action');
|
||||
action.style.opacity = 1;
|
||||
action.click();
|
||||
expect(textarea.value).toBe('');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => (u.hasClass('correcting', view.querySelector('.chat-msg')) === false), 500);
|
||||
|
||||
// Test that messages from other users don't have the pencil icon
|
||||
_converse.handleMessageStanza(
|
||||
|
@ -263,12 +263,12 @@ describe("A Chat Message", function () {
|
|||
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()
|
||||
);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(2);
|
||||
expect(view.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(2);
|
||||
|
||||
// Test confirmation dialog
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
action = view.el.querySelector('.chat-msg .chat-msg__action');
|
||||
action = view.querySelector('.chat-msg .chat-msg__action');
|
||||
action.style.opacity = 1;
|
||||
action.click();
|
||||
expect(window.confirm).toHaveBeenCalledWith(
|
||||
|
@ -307,8 +307,8 @@ describe("A Chat Message", function () {
|
|||
'id': msg_id,
|
||||
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
_converse.handleMessageStanza($msg({
|
||||
|
@ -320,10 +320,10 @@ describe("A Chat Message", function () {
|
|||
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder chimney breaks?');
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
expect(view.model.messages.models.length).toBe(1);
|
||||
|
||||
_converse.handleMessageStanza($msg({
|
||||
|
@ -335,11 +335,11 @@ describe("A Chat Message", function () {
|
|||
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder window breaks?');
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
view.el.querySelector('.chat-msg__content .fa-edit').click();
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
view.querySelector('.chat-msg__content .fa-edit').click();
|
||||
|
||||
const modal = _converse.api.modal.get('message-versions-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -382,9 +382,9 @@ describe("A Groupchat Message", function () {
|
|||
'id': msg_id,
|
||||
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
await view.model.handleMessageStanza($msg({
|
||||
|
@ -394,10 +394,10 @@ describe("A Groupchat Message", function () {
|
|||
'id': u.getUniqueId(),
|
||||
}).c('body').t('But soft, what light through yonder chimney breaks?').up()
|
||||
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||
'But soft, what light through yonder chimney breaks?', 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__content .fa-edit'));
|
||||
|
||||
await view.model.handleMessageStanza($msg({
|
||||
'from': 'lounge@montague.lit/newguy',
|
||||
|
@ -407,11 +407,11 @@ describe("A Groupchat Message", function () {
|
|||
}).c('body').t('But soft, what light through yonder window breaks?').up()
|
||||
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||
'But soft, what light through yonder window breaks?', 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
const edit = await u.waitUntil(() => view.querySelector('.chat-msg__content .fa-edit'));
|
||||
edit.click();
|
||||
const modal = _converse.api.modal.get('message-versions-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -461,11 +461,11 @@ describe("A Groupchat Message", function () {
|
|||
'id': msg_id,
|
||||
}).c('body').t('But soft, what light through yonder airlock breaks?').tree());
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(view.el.querySelectorAll('.chat-msg__text')[0].textContent)
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(view.querySelectorAll('.chat-msg__text')[0].textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
expect(view.el.querySelectorAll('.chat-msg__text')[1].textContent)
|
||||
expect(view.querySelectorAll('.chat-msg__text')[1].textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
// First message correction
|
||||
|
@ -477,10 +477,10 @@ describe("A Groupchat Message", function () {
|
|||
}).c('body').t('But soft, what light through yonder chimney breaks?').up()
|
||||
.c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||
'But soft, what light through yonder chimney breaks?', 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__content .fa-edit'));
|
||||
|
||||
// Second message correction
|
||||
await view.model.handleMessageStanza($msg({
|
||||
|
@ -499,15 +499,15 @@ describe("A Groupchat Message", function () {
|
|||
'id': u.getUniqueId(),
|
||||
}).c('body').t('But soft, what light through yonder window breaks?').tree());
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[0].textContent ===
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text')[0].textContent ===
|
||||
'But soft, what light through yonder window breaks?', 500);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 3);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[2].textContent ===
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text')[2].textContent ===
|
||||
'But soft, what light through yonder window breaks?', 500);
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
expect(view.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
|
||||
const edit = await u.waitUntil(() => view.querySelector('.chat-msg__content .fa-edit'));
|
||||
edit.click();
|
||||
const modal = _converse.api.modal.get('message-versions-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -528,7 +528,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
expect(textarea.value).toBe('');
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -542,8 +542,8 @@ describe("A Groupchat Message", function () {
|
|||
preventDefault: function preventDefault () {},
|
||||
keyCode: 13 // Enter
|
||||
});
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent)
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.querySelector('.chat-msg__text').textContent)
|
||||
.toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
|
||||
|
@ -554,8 +554,8 @@ describe("A Groupchat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')));
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
textarea.value = 'But soft, what light through yonder window breaks?';
|
||||
|
@ -588,8 +588,8 @@ describe("A Groupchat Message", function () {
|
|||
expect(keys.length).toBe(1);
|
||||
expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(u.hasClass('correcting', view.querySelector('.chat-msg'))).toBe(false);
|
||||
|
||||
// Check that messages from other users are skipped
|
||||
await view.model.handleMessageStanza($msg({
|
||||
|
@ -599,7 +599,7 @@ describe("A Groupchat Message", function () {
|
|||
'type': 'groupchat'
|
||||
}).c('body').t('Hello world').tree());
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
|
||||
// Test that pressing the down arrow cancels message correction
|
||||
expect(textarea.value).toBe('');
|
||||
|
@ -609,8 +609,8 @@ describe("A Groupchat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||
expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -618,8 +618,8 @@ describe("A Groupchat Message", function () {
|
|||
});
|
||||
expect(textarea.value).toBe('');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => !u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
await u.waitUntil(() => !u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -21,12 +21,12 @@ describe("Emojis", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const toolbar = await u.waitUntil(() => view.el.querySelector('converse-chat-toolbar'));
|
||||
const toolbar = await u.waitUntil(() => view.querySelector('converse-chat-toolbar'));
|
||||
toolbar.querySelector('.toggle-emojis').click();
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')), 1000);
|
||||
const item = view.el.querySelector('.emoji-picker li.insert-emoji a');
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')), 1000);
|
||||
const item = view.querySelector('.emoji-picker li.insert-emoji a');
|
||||
item.click()
|
||||
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||
expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||
toolbar.querySelector('.toggle-emojis').click(); // Close the panel again
|
||||
done();
|
||||
}));
|
||||
|
@ -39,8 +39,8 @@ describe("Emojis", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
await u.waitUntil(() => view.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = ':gri';
|
||||
|
||||
// Press tab
|
||||
|
@ -52,14 +52,14 @@ describe("Emojis", function () {
|
|||
'key': 'Tab'
|
||||
}
|
||||
view.onKeyDown(tab_event);
|
||||
await u.waitUntil(() => view.el.querySelector('converse-emoji-picker .emoji-search').value === ':gri');
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view.el).length === 3, 1000);
|
||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', view.el);
|
||||
await u.waitUntil(() => view.querySelector('converse-emoji-picker .emoji-search').value === ':gri');
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view).length === 3, 1000);
|
||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji', view);
|
||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':grimacing:');
|
||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':grin:');
|
||||
expect(visible_emojis[2].getAttribute('data-emoji')).toBe(':grinning:');
|
||||
|
||||
const picker = view.el.querySelector('converse-emoji-picker');
|
||||
const picker = view.querySelector('converse-emoji-picker');
|
||||
const input = picker.querySelector('.emoji-search');
|
||||
// Test that TAB autocompletes the to first match
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||
|
@ -92,7 +92,7 @@ describe("Emojis", function () {
|
|||
|
||||
textarea.value = ':use';
|
||||
view.onKeyDown(tab_event);
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => input.value === ':use');
|
||||
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
|
||||
expect(visible_emojis.length).toBe(0);
|
||||
|
@ -107,8 +107,8 @@ describe("Emojis", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
await u.waitUntil(() => view.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = ':';
|
||||
// Press tab
|
||||
const tab_event = {
|
||||
|
@ -119,9 +119,9 @@ describe("Emojis", function () {
|
|||
'key': 'Tab'
|
||||
}
|
||||
view.onKeyDown(tab_event);
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||
|
||||
const picker = view.el.querySelector('converse-emoji-picker');
|
||||
const picker = view.querySelector('converse-emoji-picker');
|
||||
const input = picker.querySelector('.emoji-search');
|
||||
expect(input.value).toBe(':');
|
||||
input.value = ':gri';
|
||||
|
@ -131,8 +131,8 @@ describe("Emojis", function () {
|
|||
'stopPropagation': function stopPropagation () {}
|
||||
};
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view.el).length === 3, 1000);
|
||||
let emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view.el).pop();
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view).length === 3, 1000);
|
||||
let emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop();
|
||||
emoji.click();
|
||||
await u.waitUntil(() => textarea.value === ':grinning: ');
|
||||
textarea.value = ':grinning: :';
|
||||
|
@ -141,8 +141,8 @@ describe("Emojis", function () {
|
|||
await u.waitUntil(() => input.value === ':');
|
||||
input.value = ':grimacing';
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view.el).length === 1, 1000);
|
||||
emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view.el).pop();
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji', view).length === 1, 1000);
|
||||
emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop();
|
||||
emoji.click();
|
||||
await u.waitUntil(() => textarea.value === ':grinning: :grimacing: ');
|
||||
done();
|
||||
|
@ -157,8 +157,8 @@ describe("Emojis", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
await u.waitUntil(() => view.querySelector('converse-emoji-dropdown'));
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = ':gri';
|
||||
|
||||
// Press tab
|
||||
|
@ -171,8 +171,8 @@ describe("Emojis", function () {
|
|||
}
|
||||
textarea.value = ':';
|
||||
view.onKeyDown(tab_event);
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||
const picker = view.el.querySelector('converse-emoji-picker');
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||
const picker = view.querySelector('converse-emoji-picker');
|
||||
const input = picker.querySelector('.emoji-search');
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||
await u.waitUntil(() => input.value === ':100:');
|
||||
|
@ -182,12 +182,12 @@ describe("Emojis", function () {
|
|||
|
||||
textarea.value = ':';
|
||||
view.onKeyDown(tab_event);
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => input.value === ':');
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||
await u.waitUntil(() => input.value === ':100:');
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view.el).length === 1, 1000);
|
||||
const emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view.el).pop();
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view).length === 1, 1000);
|
||||
const emoji = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden) a', view).pop();
|
||||
emoji.click();
|
||||
expect(textarea.value).toBe(':100: ');
|
||||
done();
|
||||
|
@ -202,13 +202,13 @@ describe("Emojis", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('converse-emoji-dropdown'));
|
||||
const toolbar = view.el.querySelector('converse-chat-toolbar');
|
||||
await u.waitUntil(() => view.querySelector('converse-emoji-dropdown'));
|
||||
const toolbar = view.querySelector('converse-chat-toolbar');
|
||||
toolbar.querySelector('.toggle-emojis').click();
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => sizzle('converse-chat-toolbar .insert-emoji:not(.hidden)', view.el).length === 1589);
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.emoji-picker__lists')));
|
||||
await u.waitUntil(() => sizzle('converse-chat-toolbar .insert-emoji:not(.hidden)', view).length === 1589);
|
||||
|
||||
const input = view.el.querySelector('.emoji-search');
|
||||
const input = view.querySelector('.emoji-search');
|
||||
input.value = 'smiley';
|
||||
const event = {
|
||||
'target': input,
|
||||
|
@ -217,8 +217,8 @@ describe("Emojis", function () {
|
|||
};
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view.el).length === 2, 1000);
|
||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view.el);
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view).length === 2, 1000);
|
||||
let visible_emojis = sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view);
|
||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||
expect(visible_emojis[1].getAttribute('data-emoji')).toBe(':smiley_cat:');
|
||||
|
||||
|
@ -230,25 +230,25 @@ describe("Emojis", function () {
|
|||
// Check that search results update when chars are deleted
|
||||
input.value = 'sm';
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view.el).length === 25, 1000);
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view).length === 25, 1000);
|
||||
|
||||
input.value = 'smiley';
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', event));
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view.el).length === 2, 1000);
|
||||
await u.waitUntil(() => sizzle('.emojis-lists__container--search .insert-emoji:not(.hidden)', view).length === 2, 1000);
|
||||
|
||||
// Test that TAB autocompletes the to first match
|
||||
const tab_event = Object.assign({}, event, {'keyCode': 9, 'key': 'Tab'});
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', tab_event));
|
||||
|
||||
await u.waitUntil(() => input.value === ':smiley:');
|
||||
await u.waitUntil(() => sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", view.el).length === 1, 1000);
|
||||
visible_emojis = sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", view.el);
|
||||
await u.waitUntil(() => sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", view).length === 1, 1000);
|
||||
visible_emojis = sizzle(".emojis-lists__container--search .insert-emoji:not('.hidden')", view);
|
||||
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
|
||||
|
||||
// Check that ENTER now inserts the match
|
||||
input.dispatchEvent(new KeyboardEvent('keydown', enter_event));
|
||||
await u.waitUntil(() => input.value === '');
|
||||
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||
expect(view.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -288,7 +288,7 @@ describe("Emojis", function () {
|
|||
|
||||
// Test that a modified message that no longer contains only
|
||||
// emojis now renders normally again.
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = ':poop: :innocent:';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -296,7 +296,7 @@ describe("Emojis", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
const last_msg_sel = 'converse-chat-message:last-child .chat-msg__text';
|
||||
await u.waitUntil(() => view.content.querySelector(last_msg_sel).textContent === '💩 😇');
|
||||
|
||||
|
@ -308,7 +308,7 @@ describe("Emojis", function () {
|
|||
expect(textarea.value).toBe('💩 😇');
|
||||
expect(view.model.messages.at(2).get('correcting')).toBe(true);
|
||||
sel = 'converse-chat-message:last-child .chat-msg'
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector(sel)), 500);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector(sel)), 500);
|
||||
textarea.value = textarea.value += 'This is no longer an emoji-only message';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -368,7 +368,7 @@ describe("Emojis", function () {
|
|||
expect(imgs.length).toBe(1);
|
||||
expect(imgs[0].src).toBe(_converse.api.settings.get('emoji_image_path')+'/72x72/1f607.png');
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = ':poop: :innocent:';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -411,15 +411,15 @@ describe("Emojis", function () {
|
|||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
|
||||
const toolbar = await u.waitUntil(() => view.el.querySelector('.chat-toolbar'));
|
||||
const toolbar = await u.waitUntil(() => view.querySelector('.chat-toolbar'));
|
||||
toolbar.querySelector('.toggle-emojis').click();
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')), 1000);
|
||||
const picker = await u.waitUntil(() => view.el.querySelector('converse-emoji-picker'), 1000);
|
||||
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(
|
||||
'<img class="emoji" draggable="false" title=":xmpp:" alt=":xmpp:" src="/dist/images/custom_emojis/xmpp.png">');
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'Running tests for :converse:';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -427,7 +427,7 @@ describe("Emojis", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
const body = view.el.querySelector('converse-chat-message-body');
|
||||
const body = view.querySelector('converse-chat-message-body');
|
||||
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();
|
||||
|
|
10
spec/hats.js
10
spec/hats.js
|
@ -25,7 +25,7 @@ describe("A XEP-0317 MUC Hat", function () {
|
|||
</hats>
|
||||
</presence>
|
||||
`)));
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.trim() ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent.trim() ===
|
||||
"romeo and Terry have entered the groupchat");
|
||||
|
||||
let hats = view.model.getOccupant("Terry").get('hats');
|
||||
|
@ -38,7 +38,7 @@ describe("A XEP-0317 MUC Hat", function () {
|
|||
</message>
|
||||
`)));
|
||||
|
||||
const msg_el = await u.waitUntil(() => view.el.querySelector('.chat-msg'));
|
||||
const msg_el = await u.waitUntil(() => view.querySelector('.chat-msg'));
|
||||
let badges = Array.from(msg_el.querySelectorAll('.badge'));
|
||||
expect(badges.length).toBe(2);
|
||||
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage");
|
||||
|
@ -60,8 +60,8 @@ describe("A XEP-0317 MUC Hat", function () {
|
|||
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 3);
|
||||
hats = view.model.getOccupant("Terry").get('hats');
|
||||
expect(hats.map(h => h.title).join(' ')).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 3, 1000);
|
||||
badges = Array.from(view.el.querySelectorAll('.chat-msg .badge'));
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg .badge').length === 3, 1000);
|
||||
badges = Array.from(view.querySelectorAll('.chat-msg .badge'));
|
||||
expect(badges.map(b => b.textContent.trim()).join(' ' )).toBe("Teacher's Assistant Dark Mage Mad hatter");
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(u.toStanza(`
|
||||
|
@ -72,7 +72,7 @@ describe("A XEP-0317 MUC Hat", function () {
|
|||
</presence>
|
||||
`)));
|
||||
await u.waitUntil(() => view.model.getOccupant("Terry").get('hats').length === 0);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .badge').length === 0);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg .badge').length === 0);
|
||||
done();
|
||||
}));
|
||||
})
|
||||
|
|
|
@ -62,7 +62,7 @@ describe("A headlines box", function () {
|
|||
await u.waitUntil(() => _converse.chatboxviews.keys().includes('notify.example.com'));
|
||||
const view = _converse.chatboxviews.get('notify.example.com');
|
||||
expect(view.model.get('show_avatar')).toBeFalsy();
|
||||
expect(view.el.querySelector('img.avatar')).toBe(null);
|
||||
expect(view.querySelector('img.avatar')).toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -96,9 +96,9 @@ describe("A headlines box", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
const view = _converse.chatboxviews.get('controlbox');
|
||||
await u.waitUntil(() => view.el.querySelectorAll(".open-headline").length);
|
||||
expect(view.el.querySelectorAll('.open-headline').length).toBe(1);
|
||||
expect(view.el.querySelector('.open-headline').text).toBe('notify.example.com');
|
||||
await u.waitUntil(() => view.querySelectorAll(".open-headline").length);
|
||||
expect(view.querySelectorAll('.open-headline').length).toBe(1);
|
||||
expect(view.querySelector('.open-headline').text).toBe('notify.example.com');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -133,13 +133,13 @@ describe("A headlines box", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length);
|
||||
await u.waitUntil(() => cbview.querySelectorAll(".open-headline").length);
|
||||
const hlview = _converse.chatboxviews.get('notify.example.com');
|
||||
await u.isVisible(hlview.el);
|
||||
const close_el = await u.waitUntil(() => hlview.el.querySelector('.close-chatbox-button'));
|
||||
await u.isVisible(hlview);
|
||||
const close_el = await u.waitUntil(() => hlview.querySelector('.close-chatbox-button'));
|
||||
close_el.click();
|
||||
await u.waitUntil(() => cbview.el.querySelectorAll(".open-headline").length === 0);
|
||||
expect(cbview.el.querySelectorAll('.open-headline').length).toBe(0);
|
||||
await u.waitUntil(() => cbview.querySelectorAll(".open-headline").length === 0);
|
||||
expect(cbview.querySelectorAll('.open-headline').length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
|
||||
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items');
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
expect(view.el.querySelector('.chat-toolbar .fileupload')).toBe(null);
|
||||
expect(view.querySelector('.chat-toolbar .fileupload')).toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -174,7 +174,7 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
|
||||
await mock.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], [], 'items');
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-toolbar .fileupload') === null);
|
||||
await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload') === null);
|
||||
expect(1).toBe(1);
|
||||
done();
|
||||
}));
|
||||
|
@ -198,7 +198,7 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const el = await u.waitUntil(() => view.el.querySelector('.chat-toolbar .fileupload'));
|
||||
const el = await u.waitUntil(() => view.querySelector('.chat-toolbar .fileupload'));
|
||||
expect(el).not.toEqual(null);
|
||||
done();
|
||||
}));
|
||||
|
@ -217,7 +217,7 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||
await u.waitUntil(() => _converse.chatboxviews.get('lounge@montague.lit').el.querySelector('.fileupload'));
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
expect(view.el.querySelector('.chat-toolbar .fileupload')).not.toBe(null);
|
||||
expect(view.querySelector('.chat-toolbar .fileupload')).not.toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -283,12 +283,12 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
expect(view.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
u.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
.then(() => {
|
||||
message.set('progress', 1);
|
||||
u.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '1')
|
||||
u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '1')
|
||||
}).then(() => {
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
|
@ -317,13 +317,13 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
`</x>`+
|
||||
`<origin-id id="${sent_stanza.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||
`</message>`);
|
||||
const img_link_el = await u.waitUntil(() => view.el.querySelector('converse-chat-message-body .chat-image__link'), 1000);
|
||||
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(
|
||||
`<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.el.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;
|
||||
|
@ -391,12 +391,12 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(function () {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
expect(view.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
u.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '0.5')
|
||||
.then(() => {
|
||||
message.set('progress', 1);
|
||||
u.waitUntil(() => view.el.querySelector('.chat-content progress')?.getAttribute('value') === '1')
|
||||
u.waitUntil(() => view.querySelector('.chat-content progress')?.getAttribute('value') === '1')
|
||||
}).then(() => {
|
||||
message.save({
|
||||
'upload': _converse.SUCCESS,
|
||||
|
@ -425,13 +425,13 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
`</x>`+
|
||||
`<origin-id id="${sent_stanza.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||
`</message>`);
|
||||
const img_link_el = await u.waitUntil(() => view.el.querySelector('converse-chat-message-body .chat-image__link'), 1000);
|
||||
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(
|
||||
`<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.el.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>`);
|
||||
|
||||
|
@ -548,8 +548,8 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
'name': "my-juliet.jpg"
|
||||
};
|
||||
view.model.sendFiles([file]);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.message').length)
|
||||
const messages = view.el.querySelectorAll('.message.chat-error');
|
||||
await u.waitUntil(() => view.querySelectorAll('.message').length)
|
||||
const messages = view.querySelectorAll('.message.chat-error');
|
||||
expect(messages.length).toBe(1);
|
||||
expect(messages[0].textContent.trim()).toBe(
|
||||
'The size of your file, my-juliet.jpg, exceeds the maximum allowed by your server, which is 5 MB.');
|
||||
|
@ -618,12 +618,12 @@ describe("XEP-0363: HTTP File Upload", function () {
|
|||
|
||||
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(async () => {
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.el.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
expect(view.querySelector('.chat-content progress').getAttribute('value')).toBe('0');
|
||||
message.set('progress', 0.5);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '0.5');
|
||||
await u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '0.5');
|
||||
message.set('progress', 1);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-content progress').getAttribute('value') === '1');
|
||||
expect(view.el.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
|
||||
await u.waitUntil(() => view.querySelector('.chat-content progress').getAttribute('value') === '1');
|
||||
expect(view.querySelector('.chat-content .chat-msg__text').textContent).toBe('Uploading file: my-juliet.jpg, 22.91 KB');
|
||||
done();
|
||||
});
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
|
|
@ -13,25 +13,25 @@ describe("The Login Form", function () {
|
|||
|
||||
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
|
||||
mock.toggleControlBox();
|
||||
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
|
||||
const checkboxes = cbview.querySelectorAll('input[type="checkbox"]');
|
||||
expect(checkboxes.length).toBe(1);
|
||||
|
||||
const checkbox = checkboxes[0];
|
||||
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||
const label = cbview.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||
expect(label.textContent).toBe('This is a trusted device');
|
||||
expect(checkbox.checked).toBe(true);
|
||||
|
||||
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
||||
cbview.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||
cbview.querySelector('input[name="password"]').value = 'secret';
|
||||
|
||||
expect(_converse.config.get('trusted')).toBe(true);
|
||||
expect(_converse.getDefaultStore()).toBe('persistent');
|
||||
cbview.el.querySelector('input[type="submit"]').click();
|
||||
cbview.querySelector('input[type="submit"]').click();
|
||||
expect(_converse.config.get('trusted')).toBe(true);
|
||||
expect(_converse.getDefaultStore()).toBe('persistent');
|
||||
|
||||
checkbox.click();
|
||||
cbview.el.querySelector('input[type="submit"]').click();
|
||||
cbview.querySelector('input[type="submit"]').click();
|
||||
expect(_converse.config.get('trusted')).toBe(false);
|
||||
expect(_converse.getDefaultStore()).toBe('session');
|
||||
done();
|
||||
|
@ -48,23 +48,23 @@ describe("The Login Form", function () {
|
|||
await u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
mock.toggleControlBox();
|
||||
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
|
||||
const checkboxes = cbview.querySelectorAll('input[type="checkbox"]');
|
||||
expect(checkboxes.length).toBe(1);
|
||||
|
||||
const checkbox = checkboxes[0];
|
||||
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||
const label = cbview.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
|
||||
expect(label.textContent).toBe('This is a trusted device');
|
||||
expect(checkbox.checked).toBe(false);
|
||||
|
||||
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||
cbview.el.querySelector('input[name="password"]').value = 'secret';
|
||||
cbview.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
|
||||
cbview.querySelector('input[name="password"]').value = 'secret';
|
||||
|
||||
cbview.el.querySelector('input[type="submit"]').click();
|
||||
cbview.querySelector('input[type="submit"]').click();
|
||||
expect(_converse.config.get('trusted')).toBe(false);
|
||||
expect(_converse.getDefaultStore()).toBe('session');
|
||||
|
||||
checkbox.click();
|
||||
cbview.el.querySelector('input[type="submit"]').click();
|
||||
cbview.querySelector('input[type="submit"]').click();
|
||||
expect(_converse.config.get('trusted')).toBe(true);
|
||||
expect(_converse.getDefaultStore()).toBe('persistent');
|
||||
done();
|
||||
|
|
|
@ -1175,7 +1175,7 @@ describe("Chatboxes", function () {
|
|||
expect(view.model.messages.at(0).get('type')).toBe('error');
|
||||
expect(view.model.messages.at(0).get('message')).toBe('Timeout while trying to fetch archived messages.');
|
||||
|
||||
let err_message = await u.waitUntil(() => view.el.querySelector('.message.chat-error'));
|
||||
let err_message = await u.waitUntil(() => view.querySelector('.message.chat-error'));
|
||||
err_message.querySelector('.retry').click();
|
||||
|
||||
while (_converse.connection.IQ_stanzas.length) {
|
||||
|
@ -1226,7 +1226,7 @@ describe("Chatboxes", function () {
|
|||
.c('count').t('2');
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.model.messages.length === 2, 500);
|
||||
err_message = view.el.querySelector('.message.chat-error');
|
||||
err_message = view.querySelector('.message.chat-error');
|
||||
expect(err_message).toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -98,7 +98,7 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
stanza = u.toStanza(
|
||||
|
@ -116,7 +116,7 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => _converse.api.trigger.calls.count(), 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
done();
|
||||
}));
|
||||
|
@ -131,7 +131,7 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -139,8 +139,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg__body').textContent.trim())
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg .chat-msg__body').textContent.trim())
|
||||
.toBe("But soft, what light through yonder airlock breaks?");
|
||||
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
|
@ -150,8 +150,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
<received xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
|
||||
stanza = u.toStanza(`
|
||||
<message xml:lang="en" to="romeo@montague.lit/orchard"
|
||||
|
@ -159,8 +159,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
<displayed xmlns="urn:xmpp:chat-markers:0" id="${msg_obj.get('msgid')}"/>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
|
||||
stanza = u.toStanza(`
|
||||
<message xml:lang="en" to="romeo@montague.lit/orchard"
|
||||
|
@ -169,8 +169,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
|
||||
stanza = u.toStanza(`
|
||||
<message xml:lang="en" to="romeo@montague.lit/orchard"
|
||||
|
@ -179,8 +179,8 @@ describe("A XEP-0333 Chat Marker", function () {
|
|||
<markable xmlns="urn:xmpp:chat-markers:0"/>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ describe("A Groupchat Message", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
if (!view.el.querySelectorAll('.chat-area').length) {
|
||||
if (!view.querySelectorAll('.chat-area').length) {
|
||||
view.renderChatArea();
|
||||
}
|
||||
let message = '/me is tired';
|
||||
|
@ -27,8 +27,8 @@ describe("A Groupchat Message", function () {
|
|||
}).c('body').t(message).tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => sizzle('.chat-msg:last .chat-msg__text', view.content).pop());
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.includes('**Dyon van de Wege')).toBeTruthy();
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent.trim()).toBe('is tired');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.includes('**Dyon van de Wege')).toBeTruthy();
|
||||
expect(view.querySelector('.chat-msg__text').textContent.trim()).toBe('is tired');
|
||||
|
||||
message = '/me is as well';
|
||||
msg = $msg({
|
||||
|
@ -38,9 +38,9 @@ describe("A Groupchat Message", function () {
|
|||
type: 'groupchat'
|
||||
}).c('body').t(message).tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(sizzle('.chat-msg__author:last', view.el).pop().textContent.includes('**Romeo Montague')).toBeTruthy();
|
||||
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent.trim()).toBe('is as well');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(sizzle('.chat-msg__author:last', view).pop().textContent.includes('**Romeo Montague')).toBeTruthy();
|
||||
expect(sizzle('.chat-msg__text:last', view).pop().textContent.trim()).toBe('is as well');
|
||||
|
||||
// Check rendering of a mention inside a me message
|
||||
const msg_text = "/me mentions romeo";
|
||||
|
@ -52,8 +52,8 @@ describe("A Groupchat Message", function () {
|
|||
}).c('body').t(msg_text).up()
|
||||
.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.el.querySelectorAll('.chat-msg__text').length === 3);
|
||||
await u.waitUntil(() => sizzle('.chat-msg__text:last', view.el).pop().innerHTML.replace(/<!---->/g, '') ===
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 3);
|
||||
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();
|
||||
}));
|
||||
|
@ -79,16 +79,16 @@ describe("A Message", function () {
|
|||
|
||||
await _converse.handleMessageStanza(msg);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(1);
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.includes('**Mercutio')).toBeTruthy();
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent).toBe('is tired');
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(view.querySelectorAll('.chat-msg--action').length).toBe(1);
|
||||
expect(view.querySelector('.chat-msg__author').textContent.includes('**Mercutio')).toBeTruthy();
|
||||
expect(view.querySelector('.chat-msg__text').textContent).toBe('is tired');
|
||||
|
||||
message = '/me is as well';
|
||||
await mock.sendMessage(view, message);
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(2);
|
||||
await u.waitUntil(() => sizzle('.chat-msg__author:last', view.el).pop().textContent.trim() === '**Romeo Montague');
|
||||
const last_el = sizzle('.chat-msg__text:last', view.el).pop();
|
||||
expect(view.querySelectorAll('.chat-msg--action').length).toBe(2);
|
||||
await u.waitUntil(() => sizzle('.chat-msg__author:last', view).pop().textContent.trim() === '**Romeo Montague');
|
||||
const last_el = sizzle('.chat-msg__text:last', view).pop();
|
||||
await u.waitUntil(() => last_el.textContent === 'is as well');
|
||||
expect(u.hasClass('chat-msg--followup', last_el)).toBe(false);
|
||||
|
||||
|
@ -97,18 +97,18 @@ describe("A Message", function () {
|
|||
message = 'This a normal message';
|
||||
await mock.sendMessage(view, message);
|
||||
const msg_txt_sel = 'converse-chat-message:last-child .chat-msg__text';
|
||||
await u.waitUntil(() => view.el.querySelector(msg_txt_sel).textContent.trim() === message);
|
||||
let el = view.el.querySelector('converse-chat-message:last-child .chat-msg__body');
|
||||
await u.waitUntil(() => view.querySelector(msg_txt_sel).textContent.trim() === message);
|
||||
let el = view.querySelector('converse-chat-message:last-child .chat-msg__body');
|
||||
expect(u.hasClass('chat-msg--followup', el)).toBeFalsy();
|
||||
|
||||
message = '/me wrote a 3rd person message';
|
||||
await mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelector(msg_txt_sel).textContent.trim() === message.replace('/me ', ''));
|
||||
el = view.el.querySelector('converse-chat-message:last-child .chat-msg__body');
|
||||
expect(view.el.querySelectorAll('.chat-msg--action').length).toBe(3);
|
||||
await u.waitUntil(() => view.querySelector(msg_txt_sel).textContent.trim() === message.replace('/me ', ''));
|
||||
el = view.querySelector('converse-chat-message:last-child .chat-msg__body');
|
||||
expect(view.querySelectorAll('.chat-msg--action').length).toBe(3);
|
||||
|
||||
expect(sizzle('.chat-msg__text:last', view.el).pop().textContent).toBe('wrote a 3rd person message');
|
||||
expect(u.isVisible(sizzle('.chat-msg__author:last', view.el).pop())).toBeTruthy();
|
||||
expect(sizzle('.chat-msg__text:last', view).pop().textContent).toBe('wrote a 3rd person message');
|
||||
expect(u.isVisible(sizzle('.chat-msg__author:last', view).pop())).toBeTruthy();
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ describe("An incoming groupchat message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
if (!view.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
const message = 'romeo: Your attention is required';
|
||||
const nick = mock.chatroom_names[0],
|
||||
msg = $msg({
|
||||
|
@ -25,7 +25,7 @@ describe("An incoming groupchat message", function () {
|
|||
}).c('body').t(message).tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(u.hasClass('mentioned', view.el.querySelector('.chat-msg'))).toBeTruthy();
|
||||
expect(u.hasClass('mentioned', view.querySelector('.chat-msg'))).toBeTruthy();
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -62,7 +62,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);
|
||||
let message = await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
let message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(message.classList.length).toEqual(1);
|
||||
expect(message.innerHTML.replace(/<!---->/g, '')).toBe(
|
||||
'hello <span class="mention">z3r0</span> '+
|
||||
|
@ -77,7 +77,7 @@ describe("An incoming groupchat message", function () {
|
|||
}).c('body').t('https://conversejs.org/@gibson').up()
|
||||
.c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'23', 'end':'29', 'type':'mention', 'uri':'xmpp:gibson@montague.lit'}).nodeTree;
|
||||
await view.model.handleMessageStanza(msg);
|
||||
message = await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(message.classList.length).toEqual(1);
|
||||
expect(message.innerHTML.replace(/<!---->/g, '')).toBe(
|
||||
'hello <span class="mention">z3r0</span> '+
|
||||
|
@ -119,7 +119,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);
|
||||
const message = await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(message.classList.length).toEqual(1);
|
||||
expect(message.innerHTML.replace(/<!---->/g, '')).toBe(
|
||||
'<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>');
|
||||
|
@ -318,7 +318,7 @@ describe("A sent groupchat message", function () {
|
|||
})));
|
||||
await u.waitUntil(() => view.model.occupants.length === 2);
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'hello @Link Mauve'
|
||||
const enter_event = {
|
||||
'target': textarea,
|
||||
|
@ -379,7 +379,7 @@ describe("A sent groupchat message", function () {
|
|||
});
|
||||
await u.waitUntil(() => view.model.occupants.length === 5);
|
||||
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'hello @z3r0 @gibson @mr.robot, how are you?'
|
||||
const enter_event = {
|
||||
'target': textarea,
|
||||
|
@ -410,19 +410,19 @@ describe("A sent groupchat message", function () {
|
|||
`<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
|
||||
`</message>`);
|
||||
|
||||
const action = await u.waitUntil(() => view.el.querySelector('.chat-msg .chat-msg__action'));
|
||||
const action = await u.waitUntil(() => view.querySelector('.chat-msg .chat-msg__action'));
|
||||
action.style.opacity = 1;
|
||||
action.click();
|
||||
|
||||
expect(textarea.value).toBe('hello @z3r0 @gibson @mr.robot, how are you?');
|
||||
expect(view.model.messages.at(0).get('correcting')).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => u.hasClass('correcting', view.querySelector('.chat-msg')), 500);
|
||||
await u.waitUntil(() => _converse.connection.send.calls.count() === 2);
|
||||
|
||||
textarea.value = 'hello @z3r0 @gibson @sw0rdf1sh, how are you?';
|
||||
view.onKeyDown(enter_event);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__text').textContent ===
|
||||
'hello z3r0 gibson sw0rdf1sh, how are you?', 500);
|
||||
|
||||
const correction = _converse.connection.send.calls.all()[2].args[0];
|
||||
|
@ -465,7 +465,7 @@ describe("A sent groupchat message", function () {
|
|||
await u.waitUntil(() => view.model.occupants.length === 5);
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'hello @z3r0 @gibson @mr.robot, how are you?'
|
||||
const enter_event = {
|
||||
'target': textarea,
|
||||
|
@ -501,7 +501,7 @@ describe("A sent groupchat message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'tom', [], members);
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = "Welcome @gibson 💩 We have a guide on how to do that here: https://conversejs.org/docs/html/index.html";
|
||||
const enter_event = {
|
||||
'target': textarea,
|
||||
|
@ -510,7 +510,7 @@ describe("A sent groupchat message", function () {
|
|||
'keyCode': 13 // Enter
|
||||
}
|
||||
view.onKeyDown(enter_event);
|
||||
const message = await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
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: `+
|
||||
|
|
|
@ -15,7 +15,7 @@ describe("A Chat Message", function () {
|
|||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
await _converse.handleMessageStanza(mock.createChatMessage(_converse, contact_jid, 'This message will be read'));
|
||||
const msg_el = await u.waitUntil(() => view.el.querySelector('converse-chat-message'));
|
||||
const msg_el = await u.waitUntil(() => view.querySelector('converse-chat-message'));
|
||||
expect(msg_el.querySelector('.chat-msg__text').textContent).toBe('This message will be read');
|
||||
expect(view.model.get('num_unread')).toBe(0);
|
||||
|
||||
|
@ -26,8 +26,8 @@ describe("A Chat Message", function () {
|
|||
expect(view.model.get('num_unread')).toBe(1);
|
||||
expect(view.model.get('first_unread_id')).toBe(view.model.messages.last().get('id'));
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('converse-chat-message').length === 2);
|
||||
const last_msg_el = view.el.querySelector('converse-chat-message:last-child');
|
||||
await u.waitUntil(() => view.querySelectorAll('converse-chat-message').length === 2);
|
||||
const last_msg_el = view.querySelector('converse-chat-message:last-child');
|
||||
expect(last_msg_el.firstElementChild?.textContent).toBe('New messages');
|
||||
done();
|
||||
}));
|
||||
|
@ -87,7 +87,7 @@ describe("A Chat Message", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length)
|
||||
_converse.filter_by_resource = true;
|
||||
|
||||
let msg = $msg({
|
||||
|
@ -174,7 +174,7 @@ describe("A Chat Message", function () {
|
|||
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
|
||||
.tree();
|
||||
_converse.handleMessageStanza(msg);
|
||||
const csntext = await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent);
|
||||
const csntext = await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent);
|
||||
expect(csntext.trim()).toEqual('Mercutio is typing');
|
||||
|
||||
msg = $msg({
|
||||
|
@ -365,7 +365,7 @@ describe("A Chat Message", function () {
|
|||
expect(msg_obj.get('sender')).toEqual('me');
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
const msg_el = await u.waitUntil(() => view.el.querySelector('.chat-content .chat-msg .chat-msg__text'));
|
||||
const msg_el = await u.waitUntil(() => view.querySelector('.chat-content .chat-msg .chat-msg__text'));
|
||||
expect(msg_el.textContent).toEqual(msgtext);
|
||||
done();
|
||||
}));
|
||||
|
@ -428,7 +428,7 @@ describe("A Chat Message", function () {
|
|||
const contact_name = mock.cur_names[1];
|
||||
const contact_jid = contact_name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
const one_day_ago = dayjs().subtract(1, 'day');
|
||||
|
@ -646,7 +646,7 @@ describe("A Chat Message", function () {
|
|||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000)
|
||||
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(
|
||||
|
@ -656,7 +656,7 @@ describe("A Chat Message", function () {
|
|||
|
||||
message += "?param1=val1¶m2=val2";
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 2, 1000);
|
||||
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(
|
||||
|
@ -667,7 +667,7 @@ describe("A Chat Message", function () {
|
|||
// Test now with two images in one message
|
||||
message += ' hello world '+base_url+"/logo/conversejs-filled.svg";
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 4, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 4, 1000);
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
msg = sizzle('.chat-content .chat-msg:last .chat-msg__text').pop();
|
||||
expect(msg.textContent.trim()).toEqual('hello world');
|
||||
|
@ -677,11 +677,11 @@ describe("A Chat Message", function () {
|
|||
_converse.api.settings.set('image_urls_regex', /^https?:\/\/(?:www.)?(?:imgur\.com\/\w{7})\/?$/i);
|
||||
message = 'https://imgur.com/oxymPax';
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 5, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 5, 1000);
|
||||
expect(view.content.querySelectorAll('.chat-content .chat-image').length).toBe(5);
|
||||
|
||||
// Check that the Imgur URL gets a .png attached to make it render
|
||||
await u.waitUntil(() => Array.from(view.el.querySelectorAll('.chat-content .chat-image')).pop().src.endsWith('png'), 1000);
|
||||
await u.waitUntil(() => Array.from(view.querySelectorAll('.chat-content .chat-image')).pop().src.endsWith('png'), 1000);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -698,12 +698,12 @@ describe("A Chat Message", function () {
|
|||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg').length === 1);
|
||||
|
||||
message = base_url+"/logo/conversejs-filled.svg";
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length === 2, 1000);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 1, 1000)
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg').length === 2, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-image').length === 1, 1000)
|
||||
expect(view.content.querySelectorAll('.chat-content .chat-image').length).toBe(1);
|
||||
|
||||
done();
|
||||
|
@ -722,7 +722,7 @@ describe("A Chat Message", function () {
|
|||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length, 1000)
|
||||
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() ==
|
||||
|
@ -770,10 +770,10 @@ describe("A Chat Message", function () {
|
|||
expect(chatbox.messages.models.length, 1);
|
||||
const msg_object = chatbox.messages.models[0];
|
||||
|
||||
const msg_author = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
|
||||
const msg_author = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__author');
|
||||
expect(msg_author.textContent.trim()).toBe('Romeo Montague');
|
||||
|
||||
const msg_time = view.el.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
|
||||
const msg_time = view.querySelector('.chat-content .chat-msg:last-child .chat-msg__time');
|
||||
const time = dayjs(msg_object.get('time')).format(_converse.time_format);
|
||||
expect(msg_time.textContent).toBe(time);
|
||||
done();
|
||||
|
@ -790,7 +790,7 @@ describe("A Chat Message", function () {
|
|||
const base_time = new Date();
|
||||
const ONE_MINUTE_LATER = 60000;
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 300);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 300);
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
_converse.filter_by_resource = true;
|
||||
|
||||
|
@ -992,7 +992,7 @@ describe("A Chat Message", function () {
|
|||
const include_nick = false;
|
||||
await mock.waitForRoster(_converse, 'current', 1, include_nick);
|
||||
await mock.openControlBox(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 300);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 300);
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
const message = 'This is a received message';
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
@ -1036,7 +1036,7 @@ describe("A Chat Message", function () {
|
|||
async function (done, _converse) {
|
||||
|
||||
await mock.waitForRoster(_converse, 'current', 1, false);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 300);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length, 300);
|
||||
const message = '\n\n This is a received message \n\n';
|
||||
const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await _converse.handleMessageStanza(
|
||||
|
@ -1100,13 +1100,13 @@ describe("A Chat Message", function () {
|
|||
const chatbox = await _converse.api.chats.get(sender_jid);
|
||||
expect(chatbox.get('fullname') === sender_jid);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__author').textContent.trim() === 'Mercutio');
|
||||
let author_el = view.el.querySelector('.chat-msg__author');
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__author').textContent.trim() === 'Mercutio');
|
||||
let author_el = view.querySelector('.chat-msg__author');
|
||||
expect( _.includes(author_el.textContent.trim(), 'Mercutio')).toBeTruthy();
|
||||
await u.waitUntil(() => vcard_fetched, 100);
|
||||
expect(_converse.api.vcard.get).toHaveBeenCalled();
|
||||
await u.waitUntil(() => chatbox.vcard.get('fullname') === mock.cur_names[0])
|
||||
author_el = view.el.querySelector('.chat-msg__author');
|
||||
author_el = view.querySelector('.chat-msg__author');
|
||||
expect( _.includes(author_el.textContent.trim(), 'Mercutio')).toBeTruthy();
|
||||
done();
|
||||
}));
|
||||
|
@ -1159,7 +1159,7 @@ describe("A Chat Message", function () {
|
|||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__author').textContent.trim() === 'Mercutio');
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__author').textContent.trim() === 'Mercutio');
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
expect(view.content.querySelector('.chat-msg .chat-msg__text').textContent).toEqual(message);
|
||||
expect(view.content.querySelector('.chat-msg__time').textContent.match(/^[0-9][0-9]:[0-9][0-9]/)).toBeTruthy();
|
||||
|
@ -1363,7 +1363,7 @@ describe("A Chat Message", function () {
|
|||
}
|
||||
await Promise.all(promises);
|
||||
|
||||
const indicator_el = view.el.querySelector('.new-msgs-indicator');
|
||||
const indicator_el = view.querySelector('.new-msgs-indicator');
|
||||
expect(u.isVisible(indicator_el)).toBeTruthy();
|
||||
|
||||
expect(view.model.get('scrolled')).toBe(true);
|
||||
|
@ -1380,7 +1380,7 @@ describe("A Chat Message", function () {
|
|||
async function (done, _converse) {
|
||||
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length)
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length)
|
||||
// Send a message from a different resource
|
||||
spyOn(converse.env.log, 'error');
|
||||
spyOn(_converse.api.chatboxes, 'create').and.callThrough();
|
||||
|
@ -1444,12 +1444,12 @@ describe("A Chat Message", function () {
|
|||
</message>`)
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg audio').length, 1000);
|
||||
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg audio').length, 1000);
|
||||
let msg = view.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(msg.classList.length).toEqual(1);
|
||||
expect(u.hasClass('chat-msg__text', msg)).toBe(true);
|
||||
expect(msg.textContent).toEqual('Have you heard this funny audio?');
|
||||
let media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
let media = view.querySelector('.chat-msg .chat-msg__media');
|
||||
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>`);
|
||||
|
@ -1464,9 +1464,9 @@ describe("A Chat Message", function () {
|
|||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
|
||||
msg = view.querySelector('.chat-msg:last-child .chat-msg__text');
|
||||
expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('Have you heard this funny audio?'); // Emtpy
|
||||
media = view.el.querySelector('.chat-msg:last-child .chat-msg__media');
|
||||
media = view.querySelector('.chat-msg:last-child .chat-msg__media');
|
||||
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">`+
|
||||
|
@ -1493,11 +1493,11 @@ describe("A Chat Message", function () {
|
|||
<x xmlns="jabber:x:oob"><url>https://montague.lit/video.mp4</url></x>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg video').length, 2000)
|
||||
let msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg video').length, 2000)
|
||||
let msg = view.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(msg.classList.length).toBe(1);
|
||||
expect(msg.textContent).toEqual('Have you seen this funny video?');
|
||||
let media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
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><!---->`);
|
||||
|
||||
|
@ -1512,9 +1512,9 @@ describe("A Chat Message", function () {
|
|||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg = view.el.querySelector('.chat-msg:last-child .chat-msg__text');
|
||||
msg = view.querySelector('.chat-msg:last-child .chat-msg__text');
|
||||
expect(msg.innerHTML.replace(/<!---->/g, '')).toEqual('Have you seen this funny video?');
|
||||
media = view.el.querySelector('.chat-msg:last-child .chat-msg__media');
|
||||
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><!---->`);
|
||||
done();
|
||||
|
@ -1539,11 +1539,11 @@ describe("A Chat Message", function () {
|
|||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000);
|
||||
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg a').length, 1000);
|
||||
const msg = view.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(u.hasClass('chat-msg__text', msg)).toBe(true);
|
||||
expect(msg.textContent).toEqual('Have you downloaded this funny file?');
|
||||
const media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
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><!---->`);
|
||||
done();
|
||||
|
@ -1572,11 +1572,11 @@ describe("A Chat Message", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg a').length, 1000);
|
||||
const msg = view.el.querySelector('.chat-msg .chat-msg__text');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-content .chat-msg a').length, 1000);
|
||||
const msg = view.querySelector('.chat-msg .chat-msg__text');
|
||||
expect(u.hasClass('chat-msg__text', msg)).toBe(true);
|
||||
expect(msg.textContent).toEqual('Have you seen this funny image?');
|
||||
const media = view.el.querySelector('.chat-msg .chat-msg__media');
|
||||
const media = view.querySelector('.chat-msg .chat-msg__media');
|
||||
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>`);
|
||||
|
|
|
@ -21,12 +21,12 @@ describe("A chat message", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const chatview = _converse.api.chatviews.get(contact_jid);
|
||||
expect(u.isVisible(chatview.el)).toBeTruthy();
|
||||
expect(u.isVisible(chatview)).toBeTruthy();
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
chatview.querySelector('.toggle-chatbox-button').click();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
var message = 'This message is sent to a minimized chatbox';
|
||||
var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
|
@ -44,7 +44,7 @@ describe("A chat message", function () {
|
|||
expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
const trimmed_chatboxes = _converse.minimized_chats;
|
||||
let count = trimmed_chatboxes.el.querySelector('converse-minimized-chat .message-count');
|
||||
expect(u.isVisible(chatview.el)).toBeFalsy();
|
||||
expect(u.isVisible(chatview)).toBeFalsy();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
|
||||
expect(u.isVisible(count)).toBeTruthy();
|
||||
|
@ -60,7 +60,7 @@ describe("A chat message", function () {
|
|||
);
|
||||
|
||||
await u.waitUntil(() => (chatview.model.messages.length > 1));
|
||||
expect(u.isVisible(chatview.el)).toBeFalsy();
|
||||
expect(u.isVisible(chatview)).toBeFalsy();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
count = trimmed_chatboxes.el.querySelector('converse-minimized-chat .message-count');
|
||||
expect(u.isVisible(count)).toBeTruthy();
|
||||
|
@ -85,12 +85,12 @@ describe("A Groupcaht", function () {
|
|||
spyOn(view, 'onMaximized').and.callThrough();
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
const button = await u.waitUntil(() => view.el.querySelector('.toggle-chatbox-button'));
|
||||
const button = await u.waitUntil(() => view.querySelector('.toggle-chatbox-button'));
|
||||
button.click();
|
||||
|
||||
expect(view.onMinimized).toHaveBeenCalled();
|
||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
||||
expect(u.isVisible(view.el)).toBeFalsy();
|
||||
expect(u.isVisible(view)).toBeFalsy();
|
||||
expect(view.model.get('minimized')).toBeTruthy();
|
||||
expect(view.onMinimized).toHaveBeenCalled();
|
||||
const el = await u.waitUntil(() => _converse.minimized_chats.el.querySelector("a.restore-chat"));
|
||||
|
@ -115,21 +115,21 @@ describe("A Chatbox", function () {
|
|||
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 u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length);
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const chatview = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(chatview, 'minimize').and.callThrough();
|
||||
spyOn(_converse.api, "trigger").and.callThrough();
|
||||
// We need to rebind all events otherwise our spy won't be called
|
||||
chatview.delegateEvents();
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
chatview.querySelector('.toggle-chatbox-button').click();
|
||||
|
||||
expect(chatview.minimize).toHaveBeenCalled();
|
||||
expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxMinimized', jasmine.any(Object));
|
||||
expect(_converse.api.trigger.calls.count(), 2);
|
||||
expect(u.isVisible(chatview.el)).toBeFalsy();
|
||||
expect(u.isVisible(chatview)).toBeFalsy();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
chatview.querySelector('.toggle-chatbox-button').click();
|
||||
|
||||
await u.waitUntil(() => _converse.chatboxviews.keys().length);
|
||||
_converse.minimized_chats.el.querySelector("a.restore-chat").click();
|
||||
|
@ -150,7 +150,7 @@ describe("A Chatbox", function () {
|
|||
await _converse.api.chats.create(sender_jid, {'minimized': true});
|
||||
await u.waitUntil(() => _converse.chatboxes.length > 1);
|
||||
const chatBoxView = _converse.chatboxviews.get(sender_jid);
|
||||
expect(u.isVisible(chatBoxView.el)).toBeFalsy();
|
||||
expect(u.isVisible(chatBoxview)).toBeFalsy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el.firstElementChild)).toBe(true);
|
||||
expect(_converse.minimized_chats.el.firstElementChild.querySelectorAll('converse-minimized-chat').length).toBe(1);
|
||||
expect(_converse.chatboxes.filter('minimized').length).toBe(1);
|
||||
|
@ -175,9 +175,9 @@ describe("A Chatbox", function () {
|
|||
expect(document.querySelectorAll("#conversejs .chatbox").length).toBe(1); // Controlbox is open
|
||||
|
||||
_converse.rosterview.update(); // XXX: Hack to make sure $roster element is attached.
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group li').length);
|
||||
// Test that they can be maximized again
|
||||
const online_contacts = _converse.rosterview.el.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
|
||||
const online_contacts = _converse.rosterview.querySelectorAll('.roster-group .current-xmpp-contact a.open-chat');
|
||||
expect(online_contacts.length).toBe(17);
|
||||
let i;
|
||||
for (i=0; i<online_contacts.length; i++) {
|
||||
|
@ -265,9 +265,9 @@ describe("A Minimized ChatBoxView's Unread Message Count", function () {
|
|||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
mock.sendMessage(view, message);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length, 1000);
|
||||
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.el).pop();
|
||||
const msg = sizzle('.chat-content .chat-msg:last .chat-msg__text', view).pop();
|
||||
await u.waitUntil(() => msg.innerHTML.replace(/\<!----\>/g, '') ===
|
||||
'<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&'+
|
||||
'mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.786971&mlon=-122.399677#map=18/37.786971/-122.399677</a>');
|
||||
|
@ -292,7 +292,7 @@ describe("The Minimized Chats Widget", function () {
|
|||
let chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el.firstElementChild)).toBe(false);
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
chatview.querySelector('.toggle-chatbox-button').click();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
||||
expect(_converse.chatboxes.filter('minimized').length).toBe(1);
|
||||
|
@ -302,7 +302,7 @@ describe("The Minimized Chats Widget", function () {
|
|||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
chatview = _converse.chatboxviews.get(contact_jid);
|
||||
expect(chatview.model.get('minimized')).toBeFalsy();
|
||||
chatview.el.querySelector('.toggle-chatbox-button').click();
|
||||
chatview.querySelector('.toggle-chatbox-button').click();
|
||||
expect(chatview.model.get('minimized')).toBeTruthy();
|
||||
expect(u.isVisible(_converse.minimized_chats.el)).toBe(true);
|
||||
expect(_converse.chatboxes.filter('minimized').length).toBe(2);
|
||||
|
|
|
@ -442,9 +442,9 @@ window.addEventListener('converse-loaded', () => {
|
|||
|
||||
mock.sendMessage = function (view, message) {
|
||||
const promise = new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
view.el.querySelector('.chat-textarea').value = message;
|
||||
view.querySelector('.chat-textarea').value = message;
|
||||
view.onKeyDown({
|
||||
target: view.el.querySelector('textarea.chat-textarea'),
|
||||
target: view.querySelector('textarea.chat-textarea'),
|
||||
preventDefault: () => {},
|
||||
keyCode: 13
|
||||
});
|
||||
|
@ -641,7 +641,7 @@ window.addEventListener('converse-loaded', () => {
|
|||
'view_mode': mock.view_mode
|
||||
}, settings || {}));
|
||||
|
||||
_converse.ChatBoxViews.prototype.trimChat = function () {};
|
||||
_converse.minimize.trimChat = function () {};
|
||||
|
||||
_converse.api.vcard.get = function (model, force) {
|
||||
let jid;
|
||||
|
|
|
@ -8,7 +8,7 @@ const u = converse.env.utils;
|
|||
|
||||
|
||||
async function openModtools (_converse, view) {
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = '/modtools';
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
view.onKeyDown(enter);
|
||||
|
@ -263,7 +263,7 @@ describe("The groupchat moderator tool", function () {
|
|||
));
|
||||
await u.waitUntil(() => (view.model.occupants.length === 7), 1000);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = '/modtools';
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
view.onKeyDown(enter);
|
||||
|
@ -474,7 +474,7 @@ describe("The groupchat moderator tool", function () {
|
|||
const members = [{'jid': 'romeo@montague.lit', 'nick': 'romeo', 'affiliation': 'owner'}];
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo', [], members);
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = '/modtools';
|
||||
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
|
||||
view.onKeyDown(enter);
|
||||
|
|
|
@ -32,7 +32,7 @@ describe("MUC Mention Notfications", function () {
|
|||
await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED);
|
||||
|
||||
const lview = _converse.rooms_list_view
|
||||
const room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
||||
const room_el = await u.waitUntil(() => lview.querySelector(".available-chatroom"));
|
||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
|
||||
|
||||
const base_time = new Date();
|
||||
|
|
480
spec/muc.js
480
spec/muc.js
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'hello world'
|
||||
const enter_event = {
|
||||
'target': textarea,
|
||||
|
@ -42,7 +42,7 @@ describe("A Groupchat Message", function () {
|
|||
</message>
|
||||
`);
|
||||
_converse.connection._dataRecv(mock.createRequest(error));
|
||||
expect(await u.waitUntil(() => view.el.querySelector('.chat-msg__error')?.textContent?.trim())).toBe(err_msg_text);
|
||||
expect(await u.waitUntil(() => view.querySelector('.chat-msg__error')?.textContent?.trim())).toBe(err_msg_text);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
const message = view.model.messages.at(0);
|
||||
expect(message.get('received')).toBeUndefined();
|
||||
|
@ -74,7 +74,7 @@ describe("A Groupchat Message", function () {
|
|||
</presence>
|
||||
`);
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-info').length === 1);
|
||||
|
||||
presence = u.toStanza(`
|
||||
<presence xmlns="jabber:client" to="${_converse.jid}" from="${muc_jid}/romeo1">
|
||||
|
@ -86,9 +86,9 @@ describe("A Groupchat Message", function () {
|
|||
</presence>
|
||||
`);
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 2);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-info').length === 2);
|
||||
|
||||
const messages = view.el.querySelectorAll('.chat-info');
|
||||
const messages = view.querySelectorAll('.chat-info');
|
||||
expect(u.hasClass('chat-msg--followup', messages[0])).toBe(false);
|
||||
expect(u.hasClass('chat-msg--followup', messages[1])).toBe(false);
|
||||
done();
|
||||
|
@ -119,11 +119,11 @@ describe("A Groupchat Message", function () {
|
|||
spyOn(view.model, 'createInfoMessages').and.callThrough();
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
await u.waitUntil(() => view.model.createInfoMessages.calls.count());
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-info').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-info').length === 1);
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
await u.waitUntil(() => view.model.createInfoMessages.calls.count() === 2);
|
||||
expect(view.el.querySelectorAll('.chat-info').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-info').length).toBe(1);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -159,7 +159,7 @@ describe("A Groupchat Message", function () {
|
|||
expect(converse.env.log.error).toHaveBeenCalledWith(
|
||||
`Ignoring unencapsulated forwarded message from ${muc_jid}/mallory`
|
||||
);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
expect(view.model.messages.length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
|
@ -172,7 +172,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
if (!view.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
const message = 'romeo: Your attention is required';
|
||||
const nick = mock.chatroom_names[0],
|
||||
msg = $msg({
|
||||
|
@ -185,7 +185,7 @@ describe("A Groupchat Message", function () {
|
|||
.tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelector('.chat-msg')).not.toBe(null);
|
||||
expect(view.querySelector('.chat-msg')).not.toBe(null);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -197,7 +197,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
if (!view.el.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
if (!view.querySelectorAll('.chat-area').length) { view.renderChatArea(); }
|
||||
const id = u.getUniqueId();
|
||||
let msg = $msg({
|
||||
from: 'lounge@montague.lit/some1',
|
||||
|
@ -206,7 +206,7 @@ describe("A Groupchat Message", function () {
|
|||
type: 'groupchat'
|
||||
}).c('body').t('First message').tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
|
||||
msg = $msg({
|
||||
from: 'lounge@montague.lit/some2',
|
||||
|
@ -215,7 +215,7 @@ describe("A Groupchat Message", function () {
|
|||
type: 'groupchat'
|
||||
}).c('body').t('Another message').tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.model.messages.length).toBe(2);
|
||||
done();
|
||||
}));
|
||||
|
@ -371,7 +371,7 @@ describe("A Groupchat Message", function () {
|
|||
expect(converse.env.log.error).toHaveBeenCalledWith(
|
||||
'Invalid Stanza: MUC messages SHOULD NOT be XEP-0280 carbon copied'
|
||||
);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
expect(view.model.messages.length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
|
@ -391,10 +391,10 @@ describe("A Groupchat Message", function () {
|
|||
type: 'groupchat'
|
||||
}).c('body').t('I wrote this message!').tree();
|
||||
await view.model.handleMessageStanza(msg);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
|
||||
expect(view.model.messages.last().occupant.get('affiliation')).toBe('owner');
|
||||
expect(view.model.messages.last().occupant.get('role')).toBe('moderator');
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(sizzle('.chat-msg', view.el).pop().classList.value.trim()).toBe('message chat-msg groupchat chat-msg--with-avatar moderator owner');
|
||||
let presence = $pres({
|
||||
to:'romeo@montague.lit/orchard',
|
||||
|
@ -420,7 +420,7 @@ describe("A Groupchat Message", function () {
|
|||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.model.messages.last().occupant.get('affiliation')).toBe('member');
|
||||
expect(view.model.messages.last().occupant.get('role')).toBe('participant');
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(2);
|
||||
expect(sizzle('.chat-msg', view.el).pop().classList.value.trim()).toBe('message chat-msg groupchat chat-msg--with-avatar participant member');
|
||||
|
||||
presence = $pres({
|
||||
|
@ -438,12 +438,12 @@ describe("A Groupchat Message", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
|
||||
view.model.sendMessage('hello world');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 3);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 3);
|
||||
|
||||
const occupant = await u.waitUntil(() => view.model.messages.filter(m => m.get('type') === 'groupchat')[2].occupant);
|
||||
expect(occupant.get('affiliation')).toBe('owner');
|
||||
expect(occupant.get('role')).toBe('moderator');
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(3);
|
||||
await u.waitUntil(() => sizzle('.chat-msg', view.el).pop().classList.value.trim() === 'message chat-msg groupchat chat-msg--with-avatar moderator owner');
|
||||
|
||||
const add_events = view.model.occupants._events.add.length;
|
||||
|
@ -533,7 +533,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -541,7 +541,7 @@ describe("A Groupchat Message", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length).toBe(0);
|
||||
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
const stanza = u.toStanza(`
|
||||
|
@ -556,9 +556,9 @@ describe("A Groupchat Message", function () {
|
|||
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
|
||||
</message>`);
|
||||
await view.model.handleMessageStanza(stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
expect(view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length).toBe(1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
expect(view.querySelectorAll('.chat-msg__receipt').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length).toBe(1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
const message = view.model.messages.at(0);
|
||||
|
@ -611,7 +611,7 @@ describe("A Groupchat Message", function () {
|
|||
const muc_jid = 'lounge@montague.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -619,7 +619,7 @@ describe("A Groupchat Message", function () {
|
|||
keyCode: 13 // Enter
|
||||
});
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
let stanza = u.toStanza(`
|
||||
|
@ -643,7 +643,7 @@ describe("A Groupchat Message", function () {
|
|||
<origin-id xmlns="urn:xmpp:sid:0" id="CE08D448-5ED8-4B6A-BB5B-07ED9DFE4FF0"/>
|
||||
</message>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -17,19 +17,19 @@ describe("A list of open groupchats", function () {
|
|||
await mock.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
|
||||
|
||||
const lview = _converse.rooms_list_view
|
||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.el.querySelectorAll(".open-room");
|
||||
await u.waitUntil(() => lview.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
|
||||
|
||||
await mock.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
|
||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
await u.waitUntil(() => lview.querySelectorAll(".open-room").length > 1);
|
||||
room_els = _converse.rooms_list_view.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(2);
|
||||
|
||||
let view = _converse.chatboxviews.get('room@conference.shakespeare.lit');
|
||||
await view.close();
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
room_els = _converse.rooms_list_view.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
expect(room_els[0].innerText).toBe('lounge@montague.lit');
|
||||
list = controlbox.el.querySelector('.list-container--openrooms');
|
||||
|
@ -37,7 +37,7 @@ describe("A list of open groupchats", function () {
|
|||
|
||||
view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
await view.close();
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
room_els = _converse.rooms_list_view.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(0);
|
||||
|
||||
list = controlbox.el.querySelector('.list-container--openrooms');
|
||||
|
@ -119,8 +119,8 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||
await _converse.api.rooms.open(muc_jid, {'nick': 'some1'}, true);
|
||||
const lview = _converse.rooms_list_view
|
||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.el.querySelectorAll(".available-chatroom");
|
||||
await u.waitUntil(() => lview.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.querySelectorAll(".available-chatroom");
|
||||
expect(room_els.length).toBe(1);
|
||||
|
||||
let item = room_els[0];
|
||||
|
@ -128,11 +128,11 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
await u.waitUntil(() => u.hasClass('open', item), 1000);
|
||||
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
|
||||
await _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'}, true);
|
||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
|
||||
room_els = lview.el.querySelectorAll(".open-room");
|
||||
await u.waitUntil(() => lview.querySelectorAll(".open-room").length > 1);
|
||||
room_els = lview.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(2);
|
||||
|
||||
room_els = lview.el.querySelectorAll(".available-chatroom.open");
|
||||
room_els = lview.querySelectorAll(".available-chatroom.open");
|
||||
expect(room_els.length).toBe(1);
|
||||
item = room_els[0];
|
||||
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
|
||||
|
@ -198,10 +198,11 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
.c('status').attrs({code:'110'});
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
|
||||
await u.waitUntil(() => _converse.rooms_list_view.el.querySelectorAll(".open-room").length, 500);
|
||||
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
const rooms_list = document.querySelector('converse-rooms-list');
|
||||
await u.waitUntil(() => rooms_list.querySelectorAll(".open-room").length, 500);
|
||||
const room_els = rooms_list.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
const info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
||||
const info_el = rooms_list.querySelector(".room-info");
|
||||
info_el.click();
|
||||
|
||||
const modal = _converse.api.modal.get('muc-details-modal');
|
||||
|
@ -259,16 +260,17 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
await mock.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
|
||||
expect(_converse.chatboxes.length).toBe(2);
|
||||
const lview = _converse.rooms_list_view
|
||||
await u.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.el.querySelectorAll(".open-room");
|
||||
await u.waitUntil(() => lview.querySelectorAll(".open-room").length);
|
||||
let room_els = lview.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
const close_el = _converse.rooms_list_view.el.querySelector(".close-room");
|
||||
const rooms_list = document.querySelector('converse-rooms-list');
|
||||
const close_el = rooms_list.querySelector(".close-room");
|
||||
close_el.click();
|
||||
expect(window.confirm).toHaveBeenCalledWith(
|
||||
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');
|
||||
|
||||
await new Promise(resolve => _converse.api.listen.once('chatBoxClosed', resolve));
|
||||
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
room_els = rooms_list.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(0);
|
||||
expect(_converse.chatboxes.length).toBe(1);
|
||||
done();
|
||||
|
@ -284,7 +286,8 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
const u = converse.env.utils;
|
||||
await mock.openControlBox(_converse);
|
||||
const room_jid = 'kitchen@conference.shakespeare.lit';
|
||||
await u.waitUntil(() => _converse.rooms_list_view !== undefined, 500);
|
||||
const rooms_list = document.querySelector('converse-rooms-list');
|
||||
await u.waitUntil(() => rooms_list !== undefined, 500);
|
||||
await mock.openAndEnterChatRoom(_converse, room_jid, 'romeo');
|
||||
const view = _converse.chatboxviews.get(room_jid);
|
||||
view.model.set({'minimized': true});
|
||||
|
@ -299,7 +302,7 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
|
||||
// If the user isn't mentioned, the counter doesn't get incremented, but the text of the groupchat is bold
|
||||
const lview = _converse.rooms_list_view
|
||||
let room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
||||
let room_el = await u.waitUntil(() => lview.querySelector(".available-chatroom"));
|
||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
|
||||
|
||||
// If the user is mentioned, the counter also gets updated
|
||||
|
@ -312,7 +315,7 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
}).c('body').t('romeo: Your attention is required').tree()
|
||||
);
|
||||
|
||||
let indicator_el = await u.waitUntil(() => lview.el.querySelector(".msgs-indicator"));
|
||||
let indicator_el = await u.waitUntil(() => lview.querySelector(".msgs-indicator"));
|
||||
expect(indicator_el.textContent).toBe('1');
|
||||
|
||||
spyOn(view.model, 'handleUnreadMessage').and.callThrough();
|
||||
|
@ -325,13 +328,13 @@ describe("A groupchat shown in the groupchats list", function () {
|
|||
}).c('body').t('romeo: and another thing...').tree()
|
||||
);
|
||||
await u.waitUntil(() => view.model.handleUnreadMessage.calls.count());
|
||||
await u.waitUntil(() => lview.el.querySelector(".msgs-indicator").textContent === '2', 1000);
|
||||
await u.waitUntil(() => lview.querySelector(".msgs-indicator").textContent === '2', 1000);
|
||||
|
||||
// When the chat gets maximized again, the unread indicators are removed
|
||||
view.model.set({'minimized': false});
|
||||
indicator_el = lview.el.querySelector(".msgs-indicator");
|
||||
indicator_el = lview.querySelector(".msgs-indicator");
|
||||
expect(indicator_el === null);
|
||||
room_el = lview.el.querySelector(".available-chatroom");
|
||||
room_el = lview.querySelector(".available-chatroom");
|
||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -39,7 +39,7 @@ describe("Notifications", function () {
|
|||
await mock.waitForRoster(_converse, 'current');
|
||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
|
||||
const view = _converse.api.chatviews.get('lounge@montague.lit');
|
||||
if (!view.el.querySelectorAll('.chat-area').length) {
|
||||
if (!view.querySelectorAll('.chat-area').length) {
|
||||
view.renderChatArea();
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ describe("Notifications", function () {
|
|||
spyOn(window, 'Audio').and.returnValue(stub);
|
||||
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
if (!view.el.querySelectorAll('.chat-area').length) {
|
||||
if (!view.querySelectorAll('.chat-area').length) {
|
||||
view.renderChatArea();
|
||||
}
|
||||
let text = 'This message will play a sound because it mentions romeo';
|
||||
|
@ -327,7 +327,7 @@ describe("Notifications", function () {
|
|||
|
||||
// come back to converse-chat page
|
||||
_converse.saveWindowState({'type': 'focus'});
|
||||
await u.waitUntil(() => u.isVisible(view.el));
|
||||
await u.waitUntil(() => u.isVisible(view));
|
||||
await u.waitUntil(() => favico.badge.calls.count() === 2);
|
||||
expect(favico.badge.calls.mostRecent().args.pop()).toBe(0);
|
||||
|
||||
|
@ -338,7 +338,7 @@ describe("Notifications", function () {
|
|||
// check that msg_counter is incremented from zero again
|
||||
await _converse.handleMessageStanza(msgFactory());
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
await u.waitUntil(() => u.isVisible(view.el));
|
||||
await u.waitUntil(() => u.isVisible(view));
|
||||
await u.waitUntil(() => favico.badge.calls.count() === 3);
|
||||
expect(favico.badge.calls.mostRecent().args.pop()).toBe(1);
|
||||
done();
|
||||
|
|
|
@ -114,7 +114,7 @@ describe("The OMEMO module", function() {
|
|||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
view.model.set('omemo_active', true);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This message will be encrypted';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -198,7 +198,7 @@ describe("The OMEMO module", function() {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.model.messages.length).toBe(2);
|
||||
expect(view.el.querySelectorAll('.chat-msg__body')[1].textContent.trim())
|
||||
expect(view.querySelectorAll('.chat-msg__body')[1].textContent.trim())
|
||||
.toBe('This is an encrypted message from the contact');
|
||||
|
||||
// #1193 Check for a received message without <body> tag
|
||||
|
@ -218,7 +218,7 @@ describe("The OMEMO module", function() {
|
|||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => view.model.messages.length > 1);
|
||||
expect(view.model.messages.length).toBe(3);
|
||||
expect(view.el.querySelectorAll('.chat-msg__body')[2].textContent.trim())
|
||||
expect(view.querySelectorAll('.chat-msg__body')[2].textContent.trim())
|
||||
.toBe('Another received encrypted message without fallback');
|
||||
done();
|
||||
}));
|
||||
|
@ -244,7 +244,7 @@ describe("The OMEMO module", function() {
|
|||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
await u.waitUntil(() => initializedOMEMO(_converse));
|
||||
|
||||
const toolbar = view.el.querySelector('.chat-toolbar');
|
||||
const toolbar = view.querySelector('.chat-toolbar');
|
||||
const el = await u.waitUntil(() => toolbar.querySelector('.toggle-omemo'));
|
||||
el.click();
|
||||
expect(view.model.get('omemo_active')).toBe(true);
|
||||
|
@ -297,7 +297,7 @@ describe("The OMEMO module", function() {
|
|||
expect(u.hasClass('fa-unlock', icon)).toBe(false);
|
||||
expect(u.hasClass('fa-lock', icon)).toBe(true);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This message will be encrypted';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -451,7 +451,7 @@ describe("The OMEMO module", function() {
|
|||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
expect(view.el.querySelector('.chat-msg__text').textContent.trim())
|
||||
expect(view.querySelector('.chat-msg__text').textContent.trim())
|
||||
.toBe('This is an encrypted carbon message from another device of mine');
|
||||
|
||||
expect(contact_devicelist.devices.length).toBe(1);
|
||||
|
@ -463,7 +463,7 @@ describe("The OMEMO module", function() {
|
|||
expect(my_devicelist.devices.at(2).get('id')).toBe('988349631');
|
||||
expect(my_devicelist.devices.get('988349631').get('active')).toBe(true);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is an encrypted message from this device';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -514,13 +514,13 @@ describe("The OMEMO module", function() {
|
|||
}).tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
||||
const toolbar = view.el.querySelector('.chat-toolbar');
|
||||
const toolbar = view.querySelector('.chat-toolbar');
|
||||
const toggle = await u.waitUntil(() => toolbar.querySelector('.toggle-omemo'));
|
||||
toggle.click();
|
||||
expect(view.model.get('omemo_active')).toBe(true);
|
||||
expect(view.model.get('omemo_supported')).toBe(true);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This message will be encrypted';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -605,7 +605,7 @@ describe("The OMEMO module", function() {
|
|||
"to be subscribed to their presence in order to see their OMEMO information");
|
||||
|
||||
expect(view.model.get('omemo_supported')).toBe(false);
|
||||
expect(view.el.querySelector('.chat-textarea').value).toBe('This message will be encrypted');
|
||||
expect(view.querySelector('.chat-textarea').value).toBe('This message will be encrypted');
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -1232,7 +1232,7 @@ describe("The OMEMO module", function() {
|
|||
expect(devicelist.devices.at(3).get('id')).toBe('ae890ac52d0df67ed7cfdf51b644e901');
|
||||
await u.waitUntil(() => _converse.chatboxviews.get(contact_jid).el.querySelector('.chat-toolbar'));
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const toolbar = view.el.querySelector('.chat-toolbar');
|
||||
const toolbar = view.querySelector('.chat-toolbar');
|
||||
expect(view.model.get('omemo_active')).toBe(undefined);
|
||||
const toggle = toolbar.querySelector('.toggle-omemo');
|
||||
expect(toggle === null).toBe(false);
|
||||
|
@ -1248,7 +1248,7 @@ describe("The OMEMO module", function() {
|
|||
expect(u.hasClass('fa-unlock', icon)).toBe(false);
|
||||
expect(u.hasClass('fa-lock', icon)).toBe(true);
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This message will be sent encrypted';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -1296,7 +1296,7 @@ describe("The OMEMO module", function() {
|
|||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
await u.waitUntil(() => initializedOMEMO(_converse));
|
||||
|
||||
const toolbar = view.el.querySelector('.chat-toolbar');
|
||||
const toolbar = view.querySelector('.chat-toolbar');
|
||||
let toggle = await u.waitUntil(() => toolbar.querySelector('.toggle-omemo'));
|
||||
expect(view.model.get('omemo_active')).toBe(undefined);
|
||||
expect(view.model.get('omemo_supported')).toBe(true);
|
||||
|
@ -1370,31 +1370,31 @@ describe("The OMEMO module", function() {
|
|||
// anonymous or semi-anonymous
|
||||
view.model.features.save({'nonanonymous': false, 'semianonymous': true});
|
||||
await u.waitUntil(() => !view.model.get('omemo_supported'));
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-omemo').disabled);
|
||||
await u.waitUntil(() => view.querySelector('.toggle-omemo').disabled);
|
||||
|
||||
view.model.features.save({'nonanonymous': true, 'semianonymous': false});
|
||||
await u.waitUntil(() => view.model.get('omemo_supported'));
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-omemo') !== null);
|
||||
await u.waitUntil(() => view.querySelector('.toggle-omemo') !== null);
|
||||
expect(u.hasClass('fa-unlock', toolbar.querySelector('.toggle-omemo converse-icon'))).toBe(true);
|
||||
expect(u.hasClass('fa-lock', toolbar.querySelector('.toggle-omemo converse-icon'))).toBe(false);
|
||||
expect(!!view.el.querySelector('.toggle-omemo').disabled).toBe(false);
|
||||
expect(!!view.querySelector('.toggle-omemo').disabled).toBe(false);
|
||||
|
||||
// Test that the button gets disabled when the room becomes open
|
||||
view.model.features.save({'membersonly': false, 'open': true});
|
||||
await u.waitUntil(() => !view.model.get('omemo_supported'));
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-omemo').disabled);
|
||||
await u.waitUntil(() => view.querySelector('.toggle-omemo').disabled);
|
||||
|
||||
view.model.features.save({'membersonly': true, 'open': false});
|
||||
await u.waitUntil(() => view.model.get('omemo_supported'));
|
||||
await u.waitUntil(() => !view.el.querySelector('.toggle-omemo').disabled);
|
||||
await u.waitUntil(() => !view.querySelector('.toggle-omemo').disabled);
|
||||
|
||||
expect(u.hasClass('fa-unlock', view.el.querySelector('.toggle-omemo converse-icon'))).toBe(true);
|
||||
expect(u.hasClass('fa-lock', view.el.querySelector('.toggle-omemo converse-icon'))).toBe(false);
|
||||
expect(u.hasClass('fa-unlock', view.querySelector('.toggle-omemo converse-icon'))).toBe(true);
|
||||
expect(u.hasClass('fa-lock', view.querySelector('.toggle-omemo converse-icon'))).toBe(false);
|
||||
|
||||
expect(view.model.get('omemo_supported')).toBe(true);
|
||||
expect(view.model.get('omemo_active')).toBe(false);
|
||||
|
||||
view.el.querySelector('.toggle-omemo').click();
|
||||
view.querySelector('.toggle-omemo').click();
|
||||
expect(view.model.get('omemo_active')).toBe(true);
|
||||
|
||||
// Someone enters the room who doesn't have OMEMO support, while we
|
||||
|
@ -1429,13 +1429,13 @@ describe("The OMEMO module", function() {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
||||
await u.waitUntil(() => !view.model.get('omemo_supported'));
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-error .chat-info__message')?.textContent.trim() ===
|
||||
await u.waitUntil(() => view.querySelector('.chat-error .chat-info__message')?.textContent.trim() ===
|
||||
"oldguy doesn't appear to have a client that supports OMEMO. "+
|
||||
"Encrypted chat will no longer be possible in this grouchat."
|
||||
);
|
||||
|
||||
await u.waitUntil(() => toolbar.querySelector('.toggle-omemo').disabled);
|
||||
icon = view.el.querySelector('.toggle-omemo converse-icon');
|
||||
icon = view.querySelector('.toggle-omemo converse-icon');
|
||||
expect(u.hasClass('fa-unlock', icon)).toBe(true);
|
||||
expect(u.hasClass('fa-lock', icon)).toBe(false);
|
||||
expect(toolbar.querySelector('.toggle-omemo').title).toBe('This groupchat needs to be members-only and non-anonymous in order to support OMEMO encrypted messages');
|
||||
|
@ -1461,7 +1461,7 @@ describe("The OMEMO module", function() {
|
|||
_converse.api.trigger('OMEMOInitialized');
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
const show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
const modal = _converse.api.modal.get('user-details-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
|
|
@ -75,7 +75,7 @@ describe("A sent presence stanza", function () {
|
|||
spyOn(_converse.connection, 'send').and.callThrough();
|
||||
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
const change_status_el = await u.waitUntil(() => cbview.el.querySelector('.change-status'));
|
||||
const change_status_el = await u.waitUntil(() => cbview.querySelector('.change-status'));
|
||||
change_status_el.click()
|
||||
let modal = _converse.api.modal.get('modal-status-change');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -94,7 +94,7 @@ describe("A sent presence stanza", function () {
|
|||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "true");
|
||||
await u.waitUntil(() => !u.isVisible(modal.el));
|
||||
|
||||
cbview.el.querySelector('.change-status').click()
|
||||
cbview.querySelector('.change-status').click()
|
||||
modal = _converse.api.modal.get('modal-status-change');
|
||||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden') === "false", 1000);
|
||||
modal.el.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
|
||||
|
|
|
@ -65,7 +65,7 @@ describe("The Protocol", function () {
|
|||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
cbview.querySelector('.add-contact').click()
|
||||
const modal = _converse.api.modal.get('add-contact-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
spyOn(modal, "addContactFromForm").and.callThrough();
|
||||
|
|
|
@ -97,7 +97,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
|
|||
expect(view.model.get('has_activity')).toBe(false);
|
||||
|
||||
const lview = _converse.rooms_list_view
|
||||
const room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
||||
const room_el = await u.waitUntil(() => lview.querySelector(".available-chatroom"));
|
||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
|
||||
|
||||
const activity_stanza = u.toStanza(`
|
||||
|
@ -161,7 +161,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
|
|||
expect(view.model.get('has_activity')).toBe(false);
|
||||
|
||||
const lview = _converse.rooms_list_view
|
||||
const room_el = await u.waitUntil(() => lview.el.querySelector(".available-chatroom"));
|
||||
const room_el = await u.waitUntil(() => lview.querySelector(".available-chatroom"));
|
||||
expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
|
||||
|
||||
const activity_stanza = u.toStanza(`
|
||||
|
|
|
@ -108,7 +108,7 @@ describe("A delivery receipt", function () {
|
|||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const textarea = view.el.querySelector('textarea.chat-textarea');
|
||||
const textarea = view.querySelector('textarea.chat-textarea');
|
||||
textarea.value = 'But soft, what light through yonder airlock breaks?';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -126,7 +126,7 @@ describe("A delivery receipt", function () {
|
|||
'id': u.getUniqueId(),
|
||||
}).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__receipt').length === 1);
|
||||
|
||||
// Also handle receipts with type 'chat'. See #1353
|
||||
spyOn(_converse, 'handleMessageStanza').and.callThrough();
|
||||
|
@ -147,7 +147,7 @@ describe("A delivery receipt", function () {
|
|||
'id': u.getUniqueId(),
|
||||
}).c('received', {'id': msg_id, xmlns: Strophe.NS.RECEIPTS}).up().tree();
|
||||
_converse.connection._dataRecv(mock.createRequest(msg));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__receipt').length === 2);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__receipt').length === 2);
|
||||
expect(_converse.handleMessageStanza.calls.count()).toBe(1);
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -16,7 +16,7 @@ describe("The Registration Panel", function () {
|
|||
|
||||
await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
|
||||
const cbview = _converse.api.controlbox.get();
|
||||
expect(cbview.el.querySelectorAll('a.register-account').length).toBe(0);
|
||||
expect(cbview.querySelectorAll('a.register-account').length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -36,10 +36,10 @@ describe("The Registration Panel", function () {
|
|||
}
|
||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'), 300);
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
const panels = cbview.el.querySelector('.controlbox-panes');
|
||||
const panels = cbview.querySelector('.controlbox-panes');
|
||||
const login = panels.firstElementChild;
|
||||
const registration = panels.childNodes[1];
|
||||
const register_link = cbview.el.querySelector('a.register-account');
|
||||
const register_link = cbview.querySelector('a.register-account');
|
||||
expect(register_link.textContent).toBe("Create an account");
|
||||
register_link.click();
|
||||
|
||||
|
@ -62,17 +62,17 @@ describe("The Registration Panel", function () {
|
|||
toggle.click();
|
||||
|
||||
const cbview = _converse.api.controlbox.get();
|
||||
await u.waitUntil(() => u.isVisible(cbview.el));
|
||||
await u.waitUntil(() => u.isVisible(cbview));
|
||||
const registerview = cbview.registerpanel;
|
||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||
spyOn(registerview, 'fetchRegistrationForm').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
// Open the register panel
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
|
||||
// Check the form layout
|
||||
const form = cbview.el.querySelector('#converse-register');
|
||||
const form = cbview.querySelector('#converse-register');
|
||||
expect(form.querySelectorAll('input').length).toEqual(2);
|
||||
expect(form.querySelectorAll('input')[0].getAttribute('name')).toEqual('domain');
|
||||
expect(sizzle('input:last', form).pop().getAttribute('type')).toEqual('submit');
|
||||
|
@ -100,7 +100,7 @@ describe("The Registration Panel", function () {
|
|||
|
||||
await u.waitUntil(() => _.get(_converse.chatboxviews.get('controlbox'), 'registerpanel'));
|
||||
const cbview = _converse.api.controlbox.get();
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
|
||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||
spyOn(registerview, 'fetchRegistrationForm').and.callThrough();
|
||||
|
@ -112,8 +112,8 @@ describe("The Registration Panel", function () {
|
|||
|
||||
expect(registerview._registering).toBeFalsy();
|
||||
expect(_converse.api.connection.connected()).toBeFalsy();
|
||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
expect(registerview.onProviderChosen).toHaveBeenCalled();
|
||||
expect(registerview._registering).toBeTruthy();
|
||||
await u.waitUntil(() => registerview.fetchRegistrationForm.calls.count());
|
||||
|
@ -140,9 +140,9 @@ describe("The Registration Panel", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(registerview.onRegistrationFields).toHaveBeenCalled();
|
||||
expect(registerview.renderRegistrationForm).toHaveBeenCalled();
|
||||
expect(registerview.el.querySelectorAll('input').length).toBe(5);
|
||||
expect(registerview.el.querySelectorAll('input[type=submit]').length).toBe(1);
|
||||
expect(registerview.el.querySelectorAll('input[type=button]').length).toBe(1);
|
||||
expect(registerview.querySelectorAll('input').length).toBe(5);
|
||||
expect(registerview.querySelectorAll('input[type=submit]').length).toBe(1);
|
||||
expect(registerview.querySelectorAll('input[type=button]').length).toBe(1);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -163,7 +163,7 @@ describe("The Registration Panel", function () {
|
|||
toggle.click();
|
||||
}
|
||||
const cbview = _converse.api.controlbox.get();
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
|
||||
const registerview = cbview.registerpanel;
|
||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||
|
@ -172,8 +172,8 @@ describe("The Registration Panel", function () {
|
|||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
|
||||
let stanza = new Strophe.Builder("stream:features", {
|
||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||
|
@ -194,12 +194,12 @@ describe("The Registration Panel", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(registerview.form_type).toBe('legacy');
|
||||
|
||||
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
||||
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
||||
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
||||
registerview.querySelector('input[name=username]').value = 'testusername';
|
||||
registerview.querySelector('input[name=password]').value = 'testpassword';
|
||||
registerview.querySelector('input[name=email]').value = 'test@email.local';
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
|
||||
expect(_converse.connection.send).toHaveBeenCalled();
|
||||
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
|
@ -227,7 +227,7 @@ describe("The Registration Panel", function () {
|
|||
toggle.click();
|
||||
}
|
||||
const cbview = _converse.api.controlbox.get();
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||
|
@ -235,8 +235,8 @@ describe("The Registration Panel", function () {
|
|||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
|
||||
let stanza = new Strophe.Builder("stream:features", {
|
||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||
|
@ -259,13 +259,13 @@ describe("The Registration Panel", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(registerview.form_type).toBe('xform');
|
||||
|
||||
registerview.el.querySelector('input[name=username]').value = 'testusername';
|
||||
registerview.el.querySelector('input[name=password]').value = 'testpassword';
|
||||
registerview.el.querySelector('input[name=email]').value = 'test@email.local';
|
||||
registerview.querySelector('input[name=username]').value = 'testusername';
|
||||
registerview.querySelector('input[name=password]').value = 'testpassword';
|
||||
registerview.querySelector('input[name=email]').value = 'test@email.local';
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
|
||||
expect(_converse.connection.send).toHaveBeenCalled();
|
||||
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
|
@ -308,7 +308,7 @@ describe("The Registration Panel", function () {
|
|||
toggle.click();
|
||||
}
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
const registerview = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||
spyOn(registerview, 'onProviderChosen').and.callThrough();
|
||||
spyOn(registerview, 'getRegistrationFields').and.callThrough();
|
||||
|
@ -316,8 +316,8 @@ describe("The Registration Panel", function () {
|
|||
spyOn(registerview, 'renderRegistrationForm').and.callThrough();
|
||||
registerview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
registerview.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
registerview.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
registerview.querySelector('input[type=submit]').click();
|
||||
|
||||
let stanza = new Strophe.Builder("stream:features", {
|
||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||
|
@ -353,7 +353,7 @@ describe("The Registration Panel", function () {
|
|||
</iq>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
expect(registerview.form_type).toBe('xform');
|
||||
expect(registerview.el.querySelectorAll('#converse-register input[required]').length).toBe(3);
|
||||
expect(registerview.querySelectorAll('#converse-register input[required]').length).toBe(3);
|
||||
// Hide the controlbox so that we can see whether the test
|
||||
// passed or failed
|
||||
u.addClass('hidden', _converse.chatboxviews.get('controlbox').el);
|
||||
|
@ -379,12 +379,12 @@ describe("The Registration Panel", function () {
|
|||
toggle.click();
|
||||
}
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.toggle-register-login').click();
|
||||
cbview.querySelector('.toggle-register-login').click();
|
||||
const view = _converse.chatboxviews.get('controlbox').registerpanel;
|
||||
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
view.el.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
view.el.querySelector('input[type=submit]').click();
|
||||
view.querySelector('input[name=domain]').value = 'conversejs.org';
|
||||
view.querySelector('input[type=submit]').click();
|
||||
|
||||
let stanza = new Strophe.Builder("stream:features", {
|
||||
'xmlns:stream': "http://etherx.jabber.org/streams",
|
||||
|
@ -421,13 +421,13 @@ describe("The Registration Panel", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
||||
spyOn(view, 'submitRegistrationForm').and.callThrough();
|
||||
const username_input = view.el.querySelector('[name="username"]');
|
||||
const username_input = view.querySelector('[name="username"]');
|
||||
username_input.value = 'romeo';
|
||||
const password_input = view.el.querySelector('[name="password"]');
|
||||
const password_input = view.querySelector('[name="password"]');
|
||||
password_input.value = 'secret';
|
||||
const ocr_input = view.el.querySelector('[name="ocr"]');
|
||||
const ocr_input = view.querySelector('[name="ocr"]');
|
||||
ocr_input.value = '8m9D88';
|
||||
view.el.querySelector('[type="submit"]').click();
|
||||
view.querySelector('[type="submit"]').click();
|
||||
expect(view.submitRegistrationForm).toHaveBeenCalled();
|
||||
|
||||
const response_IQ = u.toStanza(`
|
||||
|
@ -439,7 +439,7 @@ describe("The Registration Panel", function () {
|
|||
</error>
|
||||
</iq>`);
|
||||
_converse.connection._dataRecv(mock.createRequest(response_IQ));
|
||||
expect(view.el.querySelector('.error')?.textContent.trim()).toBe('Too many CAPTCHA requests');
|
||||
expect(view.querySelector('.error')?.textContent.trim()).toBe('Too many CAPTCHA requests');
|
||||
delete _converse.connection;
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -6,7 +6,7 @@ const u = converse.env.utils;
|
|||
|
||||
async function sendAndThenRetractMessage (_converse, view) {
|
||||
view.model.sendMessage('hello world');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__text').length === 1);
|
||||
const msg_obj = view.model.messages.last();
|
||||
const reflection_stanza = u.toStanza(`
|
||||
<message xmlns="jabber:client"
|
||||
|
@ -20,9 +20,9 @@ async function sendAndThenRetractMessage (_converse, view) {
|
|||
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
|
||||
</message>`);
|
||||
await view.model.handleMessageStanza(reflection_stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
|
||||
const retract_button = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
const retract_button = await u.waitUntil(() => view.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
retract_button.click();
|
||||
await u.waitUntil(() => u.isVisible(document.querySelector('#converse-modals .modal')));
|
||||
const submit_button = document.querySelector('#converse-modals .modal button[type="submit"]');
|
||||
|
@ -53,7 +53,7 @@ describe("Message Retractions", function () {
|
|||
`);
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
await view.model.handleMessageStanza(received_stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
|
||||
|
||||
|
@ -69,7 +69,7 @@ describe("Message Retractions", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
|
||||
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
|
||||
expect(await view.model.handleRetraction.calls.first().returnValue).toBe(true);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.model.messages.length).toBe(2);
|
||||
expect(view.model.messages.at(1).get('retracted')).toBeTruthy();
|
||||
expect(view.model.messages.at(1).get('is_ephemeral')).toBeFalsy();
|
||||
|
@ -119,7 +119,7 @@ describe("Message Retractions", function () {
|
|||
`);
|
||||
_converse.connection._dataRecv(mock.createRequest(received_stanza));
|
||||
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 2);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1, 1000);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
const message = view.model.messages.at(0)
|
||||
|
@ -179,8 +179,8 @@ describe("Message Retractions", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(received_stanza));
|
||||
await u.waitUntil(() => view.model.handleModeration.calls.count() === 2);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
const message = view.model.messages.at(0)
|
||||
|
@ -227,7 +227,7 @@ describe("Message Retractions", function () {
|
|||
expect(message.get('dangling_retraction')).toBe(true);
|
||||
expect(message.get('is_ephemeral')).toBe(false);
|
||||
expect(message.get('retracted')).toBeTruthy();
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(0);
|
||||
|
||||
const stanza = u.toStanza(`
|
||||
<message xmlns="jabber:client"
|
||||
|
@ -279,7 +279,7 @@ describe("Message Retractions", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.model.messages.length === 1);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
|
||||
stanza = u.toStanza(`
|
||||
<message xmlns="jabber:client"
|
||||
|
@ -295,7 +295,7 @@ describe("Message Retractions", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
await u.waitUntil(() => view.model.messages.length === 2);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
|
||||
const retraction_stanza = u.toStanza(`
|
||||
<message id="${u.getUniqueId()}"
|
||||
|
@ -309,16 +309,16 @@ describe("Message Retractions", function () {
|
|||
</message>
|
||||
`);
|
||||
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
|
||||
expect(view.model.messages.length).toBe(2);
|
||||
|
||||
const message = view.model.messages.at(1);
|
||||
expect(message.get('retracted')).toBeTruthy();
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.el.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(msg_el.textContent.trim()).toBe('Mercutio has removed this message');
|
||||
expect(u.hasClass('chat-msg--followup', view.el.querySelector('.chat-msg--retracted'))).toBe(true);
|
||||
expect(u.hasClass('chat-msg--followup', view.querySelector('.chat-msg--retracted'))).toBe(true);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
@ -335,7 +335,7 @@ describe("Message Retractions", function () {
|
|||
const view = await mock.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
view.model.sendMessage('hello world');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
|
||||
const message = view.model.messages.at(0);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
@ -343,14 +343,14 @@ describe("Message Retractions", function () {
|
|||
expect(message.get('editable')).toBeTruthy();
|
||||
|
||||
|
||||
const retract_button = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
const retract_button = await u.waitUntil(() => view.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
retract_button.click();
|
||||
await u.waitUntil(() => u.isVisible(document.querySelector('#converse-modals .modal')));
|
||||
const submit_button = document.querySelector('#converse-modals .modal button[type="submit"]');
|
||||
submit_button.click();
|
||||
|
||||
const sent_stanzas = _converse.connection.sent_stanzas;
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
const retraction_stanza = await u.waitUntil(() => sent_stanzas.filter(s => s.querySelector('message apply-to[xmlns="urn:xmpp:fasten:0"]')).pop());
|
||||
|
@ -365,8 +365,8 @@ describe("Message Retractions", function () {
|
|||
expect(view.model.messages.length).toBe(1);
|
||||
expect(message.get('retracted')).toBeTruthy();
|
||||
expect(message.get('editable')).toBeFalsy();
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(el.textContent.trim()).toBe('Romeo Montague has removed this message');
|
||||
done();
|
||||
}));
|
||||
|
@ -393,7 +393,7 @@ describe("Message Retractions", function () {
|
|||
`);
|
||||
const view = _converse.api.chatviews.get(muc_jid);
|
||||
await view.model.handleMessageStanza(received_stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
|
||||
|
||||
|
@ -407,12 +407,12 @@ describe("Message Retractions", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(retraction_stanza));
|
||||
|
||||
// We opportunistically save the message as retracted, even before receiving the retraction message
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('retracted')).toBeTruthy();
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.el.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(msg_el.textContent.trim()).toBe('eve has removed this message');
|
||||
expect(msg_el.querySelector('.chat-msg--retracted q')).toBe(null);
|
||||
done();
|
||||
|
@ -443,7 +443,7 @@ describe("Message Retractions", function () {
|
|||
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
|
||||
|
||||
const reason = "This content is inappropriate for this forum!"
|
||||
const retract_button = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
const retract_button = await u.waitUntil(() => view.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
retract_button.click();
|
||||
|
||||
await u.waitUntil(() => u.isVisible(document.querySelector('#converse-modals .modal')));
|
||||
|
@ -472,15 +472,15 @@ describe("Message Retractions", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(result_iq));
|
||||
|
||||
// We opportunistically save the message as retracted, even before receiving the retraction message
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('moderated')).toBe('retracted');
|
||||
expect(view.model.messages.at(0).get('moderation_reason')).toBe(reason);
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false);
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
|
||||
const msg_el = view.el.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(msg_el.firstElementChild.textContent.trim()).toBe('romeo has removed this message');
|
||||
|
||||
const qel = msg_el.querySelector('q');
|
||||
|
@ -523,8 +523,8 @@ describe("Message Retractions", function () {
|
|||
</message>
|
||||
`);
|
||||
await view.model.handleMessageStanza(received_stanza);
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-msg__content'));
|
||||
expect(view.el.querySelector('.chat-msg__content .chat-msg__action-retract')).toBe(null);
|
||||
await u.waitUntil(() => view.querySelector('.chat-msg__content'));
|
||||
expect(view.querySelector('.chat-msg__content .chat-msg__action-retract')).toBe(null);
|
||||
const result = await view.model.canModerateMessages();
|
||||
expect(result).toBe(false);
|
||||
done();
|
||||
|
@ -553,7 +553,7 @@ describe("Message Retractions", function () {
|
|||
await u.waitUntil(() => view.model.messages.length === 1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
|
||||
const retract_button = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
const retract_button = await u.waitUntil(() => view.querySelector('.chat-msg__content .chat-msg__action-retract'));
|
||||
retract_button.click();
|
||||
await u.waitUntil(() => u.isVisible(document.querySelector('#converse-modals .modal')));
|
||||
|
||||
|
@ -579,13 +579,13 @@ describe("Message Retractions", function () {
|
|||
</message>`);
|
||||
await view.model.handleMessageStanza(retraction);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('moderated')).toBe('retracted');
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(msg_el.textContent).toBe('romeo has removed this message');
|
||||
const qel = view.el.querySelector('.chat-msg--retracted .chat-msg__message q');
|
||||
const qel = view.querySelector('.chat-msg--retracted .chat-msg__message q');
|
||||
expect(qel.textContent).toBe('This content is inappropriate for this forum!');
|
||||
|
||||
const result_iq = $iq({'from': muc_jid, 'id': stanza.getAttribute('id'), 'to': _converse.bare_jid, 'type': 'result'});
|
||||
|
@ -615,7 +615,7 @@ describe("Message Retractions", function () {
|
|||
expect(occupant.get('role')).toBe('moderator');
|
||||
occupant.save('role', 'member');
|
||||
const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1, 1000);
|
||||
console.log('XXX: First message retracted by author');
|
||||
|
||||
const msg_obj = view.model.messages.last();
|
||||
|
@ -654,8 +654,8 @@ describe("Message Retractions", function () {
|
|||
expect(view.model.messages.last().get('retracted')).toBeTruthy();
|
||||
expect(view.model.messages.last().get('is_ephemeral')).toBe(false);
|
||||
expect(view.model.messages.last().get('editable')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent).toBe('romeo has removed this message');
|
||||
done();
|
||||
}));
|
||||
|
@ -672,13 +672,13 @@ describe("Message Retractions", function () {
|
|||
const occupant = view.model.getOwnOccupant();
|
||||
expect(occupant.get('role')).toBe('moderator');
|
||||
occupant.save('role', 'member');
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"));
|
||||
await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"));
|
||||
const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1, 1000);
|
||||
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
await u.waitUntil(() => view.model.messages.last().get('retracted'), 1000);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent.trim()).toBe('romeo has removed this message');
|
||||
|
||||
const message = view.model.messages.last();
|
||||
|
@ -697,14 +697,14 @@ describe("Message Retractions", function () {
|
|||
</message>`);
|
||||
|
||||
_converse.connection._dataRecv(mock.createRequest(error));
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__error').length === 1, 1000);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__error').length === 1, 1000);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 0, 1000);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(false);
|
||||
|
||||
const errmsg = view.el.querySelector('.chat-msg__error');
|
||||
const errmsg = view.querySelector('.chat-msg__error');
|
||||
expect(errmsg.textContent.trim()).toBe("You're not allowed to retract your message.");
|
||||
done();
|
||||
}));
|
||||
|
@ -723,23 +723,23 @@ describe("Message Retractions", function () {
|
|||
const occupant = view.model.getOwnOccupant();
|
||||
expect(occupant.get('role')).toBe('moderator');
|
||||
occupant.save('role', 'member');
|
||||
await u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"))
|
||||
await u.waitUntil(() => view.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"))
|
||||
await sendAndThenRetractMessage(_converse, view);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.last().get('retracted')).toBeTruthy();
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent.trim()).toBe('romeo has removed this message');
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 0);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
|
||||
expect(view.model.messages.at(0).get('editable')).toBeTruthy();
|
||||
|
||||
const error_messages = view.el.querySelectorAll('.chat-msg__error');
|
||||
const error_messages = view.querySelectorAll('.chat-msg__error');
|
||||
expect(error_messages.length).toBe(1);
|
||||
expect(error_messages[0].textContent.trim()).toBe('A timeout happened while while trying to retract your message.');
|
||||
done();
|
||||
|
@ -759,7 +759,7 @@ describe("Message Retractions", function () {
|
|||
expect(occupant.get('role')).toBe('moderator');
|
||||
|
||||
view.model.sendMessage('Visit this site to get free bitcoin');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
const stanza_id = 'retraction-id-1';
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
const reflection_stanza = u.toStanza(`
|
||||
|
@ -774,7 +774,7 @@ describe("Message Retractions", function () {
|
|||
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
|
||||
</message>`);
|
||||
await view.model.handleMessageStanza(reflection_stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(true);
|
||||
|
||||
|
@ -811,7 +811,7 @@ describe("Message Retractions", function () {
|
|||
expect(occupant.get('role')).toBe('moderator');
|
||||
|
||||
view.model.sendMessage('Visit this site to get free bitcoin');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 1);
|
||||
const stanza_id = 'retraction-id-1';
|
||||
const msg_obj = view.model.messages.at(0);
|
||||
const reflection_stanza = u.toStanza(`
|
||||
|
@ -826,7 +826,7 @@ describe("Message Retractions", function () {
|
|||
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
|
||||
</message>`);
|
||||
await view.model.handleMessageStanza(reflection_stanza);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg__body.chat-msg__body--received').length, 500);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(true);
|
||||
|
||||
|
@ -853,15 +853,15 @@ describe("Message Retractions", function () {
|
|||
_converse.connection._dataRecv(mock.createRequest(result_iq));
|
||||
|
||||
// We opportunistically save the message as retracted, even before receiving the retraction message
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg--retracted').length === 1);
|
||||
expect(view.model.messages.length).toBe(1);
|
||||
expect(view.model.messages.at(0).get('moderated')).toBe('retracted');
|
||||
expect(view.model.messages.at(0).get('moderation_reason')).toBe(undefined);
|
||||
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false);
|
||||
expect(view.model.messages.at(0).get('editable')).toBe(false);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
|
||||
const msg_el = view.el.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
const msg_el = view.querySelector('.chat-msg--retracted .chat-msg__message');
|
||||
expect(msg_el.firstElementChild.textContent.trim()).toBe('romeo has removed this message');
|
||||
expect(msg_el.querySelector('q')).toBe(null);
|
||||
|
||||
|
@ -967,9 +967,9 @@ describe("Message Retractions", function () {
|
|||
expect(await view.model.handleRetraction.calls.first().returnValue).toBe(false);
|
||||
expect(await view.model.handleRetraction.calls.all()[1].returnValue).toBe(false);
|
||||
expect(await view.model.handleRetraction.calls.all()[2].returnValue).toBe(true);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent.trim()).toBe('Mercutio has removed this message');
|
||||
expect(u.hasClass('chat-msg--followup', el.parentElement)).toBe(false);
|
||||
done();
|
||||
|
@ -1043,10 +1043,10 @@ describe("Message Retractions", function () {
|
|||
message = view.model.messages.at(0);
|
||||
expect(message.get('retracted')).toBeTruthy();
|
||||
expect(message.get('is_tombstone')).toBe(true);
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent.trim()).toBe('eve has removed this message');
|
||||
done();
|
||||
}));
|
||||
|
@ -1128,13 +1128,13 @@ describe("Message Retractions", function () {
|
|||
expect(message.get('is_tombstone')).toBe(true);
|
||||
expect(message.get('moderation_reason')).toBe("This message contains inappropriate content");
|
||||
|
||||
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length, 500);
|
||||
expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length, 500);
|
||||
expect(view.querySelectorAll('.chat-msg').length).toBe(1);
|
||||
|
||||
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(view.querySelectorAll('.chat-msg--retracted').length).toBe(1);
|
||||
const el = view.querySelector('.chat-msg--retracted .chat-msg__message div');
|
||||
expect(el.textContent.trim()).toBe('A moderator has removed this message');
|
||||
const qel = view.el.querySelector('.chat-msg--retracted .chat-msg__message q');
|
||||
const qel = view.querySelector('.chat-msg--retracted .chat-msg__message q');
|
||||
expect(qel.textContent.trim()).toBe('This message contains inappropriate content');
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -18,7 +18,7 @@ describe("Chatrooms", function () {
|
|||
const muc_jid = 'coven@chat.shakespeare.lit';
|
||||
await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo')
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
const textarea = view.el.querySelector('.chat-textarea')
|
||||
const textarea = view.querySelector('.chat-textarea')
|
||||
textarea.value = '/register';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
|
|
@ -153,13 +153,13 @@ describe("The Contacts Roster", function () {
|
|||
['rosterGroupsFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
const filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
const filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
expect(filter === null).toBe(false);
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
await mock.openControlBox(_converse);
|
||||
|
||||
const view = _converse.chatboxviews.get('controlbox');
|
||||
const flyout = view.el.querySelector('.box-flyout');
|
||||
const flyout = view.querySelector('.box-flyout');
|
||||
const panel = flyout.querySelector('.controlbox-pane');
|
||||
function hasScrollBar (el) {
|
||||
return el.isConnected && flyout.offsetHeight < panel.scrollHeight;
|
||||
|
@ -176,7 +176,7 @@ describe("The Contacts Roster", function () {
|
|||
|
||||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
let filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
let filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
const roster = _converse.rosterview.roster_el;
|
||||
_converse.rosterview.filter_view.delegateEvents();
|
||||
|
||||
|
@ -194,7 +194,7 @@ describe("The Contacts Roster", function () {
|
|||
const visible_group = sizzle('.roster-group', roster).filter(u.isVisible).pop();
|
||||
expect(visible_group.querySelector('a.group-toggle').textContent.trim()).toBe('friends & acquaintences');
|
||||
|
||||
filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "j";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 2), 700);
|
||||
|
@ -207,14 +207,14 @@ describe("The Contacts Roster", function () {
|
|||
expect(visible_groups[0].textContent.trim()).toBe('friends & acquaintences');
|
||||
expect(visible_groups[1].textContent.trim()).toBe('Ungrouped');
|
||||
|
||||
filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "xxx";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 0), 600);
|
||||
visible_groups = sizzle('.roster-group', roster).filter(u.isVisible).map(el => el.querySelector('a.group-toggle'));
|
||||
expect(visible_groups.length).toBe(0);
|
||||
|
||||
filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 17), 600);
|
||||
|
@ -230,7 +230,7 @@ describe("The Contacts Roster", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
|
||||
const filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
const filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
const roster = _converse.rosterview.roster_el;
|
||||
_converse.rosterview.filter_view.delegateEvents();
|
||||
|
||||
|
@ -278,13 +278,13 @@ describe("The Contacts Roster", function () {
|
|||
_converse.rosterview.filter_view.delegateEvents();
|
||||
var roster = _converse.rosterview.roster_el;
|
||||
|
||||
var button = _converse.rosterview.el.querySelector('span[data-type="groups"]');
|
||||
var button = _converse.rosterview.querySelector('span[data-type="groups"]');
|
||||
button.click();
|
||||
|
||||
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 17), 600);
|
||||
expect(sizzle('.roster-group', roster).filter(u.isVisible).length).toBe(5);
|
||||
|
||||
var filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
var filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "colleagues";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
|
||||
|
@ -294,14 +294,14 @@ describe("The Contacts Roster", function () {
|
|||
// Check that all contacts under the group are shown
|
||||
expect(sizzle('div.roster-group:not(.collapsed) li', roster).filter(l => !u.isVisible(l)).length).toBe(0);
|
||||
|
||||
filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "xxx";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
|
||||
await u.waitUntil(() => (roster.querySelectorAll('div.roster-group.collapsed').length === 5), 700);
|
||||
expect(roster.querySelectorAll('div.roster-group:not(.collapsed) a').length).toBe(0);
|
||||
|
||||
filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = ""; // Check that groups are shown again, when the filter string is cleared.
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
await u.waitUntil(() => (roster.querySelectorAll('div.roster-group.collapsed').length === 0), 700);
|
||||
|
@ -318,15 +318,15 @@ describe("The Contacts Roster", function () {
|
|||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
|
||||
const filter = _converse.rosterview.el.querySelector('.roster-filter');
|
||||
const filter = _converse.rosterview.querySelector('.roster-filter');
|
||||
filter.value = "xxx";
|
||||
u.triggerEvent(filter, "keydown", "KeyboardEvent");
|
||||
expect(_.includes(filter.classList, "x")).toBeFalsy();
|
||||
expect(u.hasClass('hidden', _converse.rosterview.el.querySelector('.roster-filter-form .clear-input'))).toBeTruthy();
|
||||
expect(u.hasClass('hidden', _converse.rosterview.querySelector('.roster-filter-form .clear-input'))).toBeTruthy();
|
||||
|
||||
const isHidden = _.partial(u.hasClass, 'hidden');
|
||||
await u.waitUntil(() => !isHidden(_converse.rosterview.el.querySelector('.roster-filter-form .clear-input')), 900);
|
||||
_converse.rosterview.el.querySelector('.clear-input').click();
|
||||
await u.waitUntil(() => !isHidden(_converse.rosterview.querySelector('.roster-filter-form .clear-input')), 900);
|
||||
_converse.rosterview.querySelector('.clear-input').click();
|
||||
expect(document.querySelector('.roster-filter').value).toBe("");
|
||||
done();
|
||||
}));
|
||||
|
@ -344,11 +344,11 @@ describe("The Contacts Roster", function () {
|
|||
jid = mock.cur_names[4].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
_converse.roster.get(jid).presence.set('show', 'dnd');
|
||||
mock.openControlBox(_converse);
|
||||
const button = _converse.rosterview.el.querySelector('span[data-type="state"]');
|
||||
const button = _converse.rosterview.querySelector('span[data-type="state"]');
|
||||
button.click();
|
||||
const roster = _converse.rosterview.roster_el;
|
||||
await u.waitUntil(() => sizzle('li', roster).filter(u.isVisible).length === 15, 900);
|
||||
const filter = _converse.rosterview.el.querySelector('.state-type');
|
||||
const filter = _converse.rosterview.querySelector('.state-type');
|
||||
expect(sizzle('ul.roster-group-contacts', roster).filter(u.isVisible).length).toBe(5);
|
||||
filter.value = "online";
|
||||
u.triggerEvent(filter, 'change');
|
||||
|
@ -565,7 +565,7 @@ describe("The Contacts Roster", function () {
|
|||
}
|
||||
});
|
||||
const view = _converse.rosterview.get('Colleagues');
|
||||
const toggle = view.el.querySelector('a.group-toggle');
|
||||
const toggle = view.querySelector('a.group-toggle');
|
||||
expect(view.model.get('state')).toBe('opened');
|
||||
toggle.click();
|
||||
await u.waitUntil(() => view.model.get('state') === 'closed');
|
||||
|
@ -736,7 +736,7 @@ describe("The Contacts Roster", function () {
|
|||
await u.waitUntil(() => sizzle('li', _converse.rosterview.get('Pending contacts').el).filter(u.isVisible).length, 900);
|
||||
// Check that they are sorted alphabetically
|
||||
const view = _converse.rosterview.get('Pending contacts');
|
||||
const spans = view.el.querySelectorAll('.pending-xmpp-contact span');
|
||||
const spans = view.querySelectorAll('.pending-xmpp-contact span');
|
||||
const t = _.reduce(spans, (result, value) => result + _.trim(value.textContent), '');
|
||||
expect(t).toEqual(mock.pend_names.slice(0,i+1).sort().join(''));
|
||||
done();
|
||||
|
@ -757,7 +757,7 @@ describe("The Contacts Roster", function () {
|
|||
|
||||
await _addContacts(_converse);
|
||||
await u.waitUntil(() => sizzle('li', _converse.rosterview.el).filter(u.isVisible).length, 500);
|
||||
await checkHeaderToggling.apply(_converse, [_converse.rosterview.el.querySelector('.roster-group')]);
|
||||
await checkHeaderToggling.apply(_converse, [_converse.rosterview.querySelector('.roster-group')]);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -769,7 +769,7 @@ describe("The Contacts Roster", function () {
|
|||
_converse.roster_groups = false;
|
||||
await _addContacts(_converse);
|
||||
await u.waitUntil(() => sizzle('li', _converse.rosterview.el).filter(u.isVisible).length, 500);
|
||||
_converse.rosterview.el.querySelector('.roster-group a.group-toggle').click();
|
||||
_converse.rosterview.querySelector('.roster-group a.group-toggle').click();
|
||||
const name = "Romeo Montague";
|
||||
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
_converse.roster.create({
|
||||
|
@ -814,7 +814,7 @@ describe("The Contacts Roster", function () {
|
|||
async function (done, _converse) {
|
||||
|
||||
await _addContacts(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('li').length);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('li').length);
|
||||
const name = mock.cur_names[0];
|
||||
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
const contact = _converse.roster.get(jid);
|
||||
|
@ -857,12 +857,12 @@ describe("The Contacts Roster", function () {
|
|||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
|
||||
if (typeof callback === "function") { return callback(); }
|
||||
});
|
||||
expect(u.isVisible(_converse.rosterview.el.querySelector('.roster-group'))).toBe(true);
|
||||
expect(u.isVisible(_converse.rosterview.querySelector('.roster-group'))).toBe(true);
|
||||
sizzle(`.remove-xmpp-contact[title="Click to remove ${name} as a contact"]`, _converse.rosterview.el).pop().click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(contact.removeFromRoster).toHaveBeenCalled();
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length === 0);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group').length === 0);
|
||||
done();
|
||||
}));
|
||||
|
||||
|
@ -872,7 +872,7 @@ describe("The Contacts Roster", function () {
|
|||
async function (done, _converse) {
|
||||
|
||||
await _addContacts(_converse);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length, 700);
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group li').length, 700);
|
||||
const roster = _converse.rosterview.el;
|
||||
const groups = roster.querySelectorAll('.roster-group');
|
||||
const groupnames = Array.from(groups).map(g => g.getAttribute('data-group'));
|
||||
|
@ -1025,7 +1025,7 @@ describe("The Contacts Roster", function () {
|
|||
_converse.roster.get(jid).presence.set('show', 'unavailable');
|
||||
}
|
||||
|
||||
await u.waitUntil(() => u.isVisible(_converse.rosterview.el.querySelector('li:first-child')), 900);
|
||||
await u.waitUntil(() => u.isVisible(_converse.rosterview.querySelector('li:first-child')), 900);
|
||||
const roster = _converse.rosterview.el;
|
||||
const groups = roster.querySelectorAll('.roster-group');
|
||||
const groupnames = Array.from(groups).map(g => g.getAttribute('data-group'));
|
||||
|
@ -1165,7 +1165,7 @@ describe("The Contacts Roster", function () {
|
|||
const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
const contact = _converse.roster.get(jid);
|
||||
spyOn(contact, 'authorize').and.callFake(() => contact);
|
||||
await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group li').length)
|
||||
await u.waitUntil(() => _converse.rosterview.querySelectorAll('.roster-group li').length)
|
||||
// TODO: Testing can be more thorough here, the user is
|
||||
// actually not accepted/authorized because of
|
||||
// mock_connection.
|
||||
|
|
|
@ -39,10 +39,10 @@ describe("A spoiler message", function () {
|
|||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Mercutio');
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Mercutio');
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
const spoiler_hint_el = view.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe(spoiler_hint);
|
||||
done();
|
||||
}));
|
||||
|
@ -75,13 +75,13 @@ describe("A spoiler message", function () {
|
|||
await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
await u.waitUntil(() => u.isVisible(view.el));
|
||||
await u.waitUntil(() => u.isVisible(view));
|
||||
await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
|
||||
await u.waitUntil(() => u.isVisible(view.el.querySelector('.chat-msg__author')));
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.includes('Mercutio')).toBeTruthy();
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => u.isVisible(view.querySelector('.chat-msg__author')));
|
||||
expect(view.querySelector('.chat-msg__author').textContent.includes('Mercutio')).toBeTruthy();
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
const spoiler_hint_el = view.el.querySelector('.spoiler-hint');
|
||||
const spoiler_hint_el = view.querySelector('.spoiler-hint');
|
||||
expect(spoiler_hint_el.textContent).toBe('');
|
||||
done();
|
||||
}));
|
||||
|
@ -112,11 +112,11 @@ describe("A spoiler message", function () {
|
|||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
await u.waitUntil(() => view.querySelector('.toggle-compose-spoiler'));
|
||||
let spoiler_toggle = view.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
view.onKeyDown({
|
||||
target: textarea,
|
||||
|
@ -147,15 +147,15 @@ describe("A spoiler message", function () {
|
|||
expect(body_el.textContent).toBe(spoiler);
|
||||
|
||||
/* Test the HTML spoiler message */
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
|
||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
const spoiler_msg_el = view.querySelector('.chat-msg__text.spoiler');
|
||||
expect(Array.from(spoiler_msg_el.classList).includes('hidden')).toBeTruthy();
|
||||
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
spoiler_toggle = view.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent.trim()).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
await u.waitUntil(() => !Array.from(spoiler_msg_el.classList).includes('hidden'));
|
||||
|
@ -190,15 +190,15 @@ describe("A spoiler message", function () {
|
|||
await mock.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]);
|
||||
const view = _converse.api.chatviews.get(contact_jid);
|
||||
|
||||
await u.waitUntil(() => view.el.querySelector('.toggle-compose-spoiler'));
|
||||
let spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
await u.waitUntil(() => view.querySelector('.toggle-compose-spoiler'));
|
||||
let spoiler_toggle = view.querySelector('.toggle-compose-spoiler');
|
||||
spoiler_toggle.click();
|
||||
|
||||
spyOn(_converse.connection, 'send');
|
||||
|
||||
const textarea = view.el.querySelector('.chat-textarea');
|
||||
const textarea = view.querySelector('.chat-textarea');
|
||||
textarea.value = 'This is the spoiler';
|
||||
const hint_input = view.el.querySelector('.spoiler-hint');
|
||||
const hint_input = view.querySelector('.spoiler-hint');
|
||||
hint_input.value = 'This is the hint';
|
||||
|
||||
view.onKeyDown({
|
||||
|
@ -229,15 +229,15 @@ describe("A spoiler message", function () {
|
|||
const body_el = stanza.querySelector('body');
|
||||
expect(body_el.textContent).toBe(spoiler);
|
||||
|
||||
expect(view.el.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
expect(view.querySelector('.chat-msg__author').textContent.trim()).toBe('Romeo Montague');
|
||||
|
||||
const message_content = view.el.querySelector('.chat-msg__text');
|
||||
const message_content = view.querySelector('.chat-msg__text');
|
||||
await u.waitUntil(() => message_content.textContent === spoiler);
|
||||
|
||||
const spoiler_msg_el = view.el.querySelector('.chat-msg__text.spoiler');
|
||||
const spoiler_msg_el = view.querySelector('.chat-msg__text.spoiler');
|
||||
expect(Array.from(spoiler_msg_el.classList).includes('hidden')).toBeTruthy();
|
||||
|
||||
spoiler_toggle = view.el.querySelector('.spoiler-toggle');
|
||||
spoiler_toggle = view.querySelector('.spoiler-toggle');
|
||||
expect(spoiler_toggle.textContent.trim()).toBe('Show more');
|
||||
spoiler_toggle.click();
|
||||
await u.waitUntil(() => !Array.from(spoiler_msg_el.classList).includes('hidden'));
|
||||
|
|
|
@ -29,7 +29,7 @@ describe("An incoming chat Message", function () {
|
|||
expect(view.model.messages.models[0].get('is_unstyled')).toBe(true);
|
||||
|
||||
setTimeout(() => {
|
||||
const msg_el = view.el.querySelector('converse-chat-message-body');
|
||||
const msg_el = view.querySelector('converse-chat-message-body');
|
||||
expect(msg_el.innerText).toBe(msg_text);
|
||||
done();
|
||||
}, 500);
|
||||
|
@ -60,7 +60,7 @@ describe("An incoming chat Message", function () {
|
|||
expect(view.model.messages.models[0].get('is_unstyled')).toBe(false);
|
||||
|
||||
setTimeout(() => {
|
||||
const msg_el = view.el.querySelector('converse-chat-message-body');
|
||||
const msg_el = view.querySelector('converse-chat-message-body');
|
||||
expect(msg_el.innerText).toBe(msg_text);
|
||||
done();
|
||||
}, 500);
|
||||
|
@ -80,7 +80,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = view.el.querySelector('converse-chat-message-body');
|
||||
msg_el = view.querySelector('converse-chat-message-body');
|
||||
expect(msg_el.innerText).toBe(msg_text);
|
||||
await u.waitUntil(() => msg_el.innerHTML.replace(/<!---->/g, '') ===
|
||||
'This <span class="styling-directive">*</span>'+
|
||||
|
@ -94,7 +94,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'Here\'s a <span class="styling-directive">~</span><del>strikethrough section</del><span class="styling-directive">~</span>');
|
||||
|
@ -104,7 +104,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'<span class="styling-directive">~</span>'+
|
||||
|
@ -117,7 +117,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'<span class="styling-directive">*</span>'+
|
||||
|
@ -129,7 +129,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'<span class="styling-directive">~</span><del> Hello! <span title=":poop:">💩</span> </del><span class="styling-directive">~</span>');
|
||||
|
@ -139,7 +139,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'This *is not a styling hint \n'+
|
||||
|
@ -149,7 +149,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'(There are three blocks in this body marked by parens,)\n'+
|
||||
|
@ -162,7 +162,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'_<span class="styling-directive">_</span><i> hello world </i><span class="styling-directive">_</span>');
|
||||
|
@ -172,7 +172,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'Go to ~https://conversejs.org~now <span class="styling-directive">_</span><i>please</i><span class="styling-directive">_</span>');
|
||||
|
@ -181,7 +181,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'Go to <span class="styling-directive">_</span>'+
|
||||
|
@ -205,7 +205,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'Here\'s a code block: \n'+
|
||||
|
@ -217,7 +217,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'<div class="styling-directive">```</div>'+
|
||||
|
@ -230,7 +230,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'```ignored\n (println "Hello, world!")\n ```\n\n'+
|
||||
|
@ -253,7 +253,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>This is quoted text\nThis is also quoted</blockquote>\nThis is not quoted');
|
||||
|
@ -262,7 +262,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>This is <span class="styling-directive">*</span><b>quoted</b><span class="styling-directive">*</span> text\n'+
|
||||
|
@ -273,7 +273,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>");
|
||||
|
||||
|
@ -281,7 +281,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>");
|
||||
|
||||
|
@ -289,7 +289,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>'+
|
||||
|
@ -303,7 +303,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>```\n (println "Hello, world!")</blockquote>\n\n'+
|
||||
|
@ -313,7 +313,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>Also, icons.js is loaded from /dist, instead of dist.</blockquote>\n'+
|
||||
|
@ -323,7 +323,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>Where is it located?</blockquote>\n'+
|
||||
|
@ -334,7 +334,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>What do you think of it?</blockquote>\n <span title=":poop:">💩</span>');
|
||||
|
@ -343,7 +343,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>What do you think of it?</blockquote>\n<span class="styling-directive">~</span><del>hello</del><span class="styling-directive">~</span>');
|
||||
|
@ -352,7 +352,7 @@ describe("An incoming chat Message", function () {
|
|||
msg = mock.createChatMessage(_converse, contact_jid, msg_text)
|
||||
await _converse.handleMessageStanza(msg);
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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 > this is not a quote');
|
||||
|
||||
|
@ -380,7 +380,7 @@ describe("An incoming chat Message", function () {
|
|||
await _converse.handleMessageStanza(msg);
|
||||
|
||||
await new Promise(resolve => view.model.messages.once('rendered', resolve));
|
||||
msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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>What do you think of it <span class="mention">romeo</span>?</blockquote>\n Did you see this <span class="mention">romeo</span>?`);
|
||||
|
@ -407,10 +407,10 @@ describe("A outgoing groupchat Message", function () {
|
|||
}).c('body').t(msg_text).up()
|
||||
.c('reference', {'xmlns':'urn:xmpp:reference:0', 'begin':'23', 'end':'29', 'type':'mention', 'uri':'xmpp:romeo@montague.lit'}).nodeTree;
|
||||
await view.model.handleMessageStanza(msg);
|
||||
const message = await u.waitUntil(() => view.el.querySelector('.chat-msg__text'));
|
||||
const message = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
|
||||
expect(message.classList.length).toEqual(1);
|
||||
|
||||
const msg_el = Array.from(view.el.querySelectorAll('converse-chat-message-body')).pop();
|
||||
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, '') ===
|
||||
'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>');
|
||||
|
|
|
@ -15,8 +15,9 @@ describe("The User Details Modal", function () {
|
|||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid);
|
||||
await u.waitUntil(() => _converse.chatboxes.length > 1);
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
let show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
const modal = _converse.api.modal.get('user-details-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
|
@ -27,7 +28,7 @@ describe("The User Details Modal", function () {
|
|||
remove_contact_button.click();
|
||||
await u.waitUntil(() => modal.el.getAttribute('aria-hidden'), 1000);
|
||||
await u.waitUntil(() => !u.isVisible(modal.el));
|
||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
remove_contact_button = modal.el.querySelector('button.remove-contact');
|
||||
expect(remove_contact_button === null).toBeTruthy();
|
||||
|
@ -43,7 +44,7 @@ describe("The User Details Modal", function () {
|
|||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
|
||||
await mock.openChatBoxFor(_converse, contact_jid)
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
let show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
let show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
let modal = _converse.api.modal.get('user-details-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||
|
@ -61,12 +62,12 @@ describe("The User Details Modal", function () {
|
|||
expect(u.ancestor(header, '.modal-content').querySelector('.modal-body p').textContent.trim())
|
||||
.toBe("Sorry, there was an error while trying to remove Mercutio as a contact.");
|
||||
document.querySelector('.alert-danger button.close').click();
|
||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
modal = _converse.api.modal.get('user-details-modal');
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
||||
|
||||
show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
show_modal_button = view.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
await u.waitUntil(() => u.isVisible(modal.el), 2000)
|
||||
|
||||
|
|
|
@ -294,8 +294,8 @@ describe("XSS", function () {
|
|||
|
||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||
await u.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
|
||||
const occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
|
||||
await u.waitUntil(() => view.querySelectorAll('li .occupant-nick').length, 500);
|
||||
const occupants = view.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
|
||||
expect(occupants.length).toBe(2);
|
||||
expect(occupants[0].textContent.trim()).toBe("<img src="x" onerror="alert(123)"/>");
|
||||
done();
|
||||
|
@ -314,7 +314,7 @@ describe("XSS", function () {
|
|||
'text': subject,
|
||||
'author': 'ralphm'
|
||||
}});
|
||||
const text = await u.waitUntil(() => view.el.querySelector('.chat-head__desc')?.textContent.trim());
|
||||
const text = await u.waitUntil(() => view.querySelector('.chat-head__desc')?.textContent.trim());
|
||||
expect(text).toBe(subject);
|
||||
done();
|
||||
}));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { api, converse } from "@converse/headless/core";
|
||||
import tpl_converse from "../templates/converse.js";
|
||||
import { CustomElement } from './element.js';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -8,11 +9,10 @@ import { api, converse } from "@converse/headless/core";
|
|||
* It can be inserted into the DOM before or after Converse has loaded or been
|
||||
* initialized.
|
||||
*/
|
||||
class ConverseRoot extends HTMLElement {
|
||||
class ConverseRoot extends CustomElement {
|
||||
|
||||
async connectedCallback () {
|
||||
await api.waitUntil('initialized');
|
||||
converse.insertInto(this);
|
||||
render () { // eslint-disable-line class-methods-use-this
|
||||
return tpl_converse();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,16 +17,17 @@ import "./plugins/chatview/index.js"; // Renders standalone chat boxes for
|
|||
import "./plugins/controlbox/index.js"; // The control box
|
||||
import "./plugins/dragresize/index.js"; // Allows chat boxes to be resized by dragging them
|
||||
import "./plugins/fullscreen.js";
|
||||
import "./plugins/headlines-view/index.js";
|
||||
import "./plugins/mam-views.js";
|
||||
import "./plugins/minimize/index.js"; // Allows chat boxes to be minimized
|
||||
import "./plugins/muc-views/index.js"; // Views related to MUC
|
||||
import "./plugins/headlines-view/index.js";
|
||||
import "./plugins/notifications/index.js";
|
||||
import "./plugins/omemo.js";
|
||||
import "./plugins/profile/index.js";
|
||||
import "./plugins/push.js"; // XEP-0357 Push Notifications
|
||||
import "./plugins/register/index.js"; // XEP-0077 In-band registration
|
||||
import "./plugins/roomslist/index.js"; // Show currently open chat rooms
|
||||
import "./plugins/rootview/index.js";
|
||||
import "./plugins/rosterview/index.js";
|
||||
import "./plugins/singleton.js";
|
||||
/* END: Removable components */
|
||||
|
@ -43,17 +44,18 @@ const WHITELISTED_PLUGINS = [
|
|||
'converse-controlbox',
|
||||
'converse-dragresize',
|
||||
'converse-fullscreen',
|
||||
'converse-headlines-view',
|
||||
'converse-mam-views',
|
||||
'converse-minimize',
|
||||
'converse-modal',
|
||||
'converse-muc-views',
|
||||
'converse-headlines-view',
|
||||
'converse-notification',
|
||||
'converse-omemo',
|
||||
'converse-profile',
|
||||
'converse-push',
|
||||
'converse-register',
|
||||
'converse-roomslist',
|
||||
'converse-rootview',
|
||||
'converse-rosterview',
|
||||
'converse-singleton'
|
||||
];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isElement } from 'lodash-es';
|
||||
import isElement from 'lodash-es/isElement';
|
||||
|
||||
const LEVELS = {
|
||||
'debug': 0,
|
||||
|
|
|
@ -2,7 +2,7 @@ import bootstrap from "bootstrap.native";
|
|||
import log from "@converse/headless/log";
|
||||
import tpl_alert_component from "templates/alert.js";
|
||||
import { View } from '@converse/skeletor/src/view.js';
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
import { api, converse } from "@converse/headless/core";
|
||||
import { render } from 'lit-html';
|
||||
|
||||
const { sizzle } = converse.env;
|
||||
|
@ -46,7 +46,7 @@ const BaseModal = View.extend({
|
|||
},
|
||||
|
||||
insertIntoDOM () {
|
||||
const container_el = _converse.chatboxviews.el.querySelector("#converse-modals");
|
||||
const container_el = document.querySelector("#converse-modals");
|
||||
container_el.insertAdjacentElement('beforeEnd', this.el);
|
||||
},
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ export const bookmarkableChatRoomView = {
|
|||
'model': this.model,
|
||||
'chatroomview': this
|
||||
});
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const container_el = this.querySelector('.chatroom-body');
|
||||
container_el.insertAdjacentElement('beforeend', this.bookmark_form.el);
|
||||
}
|
||||
u.showElement(this.bookmark_form.el);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
class ChatBoxViews {
|
||||
|
||||
constructor () {
|
||||
this.views = {};
|
||||
}
|
||||
|
||||
add (key, val) {
|
||||
this.views[key] = val;
|
||||
}
|
||||
|
||||
get (key) {
|
||||
return this.views[key];
|
||||
}
|
||||
|
||||
getAll () {
|
||||
return Object.values(this.views);
|
||||
}
|
||||
|
||||
keys () {
|
||||
return Object.keys(this.views);
|
||||
}
|
||||
|
||||
remove (key) {
|
||||
delete this.views[key];
|
||||
}
|
||||
|
||||
map (f) {
|
||||
return Object.values(this.views).map(f);
|
||||
}
|
||||
|
||||
forEach (f) {
|
||||
return Object.values(this.views).forEach(f);
|
||||
}
|
||||
|
||||
filter (f) {
|
||||
return Object.values(this.views).filter(f);
|
||||
}
|
||||
|
||||
closeAllChatBoxes () {
|
||||
return Promise.all(Object.values(this.views).map(v => v.close({ 'name': 'closeAllChatBoxes' })));
|
||||
}
|
||||
}
|
||||
|
||||
export default ChatBoxViews;
|
|
@ -3,23 +3,13 @@
|
|||
* @copyright 2020, the Converse.js contributors
|
||||
* @license Mozilla Public License (MPLv2)
|
||||
*/
|
||||
import './view.js';
|
||||
import '@converse/headless/plugins/chatboxes';
|
||||
import 'components/converse.js';
|
||||
import ChatBoxViews from './container.js';
|
||||
import ViewWithAvatar from 'shared/avatar.js';
|
||||
import ChatBoxViews from './view.js';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
||||
function onChatBoxViewsInitialized () {
|
||||
_converse.chatboxviews = new _converse.ChatBoxViews({
|
||||
'model': _converse.chatboxes
|
||||
});
|
||||
/**
|
||||
* Triggered once the _converse.ChatBoxViews view-colleciton has been initialized
|
||||
* @event _converse#chatBoxViewsInitialized
|
||||
* @example _converse.api.listen.on('chatBoxViewsInitialized', () => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxViewsInitialized');
|
||||
}
|
||||
|
||||
function calculateViewportHeightUnit () {
|
||||
const vh = window.innerHeight * 0.01;
|
||||
|
@ -47,13 +37,17 @@ converse.plugins.add('converse-chatboxviews', {
|
|||
});
|
||||
|
||||
_converse.ViewWithAvatar = ViewWithAvatar;
|
||||
_converse.ChatBoxViews = ChatBoxViews;
|
||||
_converse.chatboxviews = new ChatBoxViews();
|
||||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
api.listen.on('chatBoxesInitialized', onChatBoxViewsInitialized);
|
||||
api.listen.on('chatBoxesInitialized', () => {
|
||||
_converse.chatboxes.on('destroy', m => _converse.chatboxviews.remove(m.get('jid')));
|
||||
});
|
||||
|
||||
api.listen.on('cleanup', () => delete _converse.chatboxviews);
|
||||
api.listen.on('clearSession', () => _converse.chatboxviews.closeAllChatBoxes());
|
||||
api.listen.on('chatBoxViewsInitialized', calculateViewportHeightUnit);
|
||||
|
||||
window.addEventListener('resize', calculateViewportHeightUnit);
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import { html } from 'lit-html';
|
||||
import { _converse } from '@converse/headless/core';
|
||||
|
||||
export default () => {
|
||||
const { chatboxes, CONTROLBOX_TYPE, CHATROOMS_TYPE } = _converse;
|
||||
return html`
|
||||
<converse-minimized-chats></converse-minimized-chats>
|
||||
${chatboxes.map(m => {
|
||||
if (m.get('type') === CONTROLBOX_TYPE) {
|
||||
return html`
|
||||
<converse-controlbox-toggle class="${!m.get('closed') ? 'hidden' : ''}"></converse-controlbox-toggle>
|
||||
<converse-controlbox id="controlbox" class="chatbox ${m.get('closed') ? 'hidden' : ''}"></converse-controlbox>
|
||||
`;
|
||||
} else if (m.get('type') === CHATROOMS_TYPE) {
|
||||
return html`
|
||||
<converse-muc jid="${m.get('jid')}" class="chatbox ${(m.get('hidden') || m.get('minimized')) ? 'hidden' : ''}"></converse-muc>
|
||||
`;
|
||||
} else {
|
||||
return html`
|
||||
<converse-chat jid="${m.get('jid')}" class="chatbox ${(m.get('hidden') || m.get('minimized')) ? 'hidden' : ''}"></converse-chat>
|
||||
`;
|
||||
}
|
||||
})}
|
||||
`;
|
||||
};
|
|
@ -1,75 +1,39 @@
|
|||
import tpl_background_logo from '../../templates/background_logo.js';
|
||||
import tpl_converse from '../../templates/converse.js';
|
||||
import { Overview } from '@converse/skeletor/src/overview';
|
||||
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 { result } from 'lodash-es';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
||||
|
||||
const ChatBoxViews = Overview.extend({
|
||||
_ensureElement () {
|
||||
/* Override method from backbone.js
|
||||
* If the #conversejs element doesn't exist, create it.
|
||||
*/
|
||||
if (this.el) {
|
||||
this.setElement(result(this, 'el'), false);
|
||||
} else {
|
||||
let el = _converse.root.querySelector('#conversejs');
|
||||
if (el === null) {
|
||||
el = document.createElement('div');
|
||||
el.setAttribute('id', 'conversejs');
|
||||
u.addClass(`theme-${api.settings.get('theme')}`, el);
|
||||
const body = _converse.root.querySelector('body');
|
||||
if (body) {
|
||||
body.appendChild(el);
|
||||
} else {
|
||||
// Perhaps inside a web component?
|
||||
_converse.root.appendChild(el);
|
||||
}
|
||||
}
|
||||
this.setElement(el, false);
|
||||
}
|
||||
},
|
||||
class ConverseChats extends ElementView {
|
||||
|
||||
initialize () {
|
||||
this.listenTo(this.model, 'destroy', this.removeChat);
|
||||
this.model = _converse.chatboxes;
|
||||
this.listenTo(this.model, 'destroy', this.render);
|
||||
this.listenTo(this.model, 'add', this.render);
|
||||
this.listenTo(this.model, 'change:hidden', this.render);
|
||||
this.listenTo(this.model, 'change:closed', this.render);
|
||||
this.listenTo(this.model, 'change:jid', this.render);
|
||||
|
||||
const bg = document.getElementById('conversejs-bg');
|
||||
if (bg && !bg.innerHTML.trim()) {
|
||||
render(tpl_background_logo(), bg);
|
||||
}
|
||||
const body = document.querySelector('body');
|
||||
body.classList.add(`converse-${api.settings.get('view_mode')}`);
|
||||
this.el.classList.add(`converse-${api.settings.get('view_mode')}`);
|
||||
if (api.settings.get('singleton')) {
|
||||
this.el.classList.add(`converse-singleton`);
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
|
||||
/**
|
||||
* Triggered once the _converse.ChatBoxViews view-colleciton has been initialized
|
||||
* @event _converse#chatBoxViewsInitialized
|
||||
* @example _converse.api.listen.on('chatBoxViewsInitialized', () => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxViewsInitialized');
|
||||
}
|
||||
|
||||
render () {
|
||||
this._ensureElement();
|
||||
render(tpl_converse(), this.el);
|
||||
this.row_el = this.el.querySelector('.row');
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new DOM element (likely a chat box) into the
|
||||
* the row managed by this overview.
|
||||
* @param { HTMLElement } el
|
||||
*/
|
||||
insertRowColumn (el) {
|
||||
this.row_el.insertAdjacentElement('afterBegin', el);
|
||||
},
|
||||
|
||||
removeChat (item) {
|
||||
this.remove(item.get('id'));
|
||||
},
|
||||
|
||||
closeAllChatBoxes () {
|
||||
return Promise.all(this.map(v => v.close({ 'name': 'closeAllChatBoxes' })));
|
||||
render(tpl_chats(), this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default ChatBoxViews;
|
||||
api.elements.define('converse-chats', ConverseChats);
|
||||
|
|
|
@ -14,25 +14,6 @@ import chatview_api from './api.js';
|
|||
|
||||
const { Strophe } = converse.env;
|
||||
|
||||
function onWindowStateChanged (data) {
|
||||
if (_converse.chatboxviews) {
|
||||
_converse.chatboxviews.forEach(view => {
|
||||
if (view.model.get('id') !== 'controlbox') {
|
||||
view.onWindowStateChanged(data.state);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onChatBoxViewsInitialized () {
|
||||
const views = _converse.chatboxviews;
|
||||
_converse.chatboxes.on('add', async item => {
|
||||
if (!views.get(item.get('id')) && item.get('type') === _converse.PRIVATE_CHAT_TYPE) {
|
||||
await item.initialized;
|
||||
views.add(item.get('id'), new _converse.ChatBoxView({ model: item }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
converse.plugins.add('converse-chatview', {
|
||||
/* Plugin dependencies are other plugins which might be
|
||||
|
@ -77,8 +58,6 @@ converse.plugins.add('converse-chatview', {
|
|||
|
||||
_converse.ChatBoxView = ChatBoxView;
|
||||
|
||||
api.listen.on('chatBoxViewsInitialized', onChatBoxViewsInitialized);
|
||||
api.listen.on('windowStateChanged', onWindowStateChanged);
|
||||
api.listen.on('connected', () => api.disco.own.features.add(Strophe.NS.SPOILER));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import BaseChatView from 'shared/chatview.js';
|
||||
import UserDetailsModal from 'modals/user-details.js';
|
||||
import log from '@converse/headless/log';
|
||||
import tpl_chatbox from 'templates/chatbox.js';
|
||||
import tpl_chatbox_head from 'templates/chatbox_head.js';
|
||||
import tpl_chatbox_message_form from 'templates/chatbox_message_form.js';
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
import tpl_toolbar from 'templates/toolbar.js';
|
||||
import { View } from '@converse/skeletor/src/view.js';
|
||||
import { __ } from '../../i18n';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { html, render } from 'lit-html';
|
||||
|
@ -20,12 +18,12 @@ const { dayjs } = converse.env;
|
|||
* @namespace _converse.ChatBoxView
|
||||
* @memberOf _converse
|
||||
*/
|
||||
const ChatBoxView = View.extend({
|
||||
length: 200,
|
||||
className: 'chatbox hidden',
|
||||
is_chatroom: false, // Leaky abstraction from MUC
|
||||
export default class ChatView extends BaseChatView {
|
||||
length = 200
|
||||
className = 'chatbox hidden'
|
||||
is_chatroom = false // Leaky abstraction from MUC
|
||||
|
||||
events: {
|
||||
events = {
|
||||
'click .chatbox-navback': 'showControlBox',
|
||||
'click .new-msgs-indicator': 'viewUnreadMessages',
|
||||
'click .send-button': 'onFormSubmitted',
|
||||
|
@ -34,15 +32,20 @@ const ChatBoxView = View.extend({
|
|||
'keydown .chat-textarea': 'onKeyDown',
|
||||
'keyup .chat-textarea': 'onKeyUp',
|
||||
'paste .chat-textarea': 'onPaste'
|
||||
},
|
||||
}
|
||||
|
||||
async initialize () {
|
||||
const jid = this.getAttribute('jid');
|
||||
_converse.chatboxviews.add(jid, this);
|
||||
|
||||
this.model = _converse.chatboxes.get(jid);
|
||||
this.initDebounced();
|
||||
|
||||
api.listen.on('windowStateChanged', this.onWindowStateChanged);
|
||||
|
||||
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
||||
this.listenTo(this.model, 'change:hidden', m => (m.get('hidden') ? this.hide() : this.show()));
|
||||
this.listenTo(this.model, 'change:hidden', m => (!m.get('hidden') && this.show()));
|
||||
this.listenTo(this.model, 'change:status', this.onStatusMessageChanged);
|
||||
this.listenTo(this.model, 'destroy', this.remove);
|
||||
this.listenTo(this.model, 'show', this.show);
|
||||
this.listenTo(this.model, 'vcard:change', this.renderHeading);
|
||||
|
||||
|
@ -68,7 +71,6 @@ const ChatBoxView = View.extend({
|
|||
this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
|
||||
|
||||
await this.model.messages.fetched;
|
||||
this.insertIntoDOM();
|
||||
this.model.maybeShow();
|
||||
this.scrollDown();
|
||||
/**
|
||||
|
@ -78,7 +80,7 @@ const ChatBoxView = View.extend({
|
|||
* @example _converse.api.listen.on('chatBoxViewInitialized', view => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxViewInitialized', this);
|
||||
},
|
||||
}
|
||||
|
||||
initDebounced () {
|
||||
this.markScrolled = debounce(this._markScrolled, 100);
|
||||
|
@ -93,20 +95,20 @@ const ChatBoxView = View.extend({
|
|||
this.renderChatHistory = () => this.renderChatContent(false);
|
||||
this.renderNotifications = () => this.renderChatContent(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
const result = tpl_chatbox(Object.assign(this.model.toJSON(), { 'markScrolled': ev => this.markScrolled(ev) }));
|
||||
render(result, this.el);
|
||||
this.content = this.el.querySelector('.chat-content');
|
||||
this.notifications = this.el.querySelector('.chat-content__notifications');
|
||||
this.msgs_container = this.el.querySelector('.chat-content__messages');
|
||||
this.help_container = this.el.querySelector('.chat-content__help');
|
||||
render(result, this);
|
||||
this.content = this.querySelector('.chat-content');
|
||||
this.notifications = this.querySelector('.chat-content__notifications');
|
||||
this.msgs_container = this.querySelector('.chat-content__messages');
|
||||
this.help_container = this.querySelector('.chat-content__help');
|
||||
this.renderChatContent();
|
||||
this.renderMessageForm();
|
||||
this.renderHeading();
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
onMessageAdded (message) {
|
||||
this.renderChatHistory();
|
||||
|
@ -122,7 +124,7 @@ const ChatBoxView = View.extend({
|
|||
this.showNewMessagesIndicator();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getNotifications () {
|
||||
if (this.model.notifications.get('chat_state') === _converse.COMPOSING) {
|
||||
|
@ -134,16 +136,16 @@ const ChatBoxView = View.extend({
|
|||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getHelpMessages () {
|
||||
getHelpMessages () { // eslint-disable-line class-methods-use-this
|
||||
return [
|
||||
`<strong>/clear</strong>: ${__('Remove messages')}`,
|
||||
`<strong>/close</strong>: ${__('Close this chat')}`,
|
||||
`<strong>/me</strong>: ${__('Write in the third person')}`,
|
||||
`<strong>/help</strong>: ${__('Show this menu')}`
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
renderHelpMessages () {
|
||||
render(
|
||||
|
@ -159,80 +161,22 @@ const ChatBoxView = View.extend({
|
|||
|
||||
this.help_container
|
||||
);
|
||||
},
|
||||
|
||||
renderChatContent (msgs_by_ref = false) {
|
||||
if (!this.tpl_chat_content) {
|
||||
this.tpl_chat_content = o => {
|
||||
return html`
|
||||
<converse-chat-content .chatview=${this} .messages=${o.messages} notifications=${o.notifications}>
|
||||
</converse-chat-content>
|
||||
`;
|
||||
};
|
||||
}
|
||||
const msg_models = this.model.messages.models;
|
||||
const messages = msgs_by_ref ? msg_models : Array.from(msg_models);
|
||||
render(this.tpl_chat_content({ messages, 'notifications': this.getNotifications() }), this.msgs_container);
|
||||
},
|
||||
|
||||
renderToolbar () {
|
||||
if (!api.settings.get('show_toolbar')) {
|
||||
return this;
|
||||
}
|
||||
const options = Object.assign(
|
||||
{
|
||||
'model': this.model,
|
||||
'chatview': this
|
||||
},
|
||||
this.model.toJSON(),
|
||||
this.getToolbarOptions()
|
||||
);
|
||||
render(tpl_toolbar(options), this.el.querySelector('.chat-toolbar'));
|
||||
/**
|
||||
* Triggered once the _converse.ChatBoxView's toolbar has been rendered
|
||||
* @event _converse#renderToolbar
|
||||
* @type { _converse.ChatBoxView }
|
||||
* @example _converse.api.listen.on('renderToolbar', view => { ... });
|
||||
*/
|
||||
api.trigger('renderToolbar', this);
|
||||
return this;
|
||||
},
|
||||
|
||||
renderMessageForm () {
|
||||
const form_container = this.el.querySelector('.message-form-container');
|
||||
render(
|
||||
tpl_chatbox_message_form(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
'hint_value': this.el.querySelector('.spoiler-hint')?.value,
|
||||
'label_message': this.model.get('composing_spoiler') ? __('Hidden message') : __('Message'),
|
||||
'label_spoiler_hint': __('Optional hint'),
|
||||
'message_value': this.el.querySelector('.chat-textarea')?.value,
|
||||
'show_send_button': api.settings.get('show_send_button'),
|
||||
'show_toolbar': api.settings.get('show_toolbar'),
|
||||
'unread_msgs': __('You have unread messages')
|
||||
})
|
||||
),
|
||||
form_container
|
||||
);
|
||||
this.el.addEventListener('focusin', ev => this.emitFocused(ev));
|
||||
this.el.addEventListener('focusout', ev => this.emitBlurred(ev));
|
||||
this.renderToolbar();
|
||||
},
|
||||
}
|
||||
|
||||
showControlBox () {
|
||||
// Used in mobile view, to navigate back to the controlbox
|
||||
_converse.chatboxviews.get('controlbox')?.show();
|
||||
this.hide();
|
||||
},
|
||||
}
|
||||
|
||||
showUserDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(UserDetailsModal, { model: this.model }, ev);
|
||||
},
|
||||
}
|
||||
|
||||
onDragOver (evt) {
|
||||
onDragOver (evt) { // eslint-disable-line class-methods-use-this
|
||||
evt.preventDefault();
|
||||
},
|
||||
}
|
||||
|
||||
onDrop (evt) {
|
||||
if (evt.dataTransfer.files.length == 0) {
|
||||
|
@ -242,33 +186,12 @@ const ChatBoxView = View.extend({
|
|||
}
|
||||
evt.preventDefault();
|
||||
this.model.sendFiles(evt.dataTransfer.files);
|
||||
},
|
||||
}
|
||||
|
||||
async renderHeading () {
|
||||
const tpl = await this.generateHeadingTemplate();
|
||||
render(tpl, this.el.querySelector('.chat-head-chatbox'));
|
||||
},
|
||||
|
||||
async getHeadingStandaloneButton (promise_or_data) {
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a
|
||||
href="#"
|
||||
class="chatbox-btn ${data.a_class} fa ${data.icon_class}"
|
||||
@click=${data.handler}
|
||||
title="${data.i18n_title}"
|
||||
></a>
|
||||
`;
|
||||
},
|
||||
|
||||
async getHeadingDropdownItem (promise_or_data) {
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a href="#" class="dropdown-item ${data.a_class}" @click=${data.handler} title="${data.i18n_title}"
|
||||
><i class="fa ${data.icon_class}"></i>${data.i18n_text}</a
|
||||
>
|
||||
`;
|
||||
},
|
||||
render(tpl, this.querySelector('.chat-head-chatbox'));
|
||||
}
|
||||
|
||||
async generateHeadingTemplate () {
|
||||
const vcard = this.model?.vcard;
|
||||
|
@ -295,7 +218,7 @@ const ChatBoxView = View.extend({
|
|||
'standalone_btns': standalone_btns.map(b => this.getHeadingStandaloneButton(b))
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the chat's header.
|
||||
|
@ -344,12 +267,12 @@ const ChatBoxView = View.extend({
|
|||
* });
|
||||
*/
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
},
|
||||
}
|
||||
|
||||
getToolbarOptions () {
|
||||
getToolbarOptions () { // eslint-disable-line class-methods-use-this
|
||||
// FIXME: can this be removed?
|
||||
return {};
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the chat down, *if* appropriate.
|
||||
|
@ -365,32 +288,7 @@ const ChatBoxView = View.extend({
|
|||
if ((new_own_msg || !this.model.get('scrolled')) && !this.model.isHidden()) {
|
||||
this.debouncedScrollDown();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Scrolls the chat down.
|
||||
*
|
||||
* This method will always scroll the chat down, regardless of
|
||||
* whether the user scrolled up manually or not.
|
||||
* @param { Event } [ev] - An optional event that is the cause for needing to scroll down.
|
||||
*/
|
||||
scrollDown (ev) {
|
||||
ev?.preventDefault?.();
|
||||
ev?.stopPropagation?.();
|
||||
if (this.model.get('scrolled')) {
|
||||
u.safeSave(this.model, {
|
||||
'scrolled': false,
|
||||
'scrollTop': null
|
||||
});
|
||||
}
|
||||
if (this.msgs_container.scrollTo) {
|
||||
const behavior = this.msgs_container.scrollTop ? 'smooth' : 'auto';
|
||||
this.msgs_container.scrollTo({ 'top': this.msgs_container.scrollHeight, behavior });
|
||||
} else {
|
||||
this.msgs_container.scrollTop = this.msgs_container.scrollHeight;
|
||||
}
|
||||
this.onScrolledDown();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the previously saved scrollTop position, or scroll
|
||||
|
@ -403,22 +301,10 @@ const ChatBoxView = View.extend({
|
|||
} else {
|
||||
this.scrollDown();
|
||||
}
|
||||
},
|
||||
|
||||
insertIntoDOM () {
|
||||
_converse.chatboxviews.insertRowColumn(this.el);
|
||||
/**
|
||||
* Triggered once the _converse.ChatBoxView has been inserted into the DOM
|
||||
* @event _converse#chatBoxInsertedIntoDOM
|
||||
* @type { _converse.ChatBoxView | _converse.HeadlinesBoxView }
|
||||
* @example _converse.api.listen.on('chatBoxInsertedIntoDOM', view => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxInsertedIntoDOM', this);
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
addSpinner (append = false) {
|
||||
if (this.el.querySelector('.spinner') === null) {
|
||||
if (this.querySelector('.spinner') === null) {
|
||||
const el = u.getElementFromTemplateResult(tpl_spinner());
|
||||
if (append) {
|
||||
this.content.insertAdjacentElement('beforeend', el);
|
||||
|
@ -427,11 +313,11 @@ const ChatBoxView = View.extend({
|
|||
this.content.insertAdjacentElement('afterbegin', el);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clearSpinner () {
|
||||
this.content.querySelectorAll('.spinner').forEach(u.removeElement);
|
||||
},
|
||||
}
|
||||
|
||||
onStatusMessageChanged (item) {
|
||||
this.renderHeading();
|
||||
|
@ -447,7 +333,7 @@ const ChatBoxView = View.extend({
|
|||
'contact': item.attributes,
|
||||
'message': item.get('status')
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a message element, determine wether it should be
|
||||
|
@ -463,7 +349,7 @@ const ChatBoxView = View.extend({
|
|||
* @method _converse.ChatBoxView#markFollowups
|
||||
* @param { HTMLElement } el - The message element
|
||||
*/
|
||||
markFollowups (el) {
|
||||
markFollowups (el) { // eslint-disable-line class-methods-use-this
|
||||
const from = el.getAttribute('data-from');
|
||||
const previous_el = el.previousElementSibling;
|
||||
const date = dayjs(el.getAttribute('data-isodate'));
|
||||
|
@ -495,7 +381,7 @@ const ChatBoxView = View.extend({
|
|||
} else {
|
||||
u.removeClass('chat-msg--followup', next_el);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
parseMessageForCommands (text) {
|
||||
const match = text.replace(/^\s*/, '').match(/^\/(.*)\s*$/);
|
||||
|
@ -511,82 +397,7 @@ const ChatBoxView = View.extend({
|
|||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async onFormSubmitted (ev) {
|
||||
ev.preventDefault();
|
||||
const textarea = this.el.querySelector('.chat-textarea');
|
||||
const message_text = textarea.value.trim();
|
||||
if (
|
||||
(api.settings.get('message_limit') && message_text.length > api.settings.get('message_limit')) ||
|
||||
!message_text.replace(/\s/g, '').length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!_converse.connection.authenticated) {
|
||||
const err_msg = __('Sorry, the connection has been lost, and your message could not be sent');
|
||||
api.alert('error', __('Error'), err_msg);
|
||||
api.connection.reconnect();
|
||||
return;
|
||||
}
|
||||
let spoiler_hint,
|
||||
hint_el = {};
|
||||
if (this.model.get('composing_spoiler')) {
|
||||
hint_el = this.el.querySelector('form.sendXMPPMessage input.spoiler-hint');
|
||||
spoiler_hint = hint_el.value;
|
||||
}
|
||||
u.addClass('disabled', textarea);
|
||||
textarea.setAttribute('disabled', 'disabled');
|
||||
this.el.querySelector('converse-emoji-dropdown')?.hideMenu();
|
||||
|
||||
const is_command = this.parseMessageForCommands(message_text);
|
||||
const message = is_command ? null : await this.model.sendMessage(message_text, spoiler_hint);
|
||||
if (is_command || message) {
|
||||
hint_el.value = '';
|
||||
textarea.value = '';
|
||||
u.removeClass('correcting', textarea);
|
||||
textarea.style.height = 'auto';
|
||||
this.updateCharCounter(textarea.value);
|
||||
}
|
||||
if (message) {
|
||||
/**
|
||||
* Triggered whenever a message is sent by the user
|
||||
* @event _converse#messageSend
|
||||
* @type { _converse.Message }
|
||||
* @example _converse.api.listen.on('messageSend', message => { ... });
|
||||
*/
|
||||
api.trigger('messageSend', message);
|
||||
}
|
||||
if (api.settings.get('view_mode') === 'overlayed') {
|
||||
// XXX: Chrome flexbug workaround. The .chat-content area
|
||||
// doesn't resize when the textarea is resized to its original size.
|
||||
this.msgs_container.parentElement.style.display = 'none';
|
||||
}
|
||||
textarea.removeAttribute('disabled');
|
||||
u.removeClass('disabled', textarea);
|
||||
|
||||
if (api.settings.get('view_mode') === 'overlayed') {
|
||||
// XXX: Chrome flexbug workaround.
|
||||
this.msgs_container.parentElement.style.display = '';
|
||||
}
|
||||
// Suppress events, otherwise superfluous CSN gets set
|
||||
// immediately after the message, causing rate-limiting issues.
|
||||
this.model.setChatState(_converse.ACTIVE, { 'silent': true });
|
||||
textarea.focus();
|
||||
},
|
||||
|
||||
updateCharCounter (chars) {
|
||||
if (api.settings.get('message_limit')) {
|
||||
const message_limit = this.el.querySelector('.message-limit');
|
||||
const counter = api.settings.get('message_limit') - chars.length;
|
||||
message_limit.textContent = counter;
|
||||
if (counter < 1) {
|
||||
u.addClass('error', message_limit);
|
||||
} else {
|
||||
u.removeClass('error', message_limit);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onPaste (ev) {
|
||||
if (ev.clipboardData.files.length !== 0) {
|
||||
|
@ -599,28 +410,7 @@ const ChatBoxView = View.extend({
|
|||
return;
|
||||
}
|
||||
this.updateCharCounter(ev.clipboardData.getData('text/plain'));
|
||||
},
|
||||
|
||||
autocompleteInPicker (input, value) {
|
||||
const emoji_dropdown = this.el.querySelector('converse-emoji-dropdown');
|
||||
const emoji_picker = this.el.querySelector('converse-emoji-picker');
|
||||
if (emoji_picker && emoji_dropdown) {
|
||||
emoji_picker.model.set({
|
||||
'ac_position': input.selectionStart,
|
||||
'autocompleting': value,
|
||||
'query': value
|
||||
});
|
||||
emoji_dropdown.showMenu();
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
onEmojiReceivedFromPicker (emoji) {
|
||||
const model = this.el.querySelector('converse-emoji-picker').model;
|
||||
const autocompleting = model.get('autocompleting');
|
||||
const ac_position = model.get('ac_position');
|
||||
this.insertIntoTextArea(emoji, autocompleting, false, ac_position);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for when a depressed key goes up
|
||||
|
@ -629,7 +419,7 @@ const ChatBoxView = View.extend({
|
|||
*/
|
||||
onKeyUp (ev) {
|
||||
this.updateCharCounter(ev.target.value);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for when a key is pressed down in a chat box textarea.
|
||||
|
@ -657,14 +447,14 @@ const ChatBoxView = View.extend({
|
|||
} else if (ev.keyCode === converse.keycodes.ENTER) {
|
||||
return this.onEnterPressed(ev);
|
||||
} else if (ev.keyCode === converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
|
||||
const textarea = this.el.querySelector('.chat-textarea');
|
||||
const textarea = this.querySelector('.chat-textarea');
|
||||
if (!textarea.value || u.hasClass('correcting', textarea)) {
|
||||
return this.editEarlierMessage();
|
||||
}
|
||||
} else if (
|
||||
ev.keyCode === converse.keycodes.DOWN_ARROW &&
|
||||
ev.target.selectionEnd === ev.target.value.length &&
|
||||
u.hasClass('correcting', this.el.querySelector('.chat-textarea'))
|
||||
u.hasClass('correcting', this.querySelector('.chat-textarea'))
|
||||
) {
|
||||
return this.editLaterMessage();
|
||||
}
|
||||
|
@ -685,15 +475,11 @@ const ChatBoxView = View.extend({
|
|||
// (which would imply an internal command and not a message).
|
||||
this.model.setChatState(_converse.COMPOSING);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getOwnMessages () {
|
||||
return this.model.messages.filter({ 'sender': 'me' });
|
||||
},
|
||||
|
||||
onEnterPressed (ev) {
|
||||
return this.onFormSubmitted(ev);
|
||||
},
|
||||
}
|
||||
|
||||
onEscapePressed (ev) {
|
||||
ev.preventDefault();
|
||||
|
@ -703,7 +489,7 @@ const ChatBoxView = View.extend({
|
|||
message.save('correcting', false);
|
||||
}
|
||||
this.insertIntoTextArea('', true, false);
|
||||
},
|
||||
}
|
||||
|
||||
async onMessageRetractButtonClicked (message) {
|
||||
if (message.get('sender') !== 'me') {
|
||||
|
@ -723,11 +509,11 @@ const ChatBoxView = View.extend({
|
|||
if (result) {
|
||||
this.model.retractOwnMessage(message);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onMessageEditButtonClicked (message) {
|
||||
const currently_correcting = this.model.messages.findWhere('correcting');
|
||||
const unsent_text = this.el.querySelector('.chat-textarea')?.value;
|
||||
const unsent_text = this.querySelector('.chat-textarea')?.value;
|
||||
if (unsent_text && (!currently_correcting || currently_correcting.get('message') !== unsent_text)) {
|
||||
if (!confirm(__('You have an unsent message which will be lost if you continue. Are you sure?'))) {
|
||||
return;
|
||||
|
@ -742,7 +528,7 @@ const ChatBoxView = View.extend({
|
|||
message.save('correcting', false);
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
editLaterMessage () {
|
||||
let message;
|
||||
|
@ -764,7 +550,7 @@ const ChatBoxView = View.extend({
|
|||
} else {
|
||||
this.insertIntoTextArea('', true, false);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
editEarlierMessage () {
|
||||
let message;
|
||||
|
@ -789,15 +575,15 @@ const ChatBoxView = View.extend({
|
|||
this.insertIntoTextArea(u.prefixMentions(message), true, true);
|
||||
message.save('correcting', true);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
inputChanged (ev) {
|
||||
inputChanged (ev) { // eslint-disable-line class-methods-use-this
|
||||
const height = ev.target.scrollHeight + 'px';
|
||||
if (ev.target.style.height != height) {
|
||||
ev.target.style.height = 'auto';
|
||||
ev.target.style.height = height;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
async clearMessages (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
|
@ -808,52 +594,14 @@ const ChatBoxView = View.extend({
|
|||
await this.model.clearMessages();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Insert a particular string value into the textarea of this chat box.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#insertIntoTextArea
|
||||
* @param {string} value - The value to be inserted.
|
||||
* @param {(boolean|string)} [replace] - Whether an existing value
|
||||
* should be replaced. If set to `true`, the entire textarea will
|
||||
* be replaced with the new value. If set to a string, then only
|
||||
* that string will be replaced *if* a position is also specified.
|
||||
* @param {integer} [position] - The end index of the string to be
|
||||
* replaced with the new value.
|
||||
*/
|
||||
insertIntoTextArea (value, replace = false, correcting = false, position) {
|
||||
const textarea = this.el.querySelector('.chat-textarea');
|
||||
if (correcting) {
|
||||
u.addClass('correcting', textarea);
|
||||
} else {
|
||||
u.removeClass('correcting', textarea);
|
||||
}
|
||||
if (replace) {
|
||||
if (position && typeof replace == 'string') {
|
||||
textarea.value = textarea.value.replace(new RegExp(replace, 'g'), (match, offset) =>
|
||||
offset == position - replace.length ? value + ' ' : match
|
||||
);
|
||||
} else {
|
||||
textarea.value = value;
|
||||
}
|
||||
} else {
|
||||
let existing = textarea.value;
|
||||
if (existing && existing[existing.length - 1] !== ' ') {
|
||||
existing = existing + ' ';
|
||||
}
|
||||
textarea.value = existing + value + ' ';
|
||||
}
|
||||
this.updateCharCounter(textarea.value);
|
||||
u.placeCaretAtEnd(textarea);
|
||||
},
|
||||
}
|
||||
|
||||
onPresenceChanged (item) {
|
||||
const show = item.get('show');
|
||||
const fullname = this.model.getDisplayName();
|
||||
|
||||
let text;
|
||||
if (u.isVisible(this.el)) {
|
||||
if (u.isVisible(this)) {
|
||||
if (show === 'offline') {
|
||||
text = __('%1$s has gone offline', fullname);
|
||||
} else if (show === 'away') {
|
||||
|
@ -865,7 +613,7 @@ const ChatBoxView = View.extend({
|
|||
}
|
||||
text && this.model.createMessage({ 'message': text, 'type': 'info' });
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
async close (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
|
@ -881,7 +629,6 @@ const ChatBoxView = View.extend({
|
|||
this.model.sendChatState();
|
||||
}
|
||||
await this.model.close(ev);
|
||||
this.remove();
|
||||
/**
|
||||
* Triggered once a chatbox has been closed.
|
||||
* @event _converse#chatBoxClosed
|
||||
|
@ -890,154 +637,23 @@ const ChatBoxView = View.extend({
|
|||
*/
|
||||
api.trigger('chatBoxClosed', this);
|
||||
return this;
|
||||
},
|
||||
|
||||
emitBlurred (ev) {
|
||||
if (this.el.contains(document.activeElement) || this.el.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox is still focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been removed from a particular chat.
|
||||
* @event _converse#chatBoxBlurred
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxBlurred', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxBlurred', this, ev);
|
||||
},
|
||||
|
||||
emitFocused (ev) {
|
||||
if (this.el.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox was already focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been moved to a particular chat.
|
||||
* @event _converse#chatBoxFocused
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxFocused', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxFocused', this, ev);
|
||||
},
|
||||
|
||||
focus () {
|
||||
const textarea_el = this.el.getElementsByClassName('chat-textarea')[0];
|
||||
if (textarea_el && document.activeElement !== textarea_el) {
|
||||
textarea_el.focus();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
maybeFocus () {
|
||||
api.settings.get('auto_focus') && this.focus();
|
||||
},
|
||||
|
||||
hide () {
|
||||
this.el.classList.add('hidden');
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
afterShown () {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
this.model.setChatState(_converse.ACTIVE);
|
||||
this.scrollDown();
|
||||
this.maybeFocus();
|
||||
},
|
||||
|
||||
show () {
|
||||
if (this.model.get('hidden')) {
|
||||
log.debug(`Not showing chat ${this.model.get('jid')} because it's set as hidden`);
|
||||
return;
|
||||
}
|
||||
if (u.isVisible(this.el)) {
|
||||
this.maybeFocus();
|
||||
return;
|
||||
}
|
||||
if (api.settings.get('animate')) {
|
||||
u.fadeIn(this.el, () => this.afterShown());
|
||||
} else {
|
||||
u.showElement(this.el);
|
||||
this.afterShown();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
showNewMessagesIndicator () {
|
||||
u.showElement(this.el.querySelector('.new-msgs-indicator'));
|
||||
},
|
||||
|
||||
hideNewMessagesIndicator () {
|
||||
const new_msgs_indicator = this.el.querySelector('.new-msgs-indicator');
|
||||
if (new_msgs_indicator !== null) {
|
||||
new_msgs_indicator.classList.add('hidden');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the chat content is scrolled up or down.
|
||||
* We want to record when the user has scrolled away from
|
||||
* the bottom, so that we don't automatically scroll away
|
||||
* from what the user is reading when new messages are received.
|
||||
*
|
||||
* Don't call this method directly, instead, call `markScrolled`,
|
||||
* which debounces this method by 100ms.
|
||||
* @private
|
||||
*/
|
||||
_markScrolled: function (ev) {
|
||||
let scrolled = true;
|
||||
let scrollTop = null;
|
||||
const is_at_bottom =
|
||||
this.msgs_container.scrollTop + this.msgs_container.clientHeight >= this.msgs_container.scrollHeight - 62; // sigh...
|
||||
|
||||
if (is_at_bottom) {
|
||||
scrolled = false;
|
||||
this.onScrolledDown();
|
||||
} else if (this.msgs_container.scrollTop === 0) {
|
||||
/**
|
||||
* Triggered once the chat's message area has been scrolled to the top
|
||||
* @event _converse#chatBoxScrolledUp
|
||||
* @property { _converse.ChatBoxView | _converse.ChatRoomView } view
|
||||
* @example _converse.api.listen.on('chatBoxScrolledUp', obj => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxScrolledUp', this);
|
||||
} else {
|
||||
scrollTop = ev.target.scrollTop;
|
||||
}
|
||||
u.safeSave(this.model, { scrolled, scrollTop });
|
||||
},
|
||||
u.showElement(this.querySelector('.new-msgs-indicator'));
|
||||
}
|
||||
|
||||
viewUnreadMessages () {
|
||||
this.model.save({ 'scrolled': false, 'scrollTop': null });
|
||||
this.scrollDown();
|
||||
},
|
||||
|
||||
onScrolledDown () {
|
||||
this.hideNewMessagesIndicator();
|
||||
if (!this.model.isHidden()) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
// Clear location hash if set to one of the messages in our history
|
||||
const hash = window.location.hash;
|
||||
hash && this.model.messages.get(hash.slice(1)) && _converse.router.history.navigate();
|
||||
}
|
||||
/**
|
||||
* Triggered once the chat's message area has been scrolled down to the bottom.
|
||||
* @event _converse#chatBoxScrolledDown
|
||||
* @type {object}
|
||||
* @property { _converse.ChatBox | _converse.ChatRoom } chatbox - The chat model
|
||||
* @example _converse.api.listen.on('chatBoxScrolledDown', obj => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxScrolledDown', { 'chatbox': this.model }); // TODO: clean up
|
||||
},
|
||||
|
||||
onWindowStateChanged (state) {
|
||||
if (state === 'visible') {
|
||||
if (!this.model.isHidden() && this.model.get('num_unread', 0)) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
}
|
||||
} else if (state === 'hidden') {
|
||||
this.model.setChatState(_converse.INACTIVE, { 'silent': true });
|
||||
this.model.sendChatState();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default ChatBoxView;
|
||||
api.elements.define('converse-chat', ChatView);
|
||||
|
|
|
@ -8,7 +8,7 @@ import "../chatview/index.js";
|
|||
import ControlBoxMixin from './model.js';
|
||||
import ControlBoxPane from './pane.js';
|
||||
import ControlBoxToggle from './toggle.js';
|
||||
import ControlBoxViewMixin from './view.js';
|
||||
import ControlBoxView from './view.js';
|
||||
import log from '@converse/headless/log';
|
||||
import { LoginPanelModel, LoginPanel } from './loginpanel.js';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
@ -17,20 +17,6 @@ import controlbox_api from './api.js';
|
|||
|
||||
const u = converse.env.utils;
|
||||
|
||||
function onChatBoxViewsInitialized () {
|
||||
_converse.chatboxes.on('add', item => {
|
||||
if (item.get('type') === _converse.CONTROLBOX_TYPE) {
|
||||
const views = _converse.chatboxviews;
|
||||
const view = views.get(item.get('id'));
|
||||
if (view) {
|
||||
view.model = item;
|
||||
view.initialize();
|
||||
} else {
|
||||
views.add(item.get('id'), new _converse.ControlBoxView({ model: item }));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function disconnect () {
|
||||
/* Upon disconnection, set connected to `false`, so that if
|
||||
|
@ -96,9 +82,6 @@ converse.plugins.add('converse-controlbox', {
|
|||
},
|
||||
|
||||
initialize () {
|
||||
/* The initialize function gets called as soon as the plugin is
|
||||
* loaded by converse.js's plugin machinery.
|
||||
*/
|
||||
api.settings.extend({
|
||||
allow_logout: true,
|
||||
allow_user_trust_override: true,
|
||||
|
@ -111,15 +94,14 @@ converse.plugins.add('converse-controlbox', {
|
|||
api.promises.add('controlBoxInitialized');
|
||||
Object.assign(api, controlbox_api);
|
||||
|
||||
_converse.ControlBoxView = ControlBoxView;
|
||||
_converse.ControlBox = _converse.ChatBox.extend(ControlBoxMixin);
|
||||
_converse.ControlBoxView = _converse.ChatBoxView.extend(ControlBoxViewMixin);
|
||||
_converse.LoginPanelModel = LoginPanelModel;
|
||||
_converse.LoginPanel = LoginPanel;
|
||||
_converse.ControlBoxPane = ControlBoxPane;
|
||||
_converse.ControlBoxToggle = ControlBoxToggle;
|
||||
|
||||
/******************** Event Handlers ********************/
|
||||
api.listen.on('chatBoxViewsInitialized', onChatBoxViewsInitialized);
|
||||
api.listen.on('chatBoxesFetched', onChatBoxesFetched);
|
||||
api.listen.on('cleanup', () => delete _converse.controlboxtoggle);
|
||||
api.listen.on('clearSession', clearSession);
|
||||
|
|
|
@ -5,5 +5,9 @@ export default (o) => html`
|
|||
<div class="chat-head controlbox-head">
|
||||
${o.sticky_controlbox ? '' : html`<a class="chatbox-btn close-chatbox-button fa fa-times"></a>` }
|
||||
</div>
|
||||
<div class="controlbox-panes"></div>
|
||||
</div>`;
|
||||
<div class="controlbox-panes">
|
||||
<converse-headlines-panel></converse-headlines-panel>
|
||||
<converse-rooms-list></converse-rooms-list>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { html } from "lit-html";
|
||||
import { api } from "@converse/headless/core";
|
||||
import { __ } from 'i18n';
|
||||
import { api } from "@converse/headless/core";
|
||||
import { html } from "lit-html";
|
||||
|
||||
export default () => {
|
||||
const i18n_toggle = api.connection.connected() ? __('Chat Contacts') : __('Toggle chat');
|
||||
return html`<span class="toggle-feedback">${i18n_toggle}</span>`;
|
||||
return html`<a id="toggle-controlbox" class="toggle-controlbox"><span class="toggle-feedback">${i18n_toggle}</span></a>`;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import log from "@converse/headless/log";
|
||||
import tpl_controlbox_toggle from "./templates/toggle.js";
|
||||
import { View } from "@converse/skeletor/src/view";
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { _converse, api, converse } from "@converse/headless/core";
|
||||
import { addControlBox } from './utils.js';
|
||||
import { render } from 'lit-html';
|
||||
|
@ -8,47 +7,39 @@ import { render } from 'lit-html';
|
|||
const u = converse.env.utils;
|
||||
|
||||
|
||||
const ControlBoxToggle = View.extend({
|
||||
tagName: 'a',
|
||||
className: 'toggle-controlbox hidden',
|
||||
id: 'toggle-controlbox',
|
||||
events: {
|
||||
class ControlBoxToggle extends ElementView {
|
||||
events = {
|
||||
'click': 'onClick'
|
||||
},
|
||||
attributes: {
|
||||
'href': "#"
|
||||
},
|
||||
}
|
||||
|
||||
initialize () {
|
||||
_converse.chatboxviews.insertRowColumn(this.render().el);
|
||||
api.waitUntil('initialized')
|
||||
.then(this.render.bind(this))
|
||||
.catch(e => log.fatal(e));
|
||||
},
|
||||
async initialize () {
|
||||
await api.waitUntil('initialized');
|
||||
this.render();
|
||||
}
|
||||
|
||||
render () {
|
||||
// We let the render method of ControlBoxView decide whether
|
||||
// the ControlBox or the Toggle must be shown. This prevents
|
||||
// artifacts (i.e. on page load the toggle is shown only to then
|
||||
// seconds later be hidden in favor of the controlbox).
|
||||
render(tpl_controlbox_toggle(), this.el);
|
||||
render(tpl_controlbox_toggle(), this);
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
hide (callback) {
|
||||
if (u.isVisible(this.el)) {
|
||||
u.hideElement(this.el);
|
||||
if (u.isVisible(this)) {
|
||||
u.hideElement(this);
|
||||
callback();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
show (callback) {
|
||||
if (!u.isVisible(this.el)) {
|
||||
u.fadeIn(this.el, callback);
|
||||
if (!u.isVisible(this)) {
|
||||
u.fadeIn(this, callback);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
showControlBox () {
|
||||
showControlBox () { // eslint-disable-line class-methods-use-this
|
||||
let controlbox = _converse.chatboxes.get('controlbox');
|
||||
if (!controlbox) {
|
||||
controlbox = addControlBox();
|
||||
|
@ -58,7 +49,7 @@ const ControlBoxToggle = View.extend({
|
|||
} else {
|
||||
controlbox.trigger('show');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onClick (e) {
|
||||
e.preventDefault();
|
||||
|
@ -73,6 +64,8 @@ const ControlBoxToggle = View.extend({
|
|||
this.showControlBox();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
api.elements.define('converse-controlbox-toggle', ControlBoxToggle);
|
||||
|
||||
export default ControlBoxToggle;
|
||||
|
|
|
@ -1,38 +1,27 @@
|
|||
import tpl_controlbox from './templates/controlbox.js';
|
||||
import { render } from 'lit-html';
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
import { render } from 'lit-html';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
||||
/**
|
||||
* Mixin which turns a ChatBoxView into a ControlBoxView.
|
||||
*
|
||||
* The ControlBox is the section of the chat that contains the open groupchats,
|
||||
* bookmarks and roster.
|
||||
*
|
||||
* In `overlayed` `view_mode` it's a box like the chat boxes, in `fullscreen`
|
||||
* `view_mode` it's a left-aligned sidebar.
|
||||
* @mixin
|
||||
*/
|
||||
const ControlBoxViewMixin = {
|
||||
tagName: 'div',
|
||||
className: 'chatbox',
|
||||
id: 'controlbox',
|
||||
events: {
|
||||
class ControlBoxView extends ElementView {
|
||||
events = {
|
||||
'click a.close-chatbox-button': 'close'
|
||||
},
|
||||
}
|
||||
|
||||
initialize () {
|
||||
if (_converse.controlboxtoggle === undefined) {
|
||||
_converse.controlboxtoggle = new _converse.ControlBoxToggle();
|
||||
}
|
||||
_converse.controlboxtoggle.el.insertAdjacentElement('afterend', this.el);
|
||||
|
||||
this.model = _converse.chatboxes.get(this.getAttribute('id'));
|
||||
this.listenTo(this.model, 'change:connected', this.onConnected);
|
||||
this.listenTo(this.model, 'destroy', this.hide);
|
||||
this.listenTo(this.model, 'hide', this.hide);
|
||||
// this.listenTo(this.model, 'hide', this.hide);
|
||||
this.listenTo(this.model, 'show', this.show);
|
||||
this.listenTo(this.model, 'change:closed', this.ensureClosedState);
|
||||
this.render();
|
||||
/**
|
||||
* Triggered when the _converse.ControlBoxView has been initialized and therefore
|
||||
|
@ -43,9 +32,11 @@ const ControlBoxViewMixin = {
|
|||
* @example _converse.api.listen.on('controlBoxInitialized', view => { ... });
|
||||
*/
|
||||
api.trigger('controlBoxInitialized', this);
|
||||
},
|
||||
}
|
||||
|
||||
render () {
|
||||
_converse.chatboxviews.add('controlbox', this);
|
||||
|
||||
if (this.model.get('connected')) {
|
||||
if (this.model.get('closed') === undefined) {
|
||||
this.model.set('closed', !api.settings.get('show_controlbox_by_default'));
|
||||
|
@ -56,13 +47,7 @@ const ControlBoxViewMixin = {
|
|||
'sticky_controlbox': api.settings.get('sticky_controlbox'),
|
||||
...this.model.toJSON()
|
||||
});
|
||||
render(tpl_result, this.el);
|
||||
|
||||
if (!this.model.get('closed')) {
|
||||
this.show();
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
render(tpl_result, this);
|
||||
|
||||
const connection = _converse?.connection || {};
|
||||
if (!connection.connected || !connection.authenticated || connection.disconnecting) {
|
||||
|
@ -71,29 +56,29 @@ const ControlBoxViewMixin = {
|
|||
this.renderControlBoxPane();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
onConnected () {
|
||||
if (this.model.get('connected')) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
renderLoginPanel () {
|
||||
this.el.classList.add('logged-out');
|
||||
this.classList.add('logged-out');
|
||||
if (this.loginpanel) {
|
||||
this.loginpanel.render();
|
||||
} else {
|
||||
this.loginpanel = new _converse.LoginPanel({
|
||||
'model': new _converse.LoginPanelModel()
|
||||
});
|
||||
const panes = this.el.querySelector('.controlbox-panes');
|
||||
const panes = this.querySelector('.controlbox-panes');
|
||||
panes.innerHTML = '';
|
||||
panes.appendChild(this.loginpanel.render().el);
|
||||
}
|
||||
this.loginpanel.initPopovers();
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the "Contacts" panel of the controlbox.
|
||||
|
@ -109,12 +94,12 @@ const ControlBoxViewMixin = {
|
|||
if (this.controlbox_pane && u.isVisible(this.controlbox_pane.el)) {
|
||||
return;
|
||||
}
|
||||
this.el.classList.remove('logged-out');
|
||||
this.classList.remove('logged-out');
|
||||
this.controlbox_pane = new _converse.ControlBoxPane();
|
||||
this.el
|
||||
this
|
||||
.querySelector('.controlbox-panes')
|
||||
.insertAdjacentElement('afterBegin', this.controlbox_pane.el);
|
||||
},
|
||||
}
|
||||
|
||||
async close (ev) {
|
||||
if (ev && ev.preventDefault) {
|
||||
|
@ -143,48 +128,42 @@ const ControlBoxViewMixin = {
|
|||
}
|
||||
api.trigger('controlBoxClosed', this);
|
||||
return this;
|
||||
},
|
||||
|
||||
ensureClosedState () {
|
||||
if (this.model.get('closed')) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
hide (callback) {
|
||||
if (api.settings.get('sticky_controlbox')) {
|
||||
return;
|
||||
}
|
||||
u.addClass('hidden', this.el);
|
||||
u.addClass('hidden', this);
|
||||
api.trigger('chatBoxClosed', this);
|
||||
if (!api.connection.connected()) {
|
||||
_converse.controlboxtoggle.render();
|
||||
}
|
||||
_converse.controlboxtoggle.show(callback);
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
onControlBoxToggleHidden () {
|
||||
this.model.set('closed', false);
|
||||
this.el.classList.remove('hidden');
|
||||
this.classList.remove('hidden');
|
||||
/**
|
||||
* Triggered once the controlbox has been opened
|
||||
* @event _converse#controlBoxOpened
|
||||
* @type {_converse.ControlBox}
|
||||
*/
|
||||
api.trigger('controlBoxOpened', this);
|
||||
},
|
||||
}
|
||||
|
||||
show () {
|
||||
_converse.controlboxtoggle.hide(() => this.onControlBoxToggleHidden());
|
||||
return this;
|
||||
},
|
||||
}
|
||||
|
||||
showHelpMessages () {
|
||||
showHelpMessages () { // eslint-disable-line class-methods-use-this
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default ControlBoxViewMixin;
|
||||
api.elements.define('converse-controlbox', ControlBoxView);
|
||||
|
||||
export default ControlBoxView;
|
||||
|
|
|
@ -126,6 +126,8 @@ converse.plugins.add('converse-dragresize', {
|
|||
});
|
||||
|
||||
Object.assign(_converse.ChatBoxView.prototype, DragResizableMixin);
|
||||
Object.assign(_converse.ChatRoomView.prototype, DragResizableMixin);
|
||||
Object.assign(_converse.ControlBoxView.prototype, DragResizableMixin);
|
||||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
function registerGlobalEventHandlers () {
|
||||
|
|
|
@ -11,7 +11,7 @@ const DragResizableMixin = {
|
|||
|
||||
// Determine and store the default box size.
|
||||
// We need this information for the drag-resizing feature.
|
||||
const flyout = this.el.querySelector('.box-flyout');
|
||||
const flyout = this.querySelector('.box-flyout');
|
||||
const style = window.getComputedStyle(flyout);
|
||||
|
||||
if (this.model.get('height') === undefined) {
|
||||
|
@ -66,7 +66,7 @@ const DragResizableMixin = {
|
|||
// If a custom width is applied (due to drag-resizing),
|
||||
// then we need to set the width of the .chatbox element as well.
|
||||
if (this.model.get('width')) {
|
||||
this.el.style.width = this.model.get('width');
|
||||
this.style.width = this.model.get('width');
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -83,7 +83,7 @@ const DragResizableMixin = {
|
|||
} else {
|
||||
height = '';
|
||||
}
|
||||
const flyout_el = this.el.querySelector('.box-flyout');
|
||||
const flyout_el = this.querySelector('.box-flyout');
|
||||
if (flyout_el !== null) {
|
||||
flyout_el.style.height = height;
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ const DragResizableMixin = {
|
|||
} else {
|
||||
width = '';
|
||||
}
|
||||
this.el.style.width = width;
|
||||
const flyout_el = this.el.querySelector('.box-flyout');
|
||||
this.style.width = width;
|
||||
const flyout_el = this.querySelector('.box-flyout');
|
||||
if (flyout_el !== null) {
|
||||
flyout_el.style.width = width;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ const DragResizableMixin = {
|
|||
}
|
||||
ev.preventDefault();
|
||||
// Record element attributes for mouseMove().
|
||||
const flyout = this.el.querySelector('.box-flyout'),
|
||||
const flyout = this.querySelector('.box-flyout'),
|
||||
style = window.getComputedStyle(flyout);
|
||||
this.height = parseInt(style.height.replace(/px$/, ''), 10);
|
||||
_converse.resizing = {
|
||||
|
@ -147,8 +147,8 @@ const DragResizableMixin = {
|
|||
return true;
|
||||
}
|
||||
ev.preventDefault();
|
||||
const flyout = this.el.querySelector('.box-flyout'),
|
||||
style = window.getComputedStyle(flyout);
|
||||
const flyout = this.querySelector('.box-flyout');
|
||||
const style = window.getComputedStyle(flyout);
|
||||
this.width = parseInt(style.width.replace(/px$/, ''), 10);
|
||||
_converse.resizing = {
|
||||
'chatbox': this,
|
||||
|
|
|
@ -23,8 +23,8 @@ export function applyDragResistance (value, default_value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
export function renderDragResizeHandles (_converse, view) {
|
||||
const flyout = view.el.querySelector('.box-flyout');
|
||||
export function renderDragResizeHandles (_converse, el) {
|
||||
const flyout = el.querySelector('.box-flyout');
|
||||
const div = document.createElement('div');
|
||||
render(tpl_dragresize(), div);
|
||||
flyout.insertBefore(div, flyout.firstChild);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import '../chatview/index.js';
|
||||
import HeadlinesBoxViewMixin from './view.js';
|
||||
import { HeadlinesPanelMixin, HeadlinesPanelView } from './panel.js';
|
||||
import { HeadlinesPanelMixin, HeadlinesPanel} from './panel.js';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
||||
function onChatBoxViewsInitialized () {
|
||||
|
@ -45,7 +45,7 @@ converse.plugins.add('converse-headlines-view', {
|
|||
*/
|
||||
_converse.ControlBoxView && Object.assign(_converse.ControlBoxView.prototype, HeadlinesPanelMixin);
|
||||
_converse.HeadlinesBoxView = _converse.ChatBoxView.extend(HeadlinesBoxViewMixin);
|
||||
_converse.HeadlinesPanel = HeadlinesPanelView;
|
||||
_converse.HeadlinesPanel = HeadlinesPanel;
|
||||
|
||||
api.listen.on('chatBoxViewsInitialized', onChatBoxViewsInitialized);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import tpl_headline_panel from './templates/panel.js';
|
||||
import { View } from '@converse/skeletor/src/view.js';
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
||||
|
@ -11,22 +11,20 @@ const u = converse.env.utils;
|
|||
* @namespace _converse.HeadlinesPanel
|
||||
* @memberOf _converse
|
||||
*/
|
||||
export const HeadlinesPanelView = View.extend({
|
||||
tagName: 'div',
|
||||
className: 'controlbox-section',
|
||||
id: 'headline',
|
||||
|
||||
events: {
|
||||
export class HeadlinesPanel extends ElementView {
|
||||
tagName = 'div'
|
||||
className = 'controlbox-section'
|
||||
id = 'headline'
|
||||
events = {
|
||||
'click .open-headline': 'openHeadline'
|
||||
},
|
||||
}
|
||||
|
||||
initialize () {
|
||||
this.listenTo(this.model, 'add', this.renderIfHeadline);
|
||||
this.listenTo(this.model, 'remove', this.renderIfHeadline);
|
||||
this.listenTo(this.model, 'destroy', this.renderIfHeadline);
|
||||
this.render();
|
||||
this.insertIntoDOM();
|
||||
},
|
||||
}
|
||||
|
||||
toHTML () {
|
||||
return tpl_headline_panel({
|
||||
|
@ -34,24 +32,21 @@ export const HeadlinesPanelView = View.extend({
|
|||
'headlineboxes': this.model.filter(m => m.get('type') === _converse.HEADLINES_TYPE),
|
||||
'open_title': __('Click to open this server message')
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
renderIfHeadline (model) {
|
||||
return model && model.get('type') === _converse.HEADLINES_TYPE && this.render();
|
||||
},
|
||||
}
|
||||
|
||||
openHeadline (ev) {
|
||||
openHeadline (ev) { // eslint-disable-line class-methods-use-this
|
||||
ev.preventDefault();
|
||||
const jid = ev.target.getAttribute('data-headline-jid');
|
||||
const chat = _converse.chatboxes.get(jid);
|
||||
chat.maybeShow(true);
|
||||
},
|
||||
|
||||
insertIntoDOM () {
|
||||
const view = _converse.chatboxviews.get('controlbox');
|
||||
view && view.el.querySelector('.controlbox-pane').insertAdjacentElement('beforeEnd', this.el);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
api.elements.define('converse-headlines-panel', HeadlinesPanel);
|
||||
|
||||
/**
|
||||
* Mixin for the {@link _converse.ControlBoxView } which add support for
|
||||
|
|
|
@ -13,8 +13,14 @@ const HeadlinesBoxViewMixin = {
|
|||
},
|
||||
|
||||
async initialize () {
|
||||
const jid = this.getAttribute('jid');
|
||||
_converse.chatboxviews.add(jid, this);
|
||||
|
||||
this.model = _converse.chatboxes.get(jid);
|
||||
this.initDebounced();
|
||||
|
||||
api.listen.on('windowStateChanged', this.onWindowStateChanged);
|
||||
|
||||
this.model.disable_mam = true; // Don't do MAM queries for this box
|
||||
this.listenTo(this.model, 'change:hidden', m => (m.get('hidden') ? this.hide() : this.show()));
|
||||
this.listenTo(this.model, 'destroy', this.remove);
|
||||
|
|
|
@ -125,7 +125,8 @@ converse.plugins.add('converse-minimize', {
|
|||
|
||||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
api.listen.on('chatBoxInsertedIntoDOM', view => _converse.minimize.trimChats(view));
|
||||
api.listen.on('chatBoxViewInitialized', view => _converse.minimize.trimChats(view));
|
||||
api.listen.on('chatRoomViewInitialized', view => _converse.minimize.trimChats(view));
|
||||
api.listen.on('connected', () => initMinimizedChats());
|
||||
api.listen.on('controlBoxOpened', view => _converse.minimize.trimChats(view));
|
||||
api.listen.on('chatBoxViewInitialized', v => v.listenTo(v.model, 'change:minimized', v.onMinimizedChanged));
|
||||
|
|
|
@ -66,7 +66,6 @@ export const minimizableChatBoxView = {
|
|||
this.model.set({ 'scroll': this.content.scrollTop });
|
||||
}
|
||||
this.model.setChatState(_converse.INACTIVE);
|
||||
this.hide();
|
||||
/**
|
||||
* Triggered when a previously maximized chat gets Minimized
|
||||
* @event _converse#chatBoxMinimized
|
||||
|
|
|
@ -6,28 +6,24 @@ const u = converse.env.utils;
|
|||
|
||||
function getChatBoxWidth (view) {
|
||||
if (view.model.get('id') === 'controlbox') {
|
||||
const controlbox = view.model;
|
||||
// We return the width of the controlbox or its toggle,
|
||||
// depending on which is visible.
|
||||
if (u.isVisible(controlbox.el)) {
|
||||
return u.getOuterWidth(controlbox.el, true);
|
||||
if (u.isVisible(view)) {
|
||||
return u.getOuterWidth(view, true);
|
||||
} else {
|
||||
return u.getOuterWidth(_converse.controlboxtoggle.el, true);
|
||||
}
|
||||
} else if (!view.model.get('minimized') && u.isVisible(view.el)) {
|
||||
return u.getOuterWidth(view.el, true);
|
||||
} else if (!view.model.get('minimized') && u.isVisible(view)) {
|
||||
return u.getOuterWidth(view, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getShownChats () {
|
||||
return _converse.chatboxviews.filter((view) =>
|
||||
return _converse.chatboxviews.filter(el =>
|
||||
// The controlbox can take a while to close,
|
||||
// so we need to check its state. That's why we checked
|
||||
// the 'closed' state.
|
||||
!view.model.get('minimized') &&
|
||||
!view.model.get('closed') &&
|
||||
u.isVisible(view.el)
|
||||
// so we need to check its state. That's why we checked the 'closed' state.
|
||||
!el.model.get('minimized') && !el.model.get('closed') && u.isVisible(el)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import '../../components/muc-sidebar';
|
||||
import '../chatview/index.js';
|
||||
import '../modal.js';
|
||||
import ChatRoomViewMixin from './muc.js';
|
||||
import MUCView from './muc.js';
|
||||
import MUCConfigForm from './config-form.js';
|
||||
import MUCPasswordForm from './password-form.js';
|
||||
import log from '@converse/headless/log';
|
||||
|
@ -60,18 +60,10 @@ function fetchAndSetMUCDomain (controlboxview) {
|
|||
}
|
||||
}
|
||||
|
||||
function openChatRoomFromURIClicked (ev) {
|
||||
ev.preventDefault();
|
||||
api.rooms.open(ev.target.href);
|
||||
}
|
||||
|
||||
async function addView (model) {
|
||||
const views = _converse.chatboxviews;
|
||||
if (!views.get(model.get('id')) && model.get('type') === _converse.CHATROOMS_TYPE && model.isValid()) {
|
||||
await model.initialized;
|
||||
return views.add(model.get('id'), new _converse.ChatRoomView({ model }));
|
||||
}
|
||||
}
|
||||
// function openChatRoomFromURIClicked (ev) {
|
||||
// ev.preventDefault();
|
||||
// api.rooms.open(ev.target.href);
|
||||
// }
|
||||
|
||||
converse.plugins.add('converse-muc-views', {
|
||||
/* Dependencies are other plugins which might be
|
||||
|
@ -129,7 +121,7 @@ converse.plugins.add('converse-muc-views', {
|
|||
|
||||
_converse.MUCConfigForm = MUCConfigForm;
|
||||
_converse.MUCPasswordForm = MUCPasswordForm;
|
||||
_converse.ChatRoomView = _converse.ChatBoxView.extend(ChatRoomViewMixin);
|
||||
_converse.ChatRoomView = MUCView;
|
||||
_converse.RoomsPanel = RoomsPanel;
|
||||
_converse.ControlBoxView && Object.assign(_converse.ControlBoxView.prototype, RoomsPanelViewMixin);
|
||||
|
||||
|
@ -137,8 +129,11 @@ converse.plugins.add('converse-muc-views', {
|
|||
|
||||
/************************ BEGIN Event Handlers ************************/
|
||||
api.listen.on('chatBoxViewsInitialized', () => {
|
||||
_converse.chatboxviews.delegate('click', 'a.open-chatroom', openChatRoomFromURIClicked);
|
||||
_converse.chatboxes.on('add', addView);
|
||||
// FIXME: Find a new way to implement this
|
||||
// _converse.chatboxviews.delegate('click', 'a.open-chatroom', openChatRoomFromURIClicked);
|
||||
|
||||
// TODO: Remove
|
||||
// _converse.chatboxes.on('add', addView);
|
||||
});
|
||||
|
||||
api.listen.on('clearSession', () => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import './config-form.js';
|
||||
import './password-form.js';
|
||||
import 'shared/autocomplete/index.js';
|
||||
import BaseChatView from 'shared/chatview.js';
|
||||
import MUCInviteModal from 'modals/muc-invite.js';
|
||||
import ModeratorToolsModal from 'modals/moderator-tools.js';
|
||||
import OccupantModal from 'modals/occupant.js';
|
||||
|
@ -11,9 +12,9 @@ import tpl_chatroom_head from 'templates/chatroom_head.js';
|
|||
import tpl_muc_bottom_panel from 'templates/muc_bottom_panel.js';
|
||||
import tpl_muc_destroyed from 'templates/muc_destroyed.js';
|
||||
import tpl_muc_disconnect from 'templates/muc_disconnect.js';
|
||||
import { $pres, Strophe } from 'strophe.js/src/strophe';
|
||||
import tpl_muc_nickname_form from 'templates/muc_nickname_form.js';
|
||||
import tpl_spinner from 'templates/spinner.js';
|
||||
import { $pres, Strophe } from 'strophe.js/src/strophe';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { __ } from 'i18n';
|
||||
import { _converse, api, converse } from '@converse/headless/core';
|
||||
|
@ -49,12 +50,12 @@ const COMMAND_TO_AFFILIATION = {
|
|||
* @namespace _converse.ChatRoomView
|
||||
* @memberOf _converse
|
||||
*/
|
||||
const ChatRoomViewMixin = {
|
||||
length: 300,
|
||||
tagName: 'div',
|
||||
className: 'chatbox chatroom hidden',
|
||||
is_chatroom: true,
|
||||
events: {
|
||||
export default class MUCView extends BaseChatView {
|
||||
length = 300
|
||||
tagName = 'div'
|
||||
className = 'chatbox chatroom hidden'
|
||||
is_chatroom = true
|
||||
events = {
|
||||
'click .chatbox-navback': 'showControlBox',
|
||||
'click .hide-occupants': 'hideOccupants',
|
||||
'click .new-msgs-indicator': 'viewUnreadMessages',
|
||||
|
@ -71,21 +72,25 @@ const ChatRoomViewMixin = {
|
|||
'mousedown .dragresize-occupants-left': 'onStartResizeOccupants',
|
||||
'paste .chat-textarea': 'onPaste',
|
||||
'submit .muc-nickname-form': 'submitNickname'
|
||||
},
|
||||
}
|
||||
|
||||
async initialize () {
|
||||
const jid = this.getAttribute('jid');
|
||||
_converse.chatboxviews.add(jid, this);
|
||||
|
||||
this.model = _converse.chatboxes.get(jid);
|
||||
this.initDebounced();
|
||||
|
||||
api.listen.on('windowStateChanged', this.onWindowStateChanged);
|
||||
|
||||
this.listenTo(
|
||||
this.model,
|
||||
'change',
|
||||
debounce(() => this.renderHeading(), 250)
|
||||
);
|
||||
this.listenTo(this.model, 'change:composing_spoiler', this.renderMessageForm);
|
||||
this.listenTo(this.model, 'change:hidden', m => (m.get('hidden') ? this.hide() : this.show()));
|
||||
this.listenTo(this.model, 'change:hidden_occupants', this.onSidebarToggle);
|
||||
this.listenTo(this.model, 'configurationNeeded', this.getAndRenderConfigurationForm);
|
||||
this.listenTo(this.model, 'destroy', this.hide);
|
||||
this.listenTo(this.model, 'show', this.show);
|
||||
this.listenTo(this.model.features, 'change:moderated', this.renderBottomPanel);
|
||||
this.listenTo(this.model.features, 'change:open', this.renderHeading);
|
||||
|
@ -115,7 +120,6 @@ const ChatRoomViewMixin = {
|
|||
this.listenTo(this.model.occupants, 'remove', this.onOccupantRemoved);
|
||||
|
||||
this.renderChatContent();
|
||||
this.insertIntoDOM();
|
||||
// Register later due to await
|
||||
const user_settings = await _converse.api.user.settings.getModel();
|
||||
this.listenTo(user_settings, 'change:mucs_with_hidden_subject', this.renderHeading);
|
||||
|
@ -129,11 +133,11 @@ const ChatRoomViewMixin = {
|
|||
* @example _converse.api.listen.on('chatRoomViewInitialized', view => { ... });
|
||||
*/
|
||||
api.trigger('chatRoomViewInitialized', this);
|
||||
},
|
||||
}
|
||||
|
||||
async render () {
|
||||
const sidebar_hidden = !this.shouldShowSidebar();
|
||||
this.el.setAttribute('id', this.model.get('box_id'));
|
||||
this.setAttribute('id', this.model.get('box_id'));
|
||||
render(
|
||||
tpl_chatroom({
|
||||
sidebar_hidden,
|
||||
|
@ -146,13 +150,13 @@ const ChatRoomViewMixin = {
|
|||
'muc_show_logs_before_join': api.settings.get('muc_show_logs_before_join'),
|
||||
'show_send_button': _converse.show_send_button
|
||||
}),
|
||||
this.el
|
||||
this
|
||||
);
|
||||
|
||||
this.notifications = this.el.querySelector('.chat-content__notifications');
|
||||
this.content = this.el.querySelector('.chat-content');
|
||||
this.msgs_container = this.el.querySelector('.chat-content__messages');
|
||||
this.help_container = this.el.querySelector('.chat-content__help');
|
||||
this.notifications = this.querySelector('.chat-content__notifications');
|
||||
this.content = this.querySelector('.chat-content');
|
||||
this.msgs_container = this.querySelector('.chat-content__messages');
|
||||
this.help_container = this.querySelector('.chat-content__help');
|
||||
|
||||
this.renderBottomPanel();
|
||||
if (
|
||||
|
@ -166,7 +170,7 @@ const ChatRoomViewMixin = {
|
|||
// Otherwise e.g. this.notifications is not yet defined when accessed elsewhere.
|
||||
await this.renderHeading();
|
||||
!this.model.get('hidden') && this.show();
|
||||
},
|
||||
}
|
||||
|
||||
getNotifications () {
|
||||
const actors_per_state = this.model.notifications.toJSON();
|
||||
|
@ -240,7 +244,7 @@ const ChatRoomViewMixin = {
|
|||
}
|
||||
return result;
|
||||
}, '');
|
||||
},
|
||||
}
|
||||
|
||||
getHelpMessages () {
|
||||
const setting = api.settings.get('muc_disable_slash_commands');
|
||||
|
@ -269,7 +273,7 @@ const ChatRoomViewMixin = {
|
|||
]
|
||||
.filter(line => disabled_commands.every(c => !line.startsWith(c + '<', 9)))
|
||||
.filter(line => this.getAllowedCommands().some(c => line.startsWith(c + '<', 9)));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the MUC heading if any relevant attributes have changed.
|
||||
|
@ -279,11 +283,11 @@ const ChatRoomViewMixin = {
|
|||
*/
|
||||
async renderHeading () {
|
||||
const tpl = await this.generateHeadingTemplate();
|
||||
render(tpl, this.el.querySelector('.chat-head-chatroom'));
|
||||
},
|
||||
render(tpl, this.querySelector('.chat-head-chatroom'));
|
||||
}
|
||||
|
||||
renderBottomPanel () {
|
||||
const container = this.el.querySelector('.bottom-panel');
|
||||
const container = this.querySelector('.bottom-panel');
|
||||
const entered = this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
|
||||
const can_edit = entered && !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
|
||||
render(tpl_muc_bottom_panel({ can_edit, entered }), container);
|
||||
|
@ -291,18 +295,18 @@ const ChatRoomViewMixin = {
|
|||
this.renderMessageForm();
|
||||
this.initMentionAutoComplete();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onStartResizeOccupants (ev) {
|
||||
this.resizing = true;
|
||||
this.el.addEventListener('mousemove', this.onMouseMove);
|
||||
this.el.addEventListener('mouseup', this.onMouseUp);
|
||||
this.addEventListener('mousemove', this.onMouseMove);
|
||||
this.addEventListener('mouseup', this.onMouseUp);
|
||||
|
||||
const sidebar_el = this.el.querySelector('converse-muc-sidebar');
|
||||
const sidebar_el = this.querySelector('converse-muc-sidebar');
|
||||
const style = window.getComputedStyle(sidebar_el);
|
||||
this.width = parseInt(style.width.replace(/px$/, ''), 10);
|
||||
this.prev_pageX = ev.pageX;
|
||||
},
|
||||
}
|
||||
|
||||
onMouseMove (ev) {
|
||||
if (this.resizing) {
|
||||
|
@ -311,24 +315,24 @@ const ChatRoomViewMixin = {
|
|||
this.resizeSidebarView(delta, ev.pageX);
|
||||
this.prev_pageX = ev.pageX;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onMouseUp (ev) {
|
||||
if (this.resizing) {
|
||||
ev.preventDefault();
|
||||
this.resizing = false;
|
||||
this.el.removeEventListener('mousemove', this.onMouseMove);
|
||||
this.el.removeEventListener('mouseup', this.onMouseUp);
|
||||
const sidebar_el = this.el.querySelector('converse-muc-sidebar');
|
||||
this.removeEventListener('mousemove', this.onMouseMove);
|
||||
this.removeEventListener('mouseup', this.onMouseUp);
|
||||
const sidebar_el = this.querySelector('converse-muc-sidebar');
|
||||
const element_position = sidebar_el.getBoundingClientRect();
|
||||
const occupants_width = this.calculateSidebarWidth(element_position, 0);
|
||||
const attrs = { occupants_width };
|
||||
_converse.connection.connected ? this.model.save(attrs) : this.model.set(attrs);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
resizeSidebarView (delta, current_mouse_position) {
|
||||
const sidebar_el = this.el.querySelector('converse-muc-sidebar');
|
||||
const sidebar_el = this.querySelector('converse-muc-sidebar');
|
||||
const element_position = sidebar_el.getBoundingClientRect();
|
||||
if (this.is_minimum) {
|
||||
this.is_minimum = element_position.left < current_mouse_position;
|
||||
|
@ -338,11 +342,11 @@ const ChatRoomViewMixin = {
|
|||
const occupants_width = this.calculateSidebarWidth(element_position, delta);
|
||||
sidebar_el.style.flex = '0 0 ' + occupants_width + 'px';
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
calculateSidebarWidth (element_position, delta) {
|
||||
let occupants_width = element_position.width + delta;
|
||||
const room_width = this.el.clientWidth;
|
||||
const room_width = this.clientWidth;
|
||||
// keeping display in boundaries
|
||||
if (occupants_width < room_width * 0.2) {
|
||||
// set pixel to 20% width
|
||||
|
@ -361,13 +365,13 @@ const ChatRoomViewMixin = {
|
|||
this.is_minimum = false;
|
||||
}
|
||||
return occupants_width;
|
||||
},
|
||||
}
|
||||
|
||||
getAutoCompleteList () {
|
||||
return this.model.getAllKnownNicknames().map(nick => ({ 'label': nick, 'value': `@${nick}` }));
|
||||
},
|
||||
}
|
||||
|
||||
getAutoCompleteListItem (text, input) {
|
||||
getAutoCompleteListItem (text, input) { // eslint-disable-line class-methods-use-this
|
||||
input = input.trim();
|
||||
const element = document.createElement('li');
|
||||
element.setAttribute('aria-selected', 'false');
|
||||
|
@ -401,10 +405,10 @@ const ChatRoomViewMixin = {
|
|||
});
|
||||
|
||||
return element;
|
||||
},
|
||||
}
|
||||
|
||||
initMentionAutoComplete () {
|
||||
this.mention_auto_complete = new _converse.AutoComplete(this.el, {
|
||||
this.mention_auto_complete = new _converse.AutoComplete(this, {
|
||||
'auto_first': true,
|
||||
'auto_evaluate': false,
|
||||
'min_chars': api.settings.get('muc_mention_autocomplete_min_chars'),
|
||||
|
@ -419,7 +423,7 @@ const ChatRoomViewMixin = {
|
|||
'item': this.getAutoCompleteListItem
|
||||
});
|
||||
this.mention_auto_complete.on('suggestion-box-selectcomplete', () => (this.auto_completing = false));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nickname value from the form and then join the groupchat with it.
|
||||
|
@ -431,19 +435,19 @@ const ChatRoomViewMixin = {
|
|||
ev.preventDefault();
|
||||
const nick = ev.target.nick.value.trim();
|
||||
nick && this.model.join(nick);
|
||||
},
|
||||
}
|
||||
|
||||
onKeyDown (ev) {
|
||||
if (this.mention_auto_complete.onKeyDown(ev)) {
|
||||
return;
|
||||
}
|
||||
return _converse.ChatBoxView.prototype.onKeyDown.call(this, ev);
|
||||
},
|
||||
}
|
||||
|
||||
onKeyUp (ev) {
|
||||
this.mention_auto_complete.evaluate(ev);
|
||||
return _converse.ChatBoxView.prototype.onKeyUp.call(this, ev);
|
||||
},
|
||||
}
|
||||
|
||||
async onMessageRetractButtonClicked (message) {
|
||||
const retraction_warning = __(
|
||||
|
@ -480,7 +484,7 @@ const ChatRoomViewMixin = {
|
|||
const err_msg = __(`Sorry, you're not allowed to retract this message`);
|
||||
api.alert('error', __('Error'), err_msg);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Retract someone else's message in this groupchat.
|
||||
|
@ -501,7 +505,7 @@ const ChatRoomViewMixin = {
|
|||
log(err_msg, Strophe.LogLevel.WARN);
|
||||
log(result, Strophe.LogLevel.WARN);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
showModeratorToolsModal (affiliation) {
|
||||
if (!this.verifyRoles(['moderator'])) {
|
||||
|
@ -515,48 +519,48 @@ const ChatRoomViewMixin = {
|
|||
modal = api.modal.create(ModeratorToolsModal, { model, _converse, 'chatroomview': this });
|
||||
}
|
||||
modal.show();
|
||||
},
|
||||
}
|
||||
|
||||
showRoomDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(RoomDetailsModal, { 'model': this.model }, ev);
|
||||
},
|
||||
}
|
||||
|
||||
showOccupantDetailsModal (ev, message) {
|
||||
showOccupantDetailsModal (ev, message) { // eslint-disable-line class-methods-use-this
|
||||
ev.preventDefault();
|
||||
api.modal.show(OccupantModal, { 'model': message.occupant }, ev);
|
||||
},
|
||||
}
|
||||
|
||||
showChatStateNotification (message) {
|
||||
if (message.get('sender') === 'me') {
|
||||
return;
|
||||
}
|
||||
return _converse.ChatBoxView.prototype.showChatStateNotification.apply(this, arguments);
|
||||
},
|
||||
}
|
||||
|
||||
shouldShowSidebar () {
|
||||
return (
|
||||
!this.model.get('hidden_occupants') &&
|
||||
this.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
onSidebarToggle () {
|
||||
this.renderToolbar();
|
||||
this.el.querySelector('.occupants')?.setVisibility();
|
||||
},
|
||||
this.querySelector('.occupants')?.setVisibility();
|
||||
}
|
||||
|
||||
onOccupantAffiliationChanged (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderHeading();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onOccupantRoleChanged (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderBottomPanel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of objects which represent buttons for the groupchat header.
|
||||
|
@ -653,7 +657,7 @@ const ChatRoomViewMixin = {
|
|||
});
|
||||
}
|
||||
return _converse.api.hook('getHeadingButtons', this, buttons);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the groupchat heading TemplateResult to be rendered.
|
||||
|
@ -674,16 +678,16 @@ const ChatRoomViewMixin = {
|
|||
'title': this.model.getDisplayName()
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
toggleTopic () {
|
||||
this.model.toggleSubjectHiddenState();
|
||||
},
|
||||
}
|
||||
|
||||
showInviteModal (ev) {
|
||||
ev.preventDefault();
|
||||
api.modal.show(MUCInviteModal, { 'model': new Model(), 'chatroomview': this }, ev);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method that gets called after the chat has become visible.
|
||||
|
@ -696,7 +700,7 @@ const ChatRoomViewMixin = {
|
|||
// This is instead done in `onConnectionStatusChanged` below.
|
||||
this.model.clearUnreadMsgCounter();
|
||||
this.scrollDown();
|
||||
},
|
||||
}
|
||||
|
||||
onConnectionStatusChanged () {
|
||||
const conn_status = this.model.session.get('connection_status');
|
||||
|
@ -715,7 +719,7 @@ const ChatRoomViewMixin = {
|
|||
} else if (conn_status === converse.ROOMSTATUS.DESTROYED) {
|
||||
this.showDestroyedMessage();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
getToolbarOptions () {
|
||||
return Object.assign(_converse.ChatBoxView.prototype.getToolbarOptions.apply(this, arguments), {
|
||||
|
@ -723,7 +727,7 @@ const ChatRoomViewMixin = {
|
|||
'label_hide_occupants': __('Hide the list of participants'),
|
||||
'show_occupants_toggle': _converse.visible_toolbar_buttons.toggle_occupants
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this chat box, which implies leaving the groupchat as well.
|
||||
|
@ -731,12 +735,11 @@ const ChatRoomViewMixin = {
|
|||
* @method _converse.ChatRoomView#close
|
||||
*/
|
||||
close () {
|
||||
this.hide();
|
||||
if (_converse.router.history.getFragment() === 'converse/room?jid=' + this.model.get('jid')) {
|
||||
_converse.router.navigate('');
|
||||
}
|
||||
return _converse.ChatBoxView.prototype.close.apply(this, arguments);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the right sidebar containing the chat occupants.
|
||||
|
@ -750,7 +753,7 @@ const ChatRoomViewMixin = {
|
|||
}
|
||||
this.model.save({ 'hidden_occupants': true });
|
||||
this.scrollDown();
|
||||
},
|
||||
}
|
||||
|
||||
verifyRoles (roles, occupant, show_error = true) {
|
||||
if (!Array.isArray(roles)) {
|
||||
|
@ -771,7 +774,7 @@ const ChatRoomViewMixin = {
|
|||
this.model.createMessage({ message, 'type': 'error' });
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
verifyAffiliations (affiliations, occupant, show_error = true) {
|
||||
if (!Array.isArray(affiliations)) {
|
||||
|
@ -792,7 +795,7 @@ const ChatRoomViewMixin = {
|
|||
this.model.createMessage({ message, 'type': 'error' });
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
validateRoleOrAffiliationChangeArgs (command, args) {
|
||||
if (!args) {
|
||||
|
@ -804,7 +807,7 @@ const ChatRoomViewMixin = {
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
getNickOrJIDFromCommandArgs (args) {
|
||||
if (u.isValidJID(args.trim())) {
|
||||
|
@ -832,7 +835,7 @@ const ChatRoomViewMixin = {
|
|||
return;
|
||||
}
|
||||
return nick_or_jid;
|
||||
},
|
||||
}
|
||||
|
||||
setAffiliation (command, args, required_affiliations) {
|
||||
const affiliation = COMMAND_TO_AFFILIATION[command];
|
||||
|
@ -874,11 +877,11 @@ const ChatRoomViewMixin = {
|
|||
.setAffiliation(affiliation, [attrs])
|
||||
.then(() => this.model.occupants.fetchMembers())
|
||||
.catch(err => this.onCommandError(err));
|
||||
},
|
||||
}
|
||||
|
||||
getReason (args) {
|
||||
getReason (args) { // eslint-disable-line class-methods-use-this
|
||||
return args.includes(',') ? args.slice(args.indexOf(',') + 1).trim() : null;
|
||||
},
|
||||
}
|
||||
|
||||
setRole (command, args, required_affiliations = [], required_roles = []) {
|
||||
/* Check that a command to change a groupchat user's role or
|
||||
|
@ -903,7 +906,7 @@ const ChatRoomViewMixin = {
|
|||
const occupant = this.model.getOccupant(nick_or_jid);
|
||||
this.model.setRole(occupant, role, reason, undefined, this.onCommandError.bind(this));
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
onCommandError (err) {
|
||||
log.fatal(err);
|
||||
|
@ -912,7 +915,7 @@ const ChatRoomViewMixin = {
|
|||
' ' +
|
||||
__("Check your browser's developer console for details.");
|
||||
this.model.createMessage({ message, 'type': 'error' });
|
||||
},
|
||||
}
|
||||
|
||||
getAllowedCommands () {
|
||||
let allowed_commands = ['clear', 'help', 'me', 'nick', 'register'];
|
||||
|
@ -937,7 +940,7 @@ const ChatRoomViewMixin = {
|
|||
} else {
|
||||
return allowed_commands;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
async destroy () {
|
||||
const messages = [__('Are you sure you want to destroy this groupchat?')];
|
||||
|
@ -968,7 +971,7 @@ const ChatRoomViewMixin = {
|
|||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
parseMessageForCommands (text) {
|
||||
if (
|
||||
|
@ -1088,7 +1091,7 @@ const ChatRoomViewMixin = {
|
|||
return _converse.ChatBoxView.prototype.parseMessageForCommands.apply(this, arguments);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a form given an IQ stanza containing the current
|
||||
|
@ -1107,11 +1110,11 @@ const ChatRoomViewMixin = {
|
|||
'model': this.model,
|
||||
'chatroomview': this
|
||||
});
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const container_el = this.querySelector('.chatroom-body');
|
||||
container_el.insertAdjacentElement('beforeend', this.config_form.el);
|
||||
}
|
||||
u.showElement(this.config_form.el);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a form which allows the user to choose theirnickname.
|
||||
|
@ -1122,24 +1125,24 @@ const ChatRoomViewMixin = {
|
|||
const tpl_result = tpl_muc_nickname_form(this.model.toJSON());
|
||||
if (api.settings.get('muc_show_logs_before_join')) {
|
||||
this.hideSpinner();
|
||||
u.showElement(this.el.querySelector('.chat-area'));
|
||||
const container = this.el.querySelector('.muc-bottom-panel');
|
||||
u.showElement(this.querySelector('.chat-area'));
|
||||
const container = this.querySelector('.muc-bottom-panel');
|
||||
render(tpl_result, container);
|
||||
u.addClass('muc-bottom-panel--nickname', container);
|
||||
} else {
|
||||
const form = this.el.querySelector('.muc-nickname-form');
|
||||
const form = this.querySelector('.muc-nickname-form');
|
||||
const form_el = u.getElementFromTemplateResult(tpl_result);
|
||||
if (form) {
|
||||
sizzle('.spinner', this.el).forEach(u.removeElement);
|
||||
sizzle('.spinner', this).forEach(u.removeElement);
|
||||
form.outerHTML = form_el.outerHTML;
|
||||
} else {
|
||||
this.hideChatRoomContents();
|
||||
const container = this.el.querySelector('.chatroom-body');
|
||||
const container = this.querySelector('.chatroom-body');
|
||||
container.insertAdjacentElement('beforeend', form_el);
|
||||
}
|
||||
}
|
||||
u.safeSave(this.model.session, { 'connection_status': converse.ROOMSTATUS.NICKNAME_REQUIRED });
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the configuration form without submitting and return to the chat view.
|
||||
|
@ -1147,9 +1150,9 @@ const ChatRoomViewMixin = {
|
|||
* @method _converse.ChatRoomView#closeForm
|
||||
*/
|
||||
closeForm () {
|
||||
sizzle('.chatroom-form-container', this.el).forEach(e => u.addClass('hidden', e));
|
||||
sizzle('.chatroom-form-container', this).forEach(e => u.addClass('hidden', e));
|
||||
this.renderAfterTransition();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the process of configuring a groupchat, either by
|
||||
|
@ -1175,14 +1178,14 @@ const ChatRoomViewMixin = {
|
|||
} else {
|
||||
this.closeForm();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
hideChatRoomContents () {
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const container_el = this.querySelector('.chatroom-body');
|
||||
if (container_el !== null) {
|
||||
[].forEach.call(container_el.children, child => child.classList.add('hidden'));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
renderPasswordForm () {
|
||||
this.hideChatRoomContents();
|
||||
|
@ -1196,19 +1199,19 @@ const ChatRoomViewMixin = {
|
|||
}),
|
||||
'chatroomview': this
|
||||
});
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const container_el = this.querySelector('.chatroom-body');
|
||||
container_el.insertAdjacentElement('beforeend', this.password_form.el);
|
||||
} else {
|
||||
this.password_form.model.set('validation_message', message);
|
||||
}
|
||||
u.showElement(this.password_form.el);
|
||||
this.model.session.save('connection_status', converse.ROOMSTATUS.PASSWORD_REQUIRED);
|
||||
},
|
||||
}
|
||||
|
||||
showDestroyedMessage () {
|
||||
u.hideElement(this.el.querySelector('.chat-area'));
|
||||
u.hideElement(this.el.querySelector('.occupants'));
|
||||
sizzle('.spinner', this.el).forEach(u.removeElement);
|
||||
u.hideElement(this.querySelector('.chat-area'));
|
||||
u.hideElement(this.querySelector('.occupants'));
|
||||
sizzle('.spinner', this).forEach(u.removeElement);
|
||||
|
||||
const reason = this.model.get('destroyed_reason');
|
||||
const moved_jid = this.model.get('moved_jid');
|
||||
|
@ -1216,7 +1219,7 @@ const ChatRoomViewMixin = {
|
|||
'destroyed_reason': undefined,
|
||||
'moved_jid': undefined
|
||||
});
|
||||
const container = this.el.querySelector('.disconnect-container');
|
||||
const container = this.querySelector('.disconnect-container');
|
||||
render(tpl_muc_destroyed(moved_jid, reason), container);
|
||||
const switch_el = container.querySelector('a.switch-chat');
|
||||
if (switch_el) {
|
||||
|
@ -1228,16 +1231,16 @@ const ChatRoomViewMixin = {
|
|||
});
|
||||
}
|
||||
u.showElement(container);
|
||||
},
|
||||
}
|
||||
|
||||
showDisconnectMessage () {
|
||||
const message = this.model.get('disconnection_message');
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
u.hideElement(this.el.querySelector('.chat-area'));
|
||||
u.hideElement(this.el.querySelector('.occupants'));
|
||||
sizzle('.spinner', this.el).forEach(u.removeElement);
|
||||
u.hideElement(this.querySelector('.chat-area'));
|
||||
u.hideElement(this.querySelector('.occupants'));
|
||||
sizzle('.spinner', this).forEach(u.removeElement);
|
||||
|
||||
const messages = [message];
|
||||
const actor = this.model.get('disconnection_actor');
|
||||
|
@ -1253,17 +1256,17 @@ const ChatRoomViewMixin = {
|
|||
'disconnection_reason': undefined,
|
||||
'disconnection_actor': undefined
|
||||
});
|
||||
const container = this.el.querySelector('.disconnect-container');
|
||||
const container = this.querySelector('.disconnect-container');
|
||||
render(tpl_muc_disconnect(messages), container);
|
||||
u.showElement(container);
|
||||
},
|
||||
}
|
||||
|
||||
onOccupantAdded (occupant) {
|
||||
if (occupant.get('jid') === _converse.bare_jid) {
|
||||
this.renderHeading();
|
||||
this.renderBottomPanel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Working backwards, get today's most recent join/leave notification
|
||||
|
@ -1273,7 +1276,7 @@ const ChatRoomViewMixin = {
|
|||
* @param {HTMLElement} el
|
||||
* @param {string} nick
|
||||
*/
|
||||
getPreviousJoinOrLeaveNotification (el, nick) {
|
||||
getPreviousJoinOrLeaveNotification (el, nick) { // eslint-disable-line class-methods-use-this
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
while (el !== null) {
|
||||
if (!el.classList.contains('chat-info')) {
|
||||
|
@ -1291,7 +1294,7 @@ const ChatRoomViewMixin = {
|
|||
}
|
||||
el = el.previousElementSibling;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerender the groupchat after some kind of transition. For
|
||||
|
@ -1308,18 +1311,18 @@ const ChatRoomViewMixin = {
|
|||
this.renderPasswordForm();
|
||||
} else if (conn_status == converse.ROOMSTATUS.ENTERED) {
|
||||
this.hideChatRoomContents();
|
||||
u.showElement(this.el.querySelector('.chat-area'));
|
||||
this.el.querySelector('.occupants')?.setVisibility();
|
||||
u.showElement(this.querySelector('.chat-area'));
|
||||
this.querySelector('.occupants')?.setVisibility();
|
||||
this.scrollDown();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
showSpinner () {
|
||||
sizzle('.spinner', this.el).forEach(u.removeElement);
|
||||
sizzle('.spinner', this).forEach(u.removeElement);
|
||||
this.hideChatRoomContents();
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
const container_el = this.querySelector('.chatroom-body');
|
||||
container_el.insertAdjacentElement('afterbegin', u.getElementFromTemplateResult(tpl_spinner()));
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the spinner is being shown and if so, hide it.
|
||||
|
@ -1329,13 +1332,13 @@ const ChatRoomViewMixin = {
|
|||
* @method _converse.ChatRoomView#hideSpinner
|
||||
*/
|
||||
hideSpinner () {
|
||||
const spinner = this.el.querySelector('.spinner');
|
||||
const spinner = this.querySelector('.spinner');
|
||||
if (spinner !== null) {
|
||||
u.removeElement(spinner);
|
||||
this.renderAfterTransition();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default ChatRoomViewMixin;
|
||||
api.elements.define('converse-muc', MUCView);
|
||||
|
|
|
@ -57,7 +57,7 @@ export const RoomsPanelViewMixin = {
|
|||
}))()
|
||||
});
|
||||
this.roomspanel.model.fetch();
|
||||
this.el.querySelector('.controlbox-pane').insertAdjacentElement('beforeEnd', this.roomspanel.render().el);
|
||||
this.querySelector('.controlbox-pane').insertAdjacentElement('beforeEnd', this.roomspanel.render().el);
|
||||
|
||||
/**
|
||||
* Triggered once the section of the { @link _converse.ControlBoxView }
|
||||
|
|
|
@ -67,23 +67,23 @@ function onChatBoxesInitialized () {
|
|||
}
|
||||
|
||||
|
||||
function onChatInitialized (view) {
|
||||
view.listenTo(view.model.messages, 'add', (message) => {
|
||||
function onChatInitialized (el) {
|
||||
el.listenTo(el.model.messages, 'add', (message) => {
|
||||
if (message.get('is_encrypted') && !message.get('is_error')) {
|
||||
view.model.save('omemo_supported', true);
|
||||
el.model.save('omemo_supported', true);
|
||||
}
|
||||
});
|
||||
view.listenTo(view.model, 'change:omemo_supported', () => {
|
||||
if (!view.model.get('omemo_supported') && view.model.get('omemo_active')) {
|
||||
view.model.set('omemo_active', false);
|
||||
el.listenTo(el.model, 'change:omemo_supported', () => {
|
||||
if (!el.model.get('omemo_supported') && el.model.get('omemo_active')) {
|
||||
el.model.set('omemo_active', false);
|
||||
} else {
|
||||
// Manually trigger an update, setting omemo_active to
|
||||
// false above will automatically trigger one.
|
||||
view.el.querySelector('converse-chat-toolbar')?.requestUpdate();
|
||||
el.querySelector('converse-chat-toolbar')?.requestUpdate();
|
||||
}
|
||||
});
|
||||
view.listenTo(view.model, 'change:omemo_active', () => {
|
||||
view.el.querySelector('converse-chat-toolbar').requestUpdate();
|
||||
el.listenTo(el.model, 'change:omemo_active', () => {
|
||||
el.querySelector('converse-chat-toolbar').requestUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { _converse, api } from '@converse/headless/core';
|
||||
|
||||
const ControlBoxRegistrationMixin = {
|
||||
|
||||
showLoginOrRegisterForm () {
|
||||
if (!this.registerpanel) {
|
||||
return;
|
||||
|
@ -21,7 +22,7 @@ const ControlBoxRegistrationMixin = {
|
|||
});
|
||||
this.registerpanel.render();
|
||||
this.registerpanel.el.classList.add('hidden');
|
||||
const login_panel = this.el.querySelector('#converse-login-panel');
|
||||
const login_panel = this.querySelector('#converse-login-panel');
|
||||
if (login_panel) {
|
||||
login_panel.insertAdjacentElement('afterend', this.registerpanel.el);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { api, converse } from '@converse/headless/core';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
||||
function ensureElement () {
|
||||
if (!api.settings.get('auto_insert')) {
|
||||
return;
|
||||
}
|
||||
const root = api.settings.get('root');
|
||||
if (!root.querySelector('converse-root#conversejs')) {
|
||||
const el = document.createElement('converse-root');
|
||||
el.setAttribute('id', 'conversejs');
|
||||
u.addClass(`theme-${api.settings.get('theme')}`, el);
|
||||
const body = root.querySelector('body');
|
||||
if (body) {
|
||||
body.appendChild(el);
|
||||
} else {
|
||||
root.appendChild(el); // Perhaps inside a web component?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
converse.plugins.add('converse-rootview', {
|
||||
initialize () {
|
||||
api.settings.extend({
|
||||
'auto_insert': true
|
||||
});
|
||||
|
||||
api.listen.on('chatBoxesInitialized', ensureElement);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import { api, converse } from '@converse/headless/converse-core';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
||||
converse.plugins.add('converse-rootview', {
|
||||
initialize () {
|
||||
api.settings.extend({
|
||||
'auto_insert': true
|
||||
});
|
||||
|
||||
function ensureElement () {
|
||||
if (!api.settings.get('auto_insert')) {
|
||||
return;
|
||||
}
|
||||
const root = api.settings.get('root');
|
||||
if (!root.querySelector('converse-root#conversejs')) {
|
||||
const el = document.createElement('converse-root');
|
||||
el.setAttribute('id', 'conversejs');
|
||||
u.addClass(`theme-${api.settings.get('theme')}`, el);
|
||||
const body = root.querySelector('body');
|
||||
if (body) {
|
||||
body.appendChild(el);
|
||||
} else {
|
||||
root.appendChild(el); // Perhaps inside a web component?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api.listen.on('chatBoxesInitialized', ensureElement);
|
||||
}
|
||||
});
|
|
@ -91,12 +91,12 @@ const RosterView = OrderedListView.extend({
|
|||
* contact fetched from browser storage.
|
||||
*/
|
||||
updateFilter: debounce(function () {
|
||||
this.filter_view = this.el.querySelector('converse-roster-filter');
|
||||
const type = this.filter_view.model.get('filter_type');
|
||||
const filter = new _converse.RosterFilter();
|
||||
const type = filter.get('filter_type');
|
||||
if (type === 'state') {
|
||||
this.filter(this.filter_view.model.get('chat_state'), type);
|
||||
this.filter(filter.get('chat_state'), type);
|
||||
} else {
|
||||
this.filter(this.filter_view.model.get('filter_text'), type);
|
||||
this.filter(filter.get('filter_text'), type);
|
||||
}
|
||||
}, 100),
|
||||
|
||||
|
|
|
@ -0,0 +1,391 @@
|
|||
import log from '@converse/headless/log';
|
||||
import tpl_chatbox_message_form from 'templates/chatbox_message_form.js';
|
||||
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 { debounce } from 'lodash-es';
|
||||
import { html, render } from 'lit-html';
|
||||
|
||||
const u = converse.env.utils;
|
||||
|
||||
export default class BaseChatView extends ElementView {
|
||||
|
||||
initDebounced () {
|
||||
this.markScrolled = debounce(this._markScrolled, 100);
|
||||
this.debouncedScrollDown = debounce(this.scrollDown, 100);
|
||||
|
||||
// For tests that use Jasmine.Clock we want to turn of
|
||||
// debouncing, since setTimeout breaks.
|
||||
if (api.settings.get('debounced_content_rendering')) {
|
||||
this.renderChatHistory = debounce(() => this.renderChatContent(false), 100);
|
||||
this.renderNotifications = debounce(() => this.renderChatContent(true), 100);
|
||||
} else {
|
||||
this.renderChatHistory = () => this.renderChatContent(false);
|
||||
this.renderNotifications = () => this.renderChatContent(true);
|
||||
}
|
||||
}
|
||||
|
||||
renderChatContent (msgs_by_ref = false) {
|
||||
if (!this.tpl_chat_content) {
|
||||
this.tpl_chat_content = o => {
|
||||
return html`
|
||||
<converse-chat-content .chatview=${this} .messages=${o.messages} notifications=${o.notifications}>
|
||||
</converse-chat-content>
|
||||
`;
|
||||
};
|
||||
}
|
||||
const msg_models = this.model.messages.models;
|
||||
const messages = msgs_by_ref ? msg_models : Array.from(msg_models);
|
||||
render(this.tpl_chat_content({ messages, 'notifications': this.getNotifications() }), this.msgs_container);
|
||||
}
|
||||
|
||||
renderMessageForm () {
|
||||
const form_container = this.querySelector('.message-form-container');
|
||||
render(
|
||||
tpl_chatbox_message_form(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
'hint_value': this.querySelector('.spoiler-hint')?.value,
|
||||
'label_message': this.model.get('composing_spoiler') ? __('Hidden message') : __('Message'),
|
||||
'label_spoiler_hint': __('Optional hint'),
|
||||
'message_value': this.querySelector('.chat-textarea')?.value,
|
||||
'show_send_button': api.settings.get('show_send_button'),
|
||||
'show_toolbar': api.settings.get('show_toolbar'),
|
||||
'unread_msgs': __('You have unread messages')
|
||||
})
|
||||
),
|
||||
form_container
|
||||
);
|
||||
this.addEventListener('focusin', ev => this.emitFocused(ev));
|
||||
this.addEventListener('focusout', ev => this.emitBlurred(ev));
|
||||
this.renderToolbar();
|
||||
}
|
||||
|
||||
renderToolbar () {
|
||||
if (!api.settings.get('show_toolbar')) {
|
||||
return this;
|
||||
}
|
||||
const options = Object.assign(
|
||||
{
|
||||
'model': this.model,
|
||||
'chatview': this
|
||||
},
|
||||
this.model.toJSON(),
|
||||
this.getToolbarOptions()
|
||||
);
|
||||
render(tpl_toolbar(options), this.querySelector('.chat-toolbar'));
|
||||
/**
|
||||
* Triggered once the _converse.ChatBoxView's toolbar has been rendered
|
||||
* @event _converse#renderToolbar
|
||||
* @type { _converse.ChatBoxView }
|
||||
* @example _converse.api.listen.on('renderToolbar', view => { ... });
|
||||
*/
|
||||
api.trigger('renderToolbar', this);
|
||||
return this;
|
||||
}
|
||||
|
||||
async getHeadingStandaloneButton (promise_or_data) { // eslint-disable-line class-methods-use-this
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a
|
||||
href="#"
|
||||
class="chatbox-btn ${data.a_class} fa ${data.icon_class}"
|
||||
@click=${data.handler}
|
||||
title="${data.i18n_title}"
|
||||
></a>
|
||||
`;
|
||||
}
|
||||
|
||||
hideNewMessagesIndicator () {
|
||||
const new_msgs_indicator = this.querySelector('.new-msgs-indicator');
|
||||
if (new_msgs_indicator !== null) {
|
||||
new_msgs_indicator.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
maybeFocus () {
|
||||
api.settings.get('auto_focus') && this.focus();
|
||||
}
|
||||
|
||||
focus () {
|
||||
const textarea_el = this.getElementsByClassName('chat-textarea')[0];
|
||||
if (textarea_el && document.activeElement !== textarea_el) {
|
||||
textarea_el.focus();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
show () {
|
||||
if (this.model.get('hidden')) {
|
||||
log.debug(`Not showing chat ${this.model.get('jid')} because it's set as hidden`);
|
||||
return;
|
||||
}
|
||||
if (u.isVisible(this)) {
|
||||
this.maybeFocus();
|
||||
return;
|
||||
}
|
||||
this.afterShown();
|
||||
}
|
||||
|
||||
emitBlurred (ev) {
|
||||
if (this.contains(document.activeElement) || this.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox is still focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been removed from a particular chat.
|
||||
* @event _converse#chatBoxBlurred
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxBlurred', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxBlurred', this, ev);
|
||||
}
|
||||
|
||||
emitFocused (ev) {
|
||||
if (this.contains(ev.relatedTarget)) {
|
||||
// Something else in this chatbox was already focused
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Triggered when the focus has been moved to a particular chat.
|
||||
* @event _converse#chatBoxFocused
|
||||
* @type { _converse.ChatBoxView | _converse.ChatRoomView }
|
||||
* @example _converse.api.listen.on('chatBoxFocused', (view, event) => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxFocused', this, ev);
|
||||
}
|
||||
|
||||
async getHeadingDropdownItem (promise_or_data) { // eslint-disable-line class-methods-use-this
|
||||
const data = await promise_or_data;
|
||||
return html`
|
||||
<a href="#" class="dropdown-item ${data.a_class}" @click=${data.handler} title="${data.i18n_title}"
|
||||
><i class="fa ${data.icon_class}"></i>${data.i18n_text}</a
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
autocompleteInPicker (input, value) {
|
||||
const emoji_dropdown = this.querySelector('converse-emoji-dropdown');
|
||||
const emoji_picker = this.querySelector('converse-emoji-picker');
|
||||
if (emoji_picker && emoji_dropdown) {
|
||||
emoji_picker.model.set({
|
||||
'ac_position': input.selectionStart,
|
||||
'autocompleting': value,
|
||||
'query': value
|
||||
});
|
||||
emoji_dropdown.showMenu();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
onEmojiReceivedFromPicker (emoji) {
|
||||
const model = this.querySelector('converse-emoji-picker').model;
|
||||
const autocompleting = model.get('autocompleting');
|
||||
const ac_position = model.get('ac_position');
|
||||
this.insertIntoTextArea(emoji, autocompleting, false, ac_position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a particular string value into the textarea of this chat box.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#insertIntoTextArea
|
||||
* @param {string} value - The value to be inserted.
|
||||
* @param {(boolean|string)} [replace] - Whether an existing value
|
||||
* should be replaced. If set to `true`, the entire textarea will
|
||||
* be replaced with the new value. If set to a string, then only
|
||||
* that string will be replaced *if* a position is also specified.
|
||||
* @param {integer} [position] - The end index of the string to be
|
||||
* replaced with the new value.
|
||||
*/
|
||||
insertIntoTextArea (value, replace = false, correcting = false, position) {
|
||||
const textarea = this.querySelector('.chat-textarea');
|
||||
if (correcting) {
|
||||
u.addClass('correcting', textarea);
|
||||
} else {
|
||||
u.removeClass('correcting', textarea);
|
||||
}
|
||||
if (replace) {
|
||||
if (position && typeof replace == 'string') {
|
||||
textarea.value = textarea.value.replace(new RegExp(replace, 'g'), (match, offset) =>
|
||||
offset == position - replace.length ? value + ' ' : match
|
||||
);
|
||||
} else {
|
||||
textarea.value = value;
|
||||
}
|
||||
} else {
|
||||
let existing = textarea.value;
|
||||
if (existing && existing[existing.length - 1] !== ' ') {
|
||||
existing = existing + ' ';
|
||||
}
|
||||
textarea.value = existing + value + ' ';
|
||||
}
|
||||
this.updateCharCounter(textarea.value);
|
||||
u.placeCaretAtEnd(textarea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the chat content is scrolled up or down.
|
||||
* We want to record when the user has scrolled away from
|
||||
* the bottom, so that we don't automatically scroll away
|
||||
* from what the user is reading when new messages are received.
|
||||
*
|
||||
* Don't call this method directly, instead, call `markScrolled`,
|
||||
* which debounces this method by 100ms.
|
||||
* @private
|
||||
*/
|
||||
_markScrolled (ev) {
|
||||
let scrolled = true;
|
||||
let scrollTop = null;
|
||||
const is_at_bottom =
|
||||
this.msgs_container.scrollTop + this.msgs_container.clientHeight >= this.msgs_container.scrollHeight - 62; // sigh...
|
||||
|
||||
if (is_at_bottom) {
|
||||
scrolled = false;
|
||||
this.onScrolledDown();
|
||||
} else if (this.msgs_container.scrollTop === 0) {
|
||||
/**
|
||||
* Triggered once the chat's message area has been scrolled to the top
|
||||
* @event _converse#chatBoxScrolledUp
|
||||
* @property { _converse.ChatBoxView | _converse.ChatRoomView } view
|
||||
* @example _converse.api.listen.on('chatBoxScrolledUp', obj => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxScrolledUp', this);
|
||||
} else {
|
||||
scrollTop = ev.target.scrollTop;
|
||||
}
|
||||
u.safeSave(this.model, { scrolled, scrollTop });
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the chat down.
|
||||
*
|
||||
* This method will always scroll the chat down, regardless of
|
||||
* whether the user scrolled up manually or not.
|
||||
* @param { Event } [ev] - An optional event that is the cause for needing to scroll down.
|
||||
*/
|
||||
scrollDown (ev) {
|
||||
ev?.preventDefault?.();
|
||||
ev?.stopPropagation?.();
|
||||
if (this.model.get('scrolled')) {
|
||||
u.safeSave(this.model, {
|
||||
'scrolled': false,
|
||||
'scrollTop': null
|
||||
});
|
||||
}
|
||||
if (this.msgs_container.scrollTo) {
|
||||
const behavior = this.msgs_container.scrollTop ? 'smooth' : 'auto';
|
||||
this.msgs_container.scrollTo({ 'top': this.msgs_container.scrollHeight, behavior });
|
||||
} else {
|
||||
this.msgs_container.scrollTop = this.msgs_container.scrollHeight;
|
||||
}
|
||||
this.onScrolledDown();
|
||||
}
|
||||
|
||||
onScrolledDown () {
|
||||
this.hideNewMessagesIndicator();
|
||||
if (!this.model.isHidden()) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
// Clear location hash if set to one of the messages in our history
|
||||
const hash = window.location.hash;
|
||||
hash && this.model.messages.get(hash.slice(1)) && _converse.router.history.navigate();
|
||||
}
|
||||
/**
|
||||
* Triggered once the chat's message area has been scrolled down to the bottom.
|
||||
* @event _converse#chatBoxScrolledDown
|
||||
* @type {object}
|
||||
* @property { _converse.ChatBox | _converse.ChatRoom } chatbox - The chat model
|
||||
* @example _converse.api.listen.on('chatBoxScrolledDown', obj => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxScrolledDown', { 'chatbox': this.model }); // TODO: clean up
|
||||
}
|
||||
|
||||
onWindowStateChanged (state) {
|
||||
if (state === 'visible') {
|
||||
if (!this.model.isHidden() && this.model.get('num_unread', 0)) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
}
|
||||
} else if (state === 'hidden') {
|
||||
this.model.setChatState(_converse.INACTIVE, { 'silent': true });
|
||||
this.model.sendChatState();
|
||||
}
|
||||
}
|
||||
|
||||
async onFormSubmitted (ev) {
|
||||
ev.preventDefault();
|
||||
const textarea = this.querySelector('.chat-textarea');
|
||||
const message_text = textarea.value.trim();
|
||||
if (
|
||||
(api.settings.get('message_limit') && message_text.length > api.settings.get('message_limit')) ||
|
||||
!message_text.replace(/\s/g, '').length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!_converse.connection.authenticated) {
|
||||
const err_msg = __('Sorry, the connection has been lost, and your message could not be sent');
|
||||
api.alert('error', __('Error'), err_msg);
|
||||
api.connection.reconnect();
|
||||
return;
|
||||
}
|
||||
let spoiler_hint,
|
||||
hint_el = {};
|
||||
if (this.model.get('composing_spoiler')) {
|
||||
hint_el = this.querySelector('form.sendXMPPMessage input.spoiler-hint');
|
||||
spoiler_hint = hint_el.value;
|
||||
}
|
||||
u.addClass('disabled', textarea);
|
||||
textarea.setAttribute('disabled', 'disabled');
|
||||
this.querySelector('converse-emoji-dropdown')?.hideMenu();
|
||||
|
||||
const is_command = this.parseMessageForCommands(message_text);
|
||||
const message = is_command ? null : await this.model.sendMessage(message_text, spoiler_hint);
|
||||
if (is_command || message) {
|
||||
hint_el.value = '';
|
||||
textarea.value = '';
|
||||
u.removeClass('correcting', textarea);
|
||||
textarea.style.height = 'auto';
|
||||
this.updateCharCounter(textarea.value);
|
||||
}
|
||||
if (message) {
|
||||
/**
|
||||
* Triggered whenever a message is sent by the user
|
||||
* @event _converse#messageSend
|
||||
* @type { _converse.Message }
|
||||
* @example _converse.api.listen.on('messageSend', message => { ... });
|
||||
*/
|
||||
api.trigger('messageSend', message);
|
||||
}
|
||||
if (api.settings.get('view_mode') === 'overlayed') {
|
||||
// XXX: Chrome flexbug workaround. The .chat-content area
|
||||
// doesn't resize when the textarea is resized to its original size.
|
||||
this.msgs_container.parentElement.style.display = 'none';
|
||||
}
|
||||
textarea.removeAttribute('disabled');
|
||||
u.removeClass('disabled', textarea);
|
||||
|
||||
if (api.settings.get('view_mode') === 'overlayed') {
|
||||
// XXX: Chrome flexbug workaround.
|
||||
this.msgs_container.parentElement.style.display = '';
|
||||
}
|
||||
// Suppress events, otherwise superfluous CSN gets set
|
||||
// immediately after the message, causing rate-limiting issues.
|
||||
this.model.setChatState(_converse.ACTIVE, { 'silent': true });
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
onEnterPressed (ev) {
|
||||
return this.onFormSubmitted(ev);
|
||||
}
|
||||
|
||||
updateCharCounter (chars) {
|
||||
if (api.settings.get('message_limit')) {
|
||||
const message_limit = this.querySelector('.message-limit');
|
||||
const counter = api.settings.get('message_limit') - chars.length;
|
||||
message_limit.textContent = counter;
|
||||
if (counter < 1) {
|
||||
u.addClass('error', message_limit);
|
||||
} else {
|
||||
u.removeClass('error', message_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,13 @@ const getImgHref = (image, image_type) => {
|
|||
return image.startsWith('data:') ? image : `data:${image_type};base64,${image}`;
|
||||
}
|
||||
|
||||
export default (o) => html`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="avatar ${o.classes}" width="${o.width}" height="${o.height}">
|
||||
<image width="${o.width}" height="${o.height}" preserveAspectRatio="xMidYMid meet" href="${getImgHref(o.image, o.image_type)}"/>
|
||||
</svg>`;
|
||||
export default (o) => {
|
||||
if (o.image) {
|
||||
return html`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="avatar ${o.classes}" width="${o.width}" height="${o.height}">
|
||||
<image width="${o.width}" height="${o.height}" preserveAspectRatio="xMidYMid meet" href="${getImgHref(o.image, o.image_type)}"/>
|
||||
</svg>`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { html } from 'lit-html';
|
||||
import '../components/font-awesome.js';
|
||||
import { api } from '@converse/headless/core';
|
||||
import { html } from 'lit-html';
|
||||
|
||||
|
||||
export default () => html`
|
||||
<div class="converse-chatboxes row no-gutters"></div>
|
||||
<div id="converse-modals" class="modals"></div>
|
||||
<converse-fontawesome></converse-fontawesome>
|
||||
`;
|
||||
export default () => {
|
||||
let extra_classes = api.settings.get('singleton') ? 'converse-singleton' : '';
|
||||
extra_classes += `converse-${api.settings.get('view_mode')}`;
|
||||
return html`
|
||||
<converse-chats class="converse-chatboxes row no-gutters ${extra_classes}"></converse-chats>
|
||||
<div id="converse-modals" class="modals"></div>
|
||||
<converse-fontawesome></converse-fontawesome>
|
||||
`;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue