Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
98923bd2
Commit
98923bd2
authored
Jan 02, 2018
by
Weblate
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
b90a516d
ee15e9e3
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
212 additions
and
57 deletions
+212
-57
spec/chatbox.js
spec/chatbox.js
+138
-0
src/converse-chatview.js
src/converse-chatview.js
+73
-57
src/converse-headline.js
src/converse-headline.js
+1
-0
No files found.
spec/chatbox.js
View file @
98923bd2
...
@@ -879,6 +879,144 @@
...
@@ -879,6 +879,144 @@
}).
then
(
done
);
}).
then
(
done
);
}));
}));
it
(
"
can be received out of order, and will still be displayed in the right order
"
,
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
function
(
done
,
_converse
)
{
test_utils
.
createContacts
(
_converse
,
'
current
'
);
test_utils
.
openControlBox
();
test_utils
.
openContactsPanel
(
_converse
);
test_utils
.
waitUntil
(
function
()
{
return
_converse
.
rosterview
.
$el
.
find
(
'
.roster-group
'
).
length
;
},
300
)
.
then
(
function
()
{
var
message
,
msg
;
spyOn
(
_converse
,
'
log
'
);
spyOn
(
_converse
.
chatboxes
,
'
getChatBox
'
).
and
.
callThrough
();
_converse
.
filter_by_resource
=
true
;
var
sender_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
/* <message id='aeb213' to='juliet@capulet.lit/chamber'>
* <forwarded xmlns='urn:xmpp:forward:0'>
* <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
* <message xmlns='jabber:client'
* to='juliet@capulet.lit/balcony'
* from='romeo@montague.lit/orchard'
* type='chat'>
* <body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>
* </message>
* </forwarded>
* </message>
*/
msg
=
$msg
({
'
id
'
:
'
aeb213
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2018-01-02T13:08:25Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
message from today
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
msg
=
$msg
({
'
id
'
:
'
aeb214
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2017-12-31T23:08:25Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
Older message
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
msg
=
$msg
({
'
id
'
:
'
aeb215
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2018-01-01T13:18:23Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
Inbetween message
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
msg
=
$msg
({
'
id
'
:
'
aeb216
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2018-01-01T13:18:23Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
another inbetween message
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
msg
=
$msg
({
'
id
'
:
'
aeb217
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2018-01-02T12:18:23Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
An earlier message today
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
msg
=
$msg
({
'
id
'
:
'
aeb218
'
,
'
to
'
:
_converse
.
bare_jid
})
.
c
(
'
forwarded
'
,
{
'
xmlns
'
:
'
urn:xmpp:forward:0
'
})
.
c
(
'
delay
'
,
{
'
xmlns
'
:
'
urn:xmpp:delay
'
,
'
stamp
'
:
'
2018-01-02T23:28:23Z
'
}).
up
()
.
c
(
'
message
'
,
{
'
xmlns
'
:
'
jabber:client
'
,
'
to
'
:
_converse
.
bare_jid
,
'
from
'
:
sender_jid
,
'
type
'
:
'
chat
'
})
.
c
(
'
body
'
).
t
(
"
newer message from today
"
)
.
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
var
chatboxview
=
_converse
.
chatboxviews
.
get
(
sender_jid
);
var
$chat_content
=
chatboxview
.
$el
.
find
(
'
.chat-content
'
);
chatboxview
.
clearSpinner
();
//cleanup
var
$time
=
$chat_content
.
find
(
'
time
'
);
expect
(
$time
.
length
).
toEqual
(
3
);
$time
=
$chat_content
.
find
(
'
time:first
'
);
expect
(
$time
.
data
(
'
isodate
'
)).
toEqual
(
'
2017-12-31T00:00:00+00:00
'
);
expect
(
$time
[
0
].
nextElementSibling
.
querySelector
(
'
.chat-msg-content
'
).
textContent
).
toBe
(
'
Older message
'
);
var
$el
=
$chat_content
.
find
(
'
.chat-message:first
'
).
find
(
'
.chat-msg-content
'
)
expect
(
$el
.
text
()).
toEqual
(
'
Older message
'
);
$time
=
$chat_content
.
find
(
'
time:eq(1)
'
);
expect
(
$time
.
data
(
'
isodate
'
)).
toEqual
(
'
2018-01-01T00:00:00+00:00
'
);
expect
(
$time
[
0
].
nextElementSibling
.
querySelector
(
'
.chat-msg-content
'
).
textContent
).
toBe
(
'
Inbetween message
'
);
$el
=
$chat_content
.
find
(
'
.chat-message:eq(1)
'
);
expect
(
$el
.
find
(
'
.chat-msg-content
'
).
text
()).
toEqual
(
'
Inbetween message
'
);
expect
(
$el
[
0
].
nextElementSibling
.
querySelector
(
'
.chat-msg-content
'
).
textContent
).
toEqual
(
'
another inbetween message
'
);
$el
=
$chat_content
.
find
(
'
.chat-message:eq(2)
'
);
expect
(
$el
.
find
(
'
.chat-msg-content
'
).
text
()).
toEqual
(
'
another inbetween message
'
);
$time
=
$chat_content
.
find
(
'
time:last
'
);
expect
(
$time
.
data
(
'
isodate
'
)).
toEqual
(
'
2018-01-02T00:00:00+00:00
'
);
expect
(
$time
[
0
].
nextElementSibling
.
querySelector
(
'
.chat-msg-content
'
).
textContent
).
toBe
(
'
An earlier message today
'
);
$el
=
$chat_content
.
find
(
'
.chat-message:eq(3)
'
);
expect
(
$el
.
find
(
'
.chat-msg-content
'
).
text
()).
toEqual
(
'
An earlier message today
'
);
$el
=
$chat_content
.
find
(
'
.chat-message:eq(4)
'
);
expect
(
$el
.
find
(
'
.chat-msg-content
'
).
text
()).
toEqual
(
'
message from today
'
);
expect
(
$el
[
0
].
nextElementSibling
.
querySelector
(
'
.chat-msg-content
'
).
textContent
).
toEqual
(
'
newer message from today
'
);
done
();
});
}));
it
(
"
is ignored if it's intended for a different resource and filter_by_resource is set to true
"
,
it
(
"
is ignored if it's intended for a different resource and filter_by_resource is set to true
"
,
mock
.
initConverseWithPromises
(
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
null
,
[
'
rosterGroupsFetched
'
],
{},
...
...
src/converse-chatview.js
View file @
98923bd2
...
@@ -42,7 +42,7 @@
...
@@ -42,7 +42,7 @@
tpl_toolbar
tpl_toolbar
)
{
)
{
"
use strict
"
;
"
use strict
"
;
const
{
$msg
,
Backbone
,
Strophe
,
_
,
b64_sha1
,
moment
}
=
converse
.
env
;
const
{
$msg
,
Backbone
,
Strophe
,
_
,
b64_sha1
,
sizzle
,
moment
}
=
converse
.
env
;
const
u
=
converse
.
env
.
utils
;
const
u
=
converse
.
env
.
utils
;
const
KEY
=
{
const
KEY
=
{
ENTER
:
13
,
ENTER
:
13
,
...
@@ -277,7 +277,6 @@
...
@@ -277,7 +277,6 @@
this
.
model
.
on
(
'
sendMessage
'
,
this
.
sendMessage
,
this
);
this
.
model
.
on
(
'
sendMessage
'
,
this
.
sendMessage
,
this
);
this
.
render
().
renderToolbar
().
insertHeading
().
fetchMessages
();
this
.
render
().
renderToolbar
().
insertHeading
().
fetchMessages
();
this
.
createEmojiPicker
();
u
.
refreshWebkit
();
u
.
refreshWebkit
();
_converse
.
emit
(
'
chatBoxOpened
'
,
this
);
_converse
.
emit
(
'
chatBoxOpened
'
,
this
);
_converse
.
emit
(
'
chatBoxInitialized
'
,
this
);
_converse
.
emit
(
'
chatBoxInitialized
'
,
this
);
...
@@ -418,6 +417,26 @@
...
@@ -418,6 +417,26 @@
)(
this
.
renderMessage
(
attrs
));
)(
this
.
renderMessage
(
attrs
));
},
},
getLastMessageElement
()
{
let
last_msg_el
=
this
.
content
.
lastElementChild
;
while
(
!
_
.
isNull
(
last_msg_el
)
&&
!
u
.
hasClass
(
last_msg_el
,
'
message
'
)
&&
!
u
.
hasClass
(
last_msg_el
,
'
chat-info
'
))
{
last_msg_el
=
last_msg_el
.
previousSibling
}
return
last_msg_el
;
},
getFirstMessageElement
()
{
let
first_msg_el
=
this
.
content
.
firstElementChild
;
while
(
!
_
.
isNull
(
first_msg_el
)
&&
!
u
.
hasClass
(
first_msg_el
,
'
message
'
)
&&
!
u
.
hasClass
(
first_msg_el
,
'
chat-info
'
))
{
first_msg_el
=
first_msg_el
.
nextSibling
}
return
first_msg_el
;
},
getLastMessageDate
(
cutoff
)
{
getLastMessageDate
(
cutoff
)
{
/* Return the ISO8601 format date of the latest message.
/* Return the ISO8601 format date of the latest message.
*
*
...
@@ -425,22 +444,36 @@
...
@@ -425,22 +444,36 @@
* (Object) cutoff: Moment Date cutoff date. The last
* (Object) cutoff: Moment Date cutoff date. The last
* message received cutoff this date will be returned.
* message received cutoff this date will be returned.
*/
*/
if
(
!
cutoff
)
{
const
first_msg
=
this
.
getFirstMessageElement
(),
const
last_msg
=
this
.
content
.
lastElementChild
;
oldest_date
=
first_msg
?
first_msg
.
getAttribute
(
'
data-isodate
'
)
:
null
;
return
last_msg
?
last_msg
.
getAttribute
(
'
data-isodate
'
)
:
null
if
(
!
_
.
isNull
(
oldest_date
)
&&
moment
(
oldest_date
).
isAfter
(
cutoff
))
{
return
null
;
}
const
last_msg
=
this
.
getLastMessageElement
(),
most_recent_date
=
last_msg
?
last_msg
.
getAttribute
(
'
data-isodate
'
)
:
null
;
if
(
_
.
isNull
(
most_recent_date
)
||
moment
(
most_recent_date
).
isBefore
(
cutoff
))
{
return
most_recent_date
;
}
}
const
msg_dates
=
_
.
invokeMap
(
const
msg_dates
=
_
.
invokeMap
(
this
.
content
.
querySelectorAll
(
'
.message
'
),
sizzle
(
'
.message, .chat-info
'
,
this
.
content
),
Element
.
prototype
.
getAttribute
,
Element
.
prototype
.
getAttribute
,
'
data-isodate
'
'
data-isodate
'
)
)
if
(
_
.
isObject
(
cutoff
))
{
if
(
_
.
isObject
(
cutoff
))
{
cutoff
=
cutoff
.
format
();
cutoff
=
cutoff
.
format
();
}
}
msg_dates
.
push
(
cutoff
);
msg_dates
.
push
(
cutoff
);
msg_dates
.
sort
();
msg_dates
.
sort
();
const
idx
=
msg_dates
.
indexOf
(
cutoff
);
const
idx
=
msg_dates
.
lastIndexOf
(
cutoff
);
return
msg_dates
[
idx
===
0
?
idx
:
idx
-
1
];
if
(
idx
===
0
)
{
return
null
;
}
else
{
return
msg_dates
[
idx
-
1
];
}
},
getDayIndicatorElement
(
date
)
{
return
this
.
content
.
querySelector
(
`.chat-date[data-isodate="
${
date
.
startOf
(
'
day
'
).
format
()}
"]`
);
},
},
showMessage
(
attrs
)
{
showMessage
(
attrs
)
{
...
@@ -456,54 +489,37 @@
...
@@ -456,54 +489,37 @@
* attributes.
* attributes.
*/
*/
const
current_msg_date
=
moment
(
attrs
.
time
)
||
moment
,
const
current_msg_date
=
moment
(
attrs
.
time
)
||
moment
,
first_msg_el
=
this
.
content
.
firstElementChild
,
prepend_html
=
_
.
bind
(
this
.
content
.
insertAdjacentHTML
,
this
.
content
,
'
afterbegin
'
),
first_msg_date
=
first_msg_el
?
first_msg_el
.
getAttribute
(
'
data-isodate
'
)
:
null
,
previous_msg_date
=
this
.
getLastMessageDate
(
current_msg_date
);
append_element
=
_
.
bind
(
this
.
content
.
insertAdjacentElement
,
this
.
content
,
'
beforeend
'
),
append_html
=
_
.
bind
(
this
.
content
.
insertAdjacentHTML
,
this
.
content
,
'
beforeend
'
),
prepend_element
=
_
.
bind
(
this
.
content
.
insertAdjacentElement
,
this
.
content
,
'
afterbegin
'
);
if
(
!
first_msg_date
)
{
// This is the first received message, so we insert a
// date indicator before it.
this
.
insertDayIndicator
(
current_msg_date
,
append_html
);
this
.
insertMessage
(
attrs
,
append_element
);
return
;
}
const
last_msg_date
=
this
.
getLastMessageDate
();
if
(
current_msg_date
.
isAfter
(
last_msg_date
)
||
current_msg_date
.
isSame
(
last_msg_date
))
{
// The new message is after the last message
if
(
current_msg_date
.
isAfter
(
last_msg_date
,
'
day
'
))
{
// Append a new day indicator
this
.
insertDayIndicator
(
current_msg_date
,
append_html
);
}
this
.
insertMessage
(
attrs
,
append_element
);
return
;
}
if
(
current_msg_date
.
isBefore
(
first_msg_date
)
||
if
(
_
.
isNull
(
previous_msg_date
))
{
current_msg_date
.
isSame
(
first_msg_date
))
{
this
.
insertMessage
(
attrs
,
_
.
bind
(
this
.
content
.
insertAdjacentElement
,
this
.
content
,
'
afterbegin
'
));
// The message is before the first, but on the same day.
this
.
insertDayIndicator
(
current_msg_date
,
prepend_html
);
// We need to prepend the message immediately before the
// first message (so that it'll still be after the day
// indicator).
this
.
insertMessage
(
attrs
,
prepend_element
);
if
(
current_msg_date
.
isBefore
(
first_msg_date
,
'
day
'
))
{
// This message is also on a different day, so
// we prepend a day indicator.
this
.
insertDayIndicator
(
current_msg_date
,
append_html
);
}
return
;
}
const
previous_msg_date
=
this
.
getLastMessageDate
(
current_msg_date
);
const
previous_msg_el
=
this
.
content
.
querySelector
(
`.message[data-isodate="
${
previous_msg_date
}
"]`
);
if
(
_
.
isNull
(
previous_msg_el
))
{
this
.
insertMessage
(
attrs
,
prepend_element
);
}
else
{
}
else
{
this
.
insertMessage
(
const
previous_msg_el
=
sizzle
(
`[data-isodate="
${
previous_msg_date
}
"]:last`
,
this
.
content
).
pop
();
attrs
,
_
.
bind
(
previous_msg_el
.
insertAdjacentElement
,
previous_msg_el
,
'
afterend
'
));
const
day_el
=
this
.
getDayIndicatorElement
(
current_msg_date
)
if
(
current_msg_date
.
isAfter
(
previous_msg_date
,
'
day
'
))
{
if
(
_
.
isNull
(
day_el
))
{
this
.
insertMessage
(
attrs
,
_
.
bind
(
previous_msg_el
.
insertAdjacentElement
,
previous_msg_el
,
'
afterend
'
)
);
this
.
insertDayIndicator
(
current_msg_date
,
_
.
bind
(
this
.
content
.
insertAdjacentHTML
,
previous_msg_el
,
'
afterend
'
)
);
}
else
{
this
.
insertMessage
(
attrs
,
_
.
bind
(
previous_msg_el
.
insertAdjacentElement
,
day_el
,
'
afterend
'
)
);
}
}
else
{
this
.
insertMessage
(
attrs
,
_
.
bind
(
previous_msg_el
.
insertAdjacentElement
,
previous_msg_el
,
'
afterend
'
)
);
}
}
}
},
},
...
@@ -590,7 +606,7 @@
...
@@ -590,7 +606,7 @@
if
(
spinner
===
true
)
{
if
(
spinner
===
true
)
{
$
(
this
.
content
).
append
(
tpl_spinner
);
$
(
this
.
content
).
append
(
tpl_spinner
);
}
else
if
(
spinner
===
false
)
{
}
else
if
(
spinner
===
false
)
{
$
(
this
.
content
).
find
(
'
span.spinner
'
).
remove
();
this
.
clearSpinner
();
}
}
return
this
.
scrollDown
();
return
this
.
scrollDown
();
},
},
...
...
src/converse-headline.js
View file @
98923bd2
...
@@ -82,6 +82,7 @@
...
@@ -82,6 +82,7 @@
},
},
initialize
()
{
initialize
()
{
this
.
markScrolled
=
_
.
debounce
(
this
.
_markScrolled
,
100
);
this
.
disable_mam
=
true
;
// Don't do MAM queries for this box
this
.
disable_mam
=
true
;
// Don't do MAM queries for this box
this
.
model
.
messages
.
on
(
'
add
'
,
this
.
onMessageAdded
,
this
);
this
.
model
.
messages
.
on
(
'
add
'
,
this
.
onMessageAdded
,
this
);
this
.
model
.
on
(
'
show
'
,
this
.
show
,
this
);
this
.
model
.
on
(
'
show
'
,
this
.
show
,
this
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment