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
c2c1db58
Commit
c2c1db58
authored
Jun 04, 2020
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create a component which renders message actions in a dropdown
parent
6ad76c14
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
127 additions
and
48 deletions
+127
-48
sass/_messages.scss
sass/_messages.scss
+34
-18
sass/_variables.scss
sass/_variables.scss
+1
-0
spec/chatbox.js
spec/chatbox.js
+1
-1
spec/messages.js
spec/messages.js
+1
-1
spec/muc_messages.js
spec/muc_messages.js
+1
-1
spec/omemo.js
spec/omemo.js
+2
-1
spec/retractions.js
spec/retractions.js
+1
-2
src/components/dropdown.js
src/components/dropdown.js
+3
-1
src/components/message-actions.js
src/components/message-actions.js
+74
-0
src/components/message.js
src/components/message.js
+9
-23
No files found.
sass/_messages.scss
View file @
c2c1db58
...
...
@@ -90,7 +90,6 @@
display
:
inline-flex
;
width
:
100%
;
flex-direction
:
row
;
overflow
:
auto
;
// Ensures that content stays inside
padding
:
0
.125rem
1rem
;
&
.onload
{
...
...
@@ -98,12 +97,7 @@
-webkit-animation
:
colorchange-chatmessage
1s
;
}
&
:hover
{
background-color
:
rgba
(
0
,
0
,
0
,
0
.035
);
.chat-msg__actions
{
.chat-msg__action
{
opacity
:
1
;
}
}
background-color
:
var
(
--
list-item-hover-color
);
}
&
.correcting
{
&
.groupchat
{
...
...
@@ -162,9 +156,15 @@
display
:
flex
;
flex-direction
:
row
;
justify-content
:
space-between
;
&
:hover
{
.btn--standalone
{
opacity
:
1
;
}
}
}
.chat-msg__message
{
line-height
:
1
.5em
;
display
:
inline-flex
;
flex-direction
:
column
;
width
:
100%
;
...
...
@@ -235,20 +235,36 @@
}
}
converse-message-actions
{
margin-left
:
0
.5em
;
}
.chat-msg__actions
{
display
:
flex
;
flex-wrap
:
nowrap
;
.chat-msg__action
{
height
:
var
(
--
message-font-size
);
font-size
:
var
(
--
message-font-size
);
padding
:
0
;
margin-left
:
0
.75em
;
.dropdown-menu
{
min-width
:
5rem
;
}
i
{
color
:
var
(
--
text-color-lighten-15-percent
);
font-size
:
70%
;
}
button
{
border
:
none
;
opacity
:
0
;
background
:
transparent
;
cursor
:
pointer
;
&
:focus
{
opacity
:
1
;
color
:
var
(
--
text-color-lighten-15-percent
);
padding
:
0
0
.25em
;
}
.btn--standalone
{
opacity
:
0
;
margin-top
:
-0
.2em
;
}
.chat-msg__action
{
width
:
100%
;
padding
:
0
.5em
1em
;
text-align
:
left
;
white-space
:
nowrap
;
&
:hover
{
color
:
var
(
--
text-color
);
background-color
:
var
(
--
list-item-hover-color
);
}
}
}
...
...
sass/_variables.scss
View file @
c2c1db58
...
...
@@ -178,6 +178,7 @@ $mobile_portrait_length: 480px !default;
--list-toggle-color
:
#818479
;
// $gray-color
--list-toggle-hover-color
:
#585B51
;
// $dark-gray-color
--list-toggle-font-weight
:
normal
;
--list-item-hover-color
:
rgba
(
0
,
0
,
0
,
0
.035
);
--list-item-action-color
:
#e3eef3
;
// lighten($lightest-blue, 25%)
--list-item-link-color
:
inherit
;
--list-item-link-hover-color
:
var
(
--
dark-link-color
);
...
...
spec/chatbox.js
View file @
c2c1db58
...
...
@@ -107,7 +107,7 @@ describe("Chatboxes", function () {
// get the 'chat-msg--followup' class.
message
=
'
This a normal message
'
;
await
mock
.
sendMessage
(
view
,
message
);
const
msg_txt_sel
=
'
converse-chat-message:last-child .chat-msg__
body
'
;
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
'
);
expect
(
u
.
hasClass
(
'
chat-msg--followup
'
,
el
)).
toBeFalsy
();
...
...
spec/messages.js
View file @
c2c1db58
...
...
@@ -106,7 +106,7 @@ describe("A Chat Message", function () {
const
first_msg
=
view
.
model
.
messages
.
findWhere
({
'
message
'
:
'
But soft, what light through yonder airlock breaks?
'
});
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg .chat-msg__action
'
).
length
).
toBe
(
2
);
let
action
=
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__action
'
);
expect
(
action
.
getAttribute
(
'
title
'
)).
toBe
(
'
Edit this message
'
);
expect
(
action
.
textContent
.
trim
()).
toBe
(
'
Edit
'
);
action
.
style
.
opacity
=
1
;
action
.
click
();
...
...
spec/muc_messages.js
View file @
c2c1db58
...
...
@@ -1215,7 +1215,7 @@ describe("A Groupchat Message", function () {
`<origin-id id="
${
msg
.
nodeTree
.
querySelector
(
'
origin-id
'
).
getAttribute
(
"
id
"
)}
" xmlns="urn:xmpp:sid:0"/>`
+
`</message>`
);
const
action
=
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__action
'
);
const
action
=
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg__action
'
)
);
action
.
style
.
opacity
=
1
;
action
.
click
();
...
...
spec/omemo.js
View file @
c2c1db58
...
...
@@ -437,7 +437,8 @@ describe("The OMEMO module", function() {
_converse
.
connection
.
_dataRecv
(
mock
.
createRequest
(
carbon
));
await
new
Promise
(
resolve
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__body
'
).
textContent
.
trim
())
expect
(
view
.
el
.
querySelector
(
'
.chat-msg__text
'
).
textContent
.
trim
())
.
toBe
(
'
This is an encrypted carbon message from another device of mine
'
);
expect
(
devicelist
.
devices
.
length
).
toBe
(
2
);
...
...
spec/retractions.js
View file @
c2c1db58
...
...
@@ -119,8 +119,7 @@ describe("Message Retractions", function () {
`
);
_converse
.
connection
.
_dataRecv
(
mock
.
createRequest
(
received_stanza
));
await
u
.
waitUntil
(()
=>
view
.
model
.
handleRetraction
.
calls
.
count
()
===
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
0
);
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
===
1
,
1000
);
expect
(
view
.
model
.
messages
.
length
).
toBe
(
1
);
const
message
=
view
.
model
.
messages
.
at
(
0
)
...
...
src/components/dropdown.js
View file @
c2c1db58
...
...
@@ -52,15 +52,17 @@ export class DropdownList extends BaseDropdown {
static
get
properties
()
{
return
{
'
icon_classes
'
:
{
type
:
String
},
'
items
'
:
{
type
:
Array
}
}
}
render
()
{
const
icon_classes
=
this
.
icon_classes
||
"
fa fa-bars
"
;
return
html
`
<div class="dropleft">
<button type="button" class="btn btn--transparent btn--standalone" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="
fa fa-bars
only-icon"></i>
<i class="
${
icon_classes
}
only-icon"></i>
</button>
<div class="dropdown-menu">
${
this
.
items
.
map
(
b
=>
until
(
b
,
''
))
}
...
...
src/components/message-actions.js
0 → 100644
View file @
c2c1db58
import
{
CustomElement
}
from
'
./element.js
'
;
import
{
__
}
from
'
@converse/headless/i18n
'
;
import
{
html
}
from
'
lit-element
'
;
import
{
until
}
from
'
lit-html/directives/until.js
'
;
class
MessageActions
extends
CustomElement
{
static
get
properties
()
{
return
{
chatview
:
{
type
:
Object
},
model
:
{
type
:
Object
},
editable
:
{
type
:
Boolean
},
correcting
:
{
type
:
Boolean
},
message_type
:
{
type
:
String
},
is_retracted
:
{
type
:
Boolean
},
}
}
render
()
{
return
html
`
${
until
(
this
.
renderActions
(),
''
)
}
`
;
}
static
getActionsDropdownItem
(
o
)
{
return
html
`
<button class="chat-msg__action
${
o
.
button_class
}
" @click=
${
o
.
handler
}
>
<fa-icon class="
${
o
.
icon_class
}
" path-prefix="/dist" color="var(--text-color-lighten-15-percent)" size="1em"></fa-icon>
${
o
.
i18n_text
}
</button>
`
;
}
onMessageEditButtonClicked
(
ev
)
{
ev
.
preventDefault
();
this
.
chatview
.
onMessageEditButtonClicked
(
this
.
model
);
}
onMessageRetractButtonClicked
(
ev
)
{
ev
.
preventDefault
();
this
.
chatview
.
onMessageRetractButtonClicked
(
this
.
model
);
}
async
renderActions
()
{
const
buttons
=
[];
if
(
this
.
editable
)
{
buttons
.
push
({
'
i18n_text
'
:
this
.
correcting
?
__
(
'
Cancel Editing
'
)
:
__
(
'
Edit
'
),
'
handler
'
:
ev
=>
this
.
onMessageEditButtonClicked
(
ev
),
'
button_class
'
:
'
chat-msg__action-edit
'
,
'
icon_class
'
:
'
fa fa-pencil-alt
'
,
'
name
'
:
'
edit
'
});
}
const
may_be_moderated
=
this
.
model
.
get
(
'
type
'
)
===
'
groupchat
'
&&
await
this
.
model
.
mayBeModerated
();
const
retractable
=
!
this
.
is_retracted
&&
(
this
.
model
.
mayBeRetracted
()
||
may_be_moderated
);
if
(
retractable
)
{
buttons
.
push
({
'
i18n_text
'
:
__
(
'
Retract
'
),
'
handler
'
:
ev
=>
this
.
onMessageRetractButtonClicked
(
ev
),
'
button_class
'
:
'
chat-msg__action-retract
'
,
'
icon_class
'
:
'
fas fa-trash-alt
'
,
'
name
'
:
'
retract
'
});
}
const
items
=
buttons
.
map
(
b
=>
MessageActions
.
getActionsDropdownItem
(
b
));
if
(
items
.
length
)
{
return
html
`<converse-dropdown class="chat-msg__actions" .items=
${
items
}
></converse-dropdown>`
;
}
else
{
return
''
;
}
}
}
customElements
.
define
(
'
converse-message-actions
'
,
MessageActions
);
src/components/message.js
View file @
c2c1db58
import
"
./message-body.js
"
;
import
'
./dropdown.js
'
;
import
'
./message-actions.js
'
;
import
MessageVersionsModal
from
'
../modals/message-versions.js
'
;
import
dayjs
from
'
dayjs
'
;
import
filesize
from
"
filesize
"
;
...
...
@@ -8,12 +10,10 @@ import { __ } from '@converse/headless/i18n';
import
{
_converse
,
api
,
converse
}
from
"
@converse/headless/converse-core
"
;
import
{
html
}
from
'
lit-element
'
;
import
{
renderAvatar
}
from
'
./../templates/directives/avatar
'
;
import
{
renderRetractionLink
}
from
'
./../templates/directives/retraction
'
;
const
{
Strophe
}
=
converse
.
env
;
const
u
=
converse
.
env
.
utils
;
const
i18n_edit_message
=
__
(
'
Edit this message
'
);
const
i18n_edited
=
__
(
'
This message has been edited
'
);
const
i18n_show
=
__
(
'
Show more
'
);
const
i18n_show_less
=
__
(
'
Show less
'
);
...
...
@@ -150,17 +150,13 @@ class Message extends CustomElement {
</div>
${
(
this
.
received
&&
!
this
.
is_me_message
&&
!
is_groupchat_message
)
?
html
`<span class="fa fa-check chat-msg__receipt"></span>`
:
''
}
${
(
this
.
edited
)
?
html
`<i title="
${
i18n_edited
}
" class="fa fa-edit chat-msg__edit-modal" @click=
${
this
.
showMessageVersionsModal
}
></i>`
:
''
}
<div class="chat-msg__actions">
${
this
.
editable
?
html
`<button
class="chat-msg__action chat-msg__action-edit"
title="
${
i18n_edit_message
}
"
@click=
${
this
.
onMessageEditButtonClicked
}
>
<fa-icon class="fas fa-pencil-alt" path-prefix="dist" color="var(--text-color-lighten-15-percent)" size="1em"></fa-icon>
</button>`
:
''
}
${
renderRetractionLink
(
this
)
}
</div>
<converse-message-actions
.chatview=
${
this
.
chatview
}
.model=
${
this
.
model
}
?correcting="
${
this
.
correcting
}
"
?editable="
${
this
.
editable
}
"
?is_retracted="
${
this
.
is_retracted
}
"
message_type="
${
this
.
message_type
}
"></converse-message-actions>
</div>
</div>
</div>`
;
...
...
@@ -189,16 +185,6 @@ class Message extends CustomElement {
this
.
parentElement
.
removeChild
(
this
);
}
onMessageRetractButtonClicked
(
ev
)
{
ev
.
preventDefault
();
this
.
chatview
.
onMessageRetractButtonClicked
(
this
.
model
);
}
onMessageEditButtonClicked
(
ev
)
{
ev
.
preventDefault
();
this
.
chatview
.
onMessageEditButtonClicked
(
this
.
model
);
}
isFollowup
()
{
const
messages
=
this
.
model
.
collection
.
models
;
const
idx
=
messages
.
indexOf
(
this
.
model
);
...
...
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