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
be20b8e1
Commit
be20b8e1
authored
Jun 22, 2020
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
emojis: fix rendering of custom emojis
parent
77a0a01e
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
173 additions
and
95 deletions
+173
-95
karma.conf.js
karma.conf.js
+3
-1
spec/emojis.js
spec/emojis.js
+46
-1
src/headless/converse-chat.js
src/headless/converse-chat.js
+11
-9
src/headless/converse-emoji.js
src/headless/converse-emoji.js
+100
-61
src/headless/converse-muc.js
src/headless/converse-muc.js
+1
-3
src/headless/emojis.json
src/headless/emojis.json
+2
-2
src/templates/directives/body.js
src/templates/directives/body.js
+7
-8
src/templates/emoji_picker.js
src/templates/emoji_picker.js
+3
-10
No files found.
karma.conf.js
View file @
be20b8e1
...
...
@@ -12,6 +12,7 @@ module.exports = function(config) {
{
pattern
:
"
dist/emojis.js
"
,
served
:
true
},
"
dist/converse.js
"
,
"
dist/converse.css
"
,
{
pattern
:
"
dist/images/**/*.*
"
,
included
:
false
},
{
pattern
:
"
dist/webfonts/**/*.*
"
,
included
:
false
},
{
pattern
:
"
dist/
\
@fortawesome/fontawesome-free/sprites/solid.svg
"
,
watched
:
false
,
...
...
@@ -60,7 +61,8 @@ module.exports = function(config) {
],
proxies
:
{
"
/dist/
\
@fortawesome/fontawesome-free/sprites/solid.svg
"
:
"
/base/dist/
\
@fortawesome/fontawesome-free/sprites/solid.svg
"
"
/dist/
\
@fortawesome/fontawesome-free/sprites/solid.svg
"
:
"
/base/dist/
\
@fortawesome/fontawesome-free/sprites/solid.svg
"
,
"
/dist/images/custom_emojis/
"
:
"
/base/dist/images/custom_emojis/
"
},
client
:
{
...
...
spec/emojis.js
View file @
be20b8e1
...
...
@@ -100,7 +100,6 @@ describe("Emojis", function () {
done
();
}));
it
(
"
allows you to search for particular emojis
"
,
mock
.
initConverse
(
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{},
...
...
@@ -239,5 +238,51 @@ describe("Emojis", function () {
expect
(
u
.
hasClass
(
'
chat-msg__text--larger
'
,
message
)).
toBe
(
true
);
done
()
}));
it
(
"
can show custom emojis
"
,
mock
.
initConverse
(
[
'
rosterGroupsFetched
'
,
'
chatBoxesFetched
'
],
{
emoji_categories
:
{
"
smileys
"
:
"
:grinning:
"
,
"
people
"
:
"
:thumbsup:
"
,
"
activity
"
:
"
:soccer:
"
,
"
travel
"
:
"
:motorcycle:
"
,
"
objects
"
:
"
:bomb:
"
,
"
nature
"
:
"
:rainbow:
"
,
"
food
"
:
"
:hotdog:
"
,
"
symbols
"
:
"
:musical_note:
"
,
"
flags
"
:
"
:flag_ac:
"
,
"
custom
"
:
'
:xmpp:
'
}
},
async
function
(
done
,
_converse
)
{
await
mock
.
waitForRoster
(
_converse
,
'
current
'
,
1
);
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
toolbar
=
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
ul.chat-toolbar
'
));
expect
(
toolbar
.
querySelectorAll
(
'
li.toggle-smiley__container
'
).
length
).
toBe
(
1
);
toolbar
.
querySelector
(
'
a.toggle-smiley
'
).
click
();
await
u
.
waitUntil
(()
=>
u
.
isVisible
(
view
.
el
.
querySelector
(
'
.emoji-picker__lists
'
)),
1000
);
const
picker
=
await
u
.
waitUntil
(()
=>
view
.
el
.
querySelector
(
'
.emoji-picker__container
'
),
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
'
);
textarea
.
value
=
'
Running tests for :converse:
'
;
view
.
onKeyDown
({
target
:
textarea
,
preventDefault
:
function
preventDefault
()
{},
keyCode
:
13
// Enter
});
await
new
Promise
(
resolve
=>
view
.
model
.
messages
.
once
(
'
rendered
'
,
resolve
));
const
body
=
view
.
el
.
querySelector
(
'
converse-chat-message-body
'
);
expect
(
body
.
innerHTML
.
replace
(
/<!---->/g
,
''
).
trim
()).
toBe
(
'
Running tests for <img class="emoji" draggable="false" title=":converse:" alt=":converse:" src="/dist/images/custom_emojis/converse.png">
'
);
done
();
}));
});
});
src/headless/converse-chat.js
View file @
be20b8e1
...
...
@@ -951,21 +951,23 @@ converse.plugins.add('converse-chat', {
getOutgoingMessageAttributes
(
text
,
spoiler_hint
)
{
const
is_spoiler
=
this
.
get
(
'
composing_spoiler
'
);
const
origin_id
=
u
.
getUniqueId
();
const
body
=
text
?
u
.
httpToGeoUri
(
u
.
shortnameToUnicode
(
text
),
_converse
)
:
undefined
;
return
{
'
from
'
:
_converse
.
bare_jid
,
'
fullname
'
:
_converse
.
xmppstatus
.
get
(
'
fullname
'
),
'
id
'
:
origin_id
,
'
is_only_emojis
'
:
text
?
u
.
isOnlyEmojis
(
text
)
:
false
,
'
jid
'
:
this
.
get
(
'
jid
'
),
'
nickname
'
:
this
.
get
(
'
nickname
'
)
,
'
message
'
:
body
,
'
msgid
'
:
origin_id
,
'
origin_id
'
:
origin_id
,
'
fullname
'
:
_converse
.
xmppstatus
.
get
(
'
fullname
'
),
'
from
'
:
_converse
.
bare_jid
,
'
is_only_emojis
'
:
text
?
u
.
isOnlyEmojis
(
text
)
:
false
,
'
nickname
'
:
this
.
get
(
'
nickname
'
),
'
sender
'
:
'
me
'
,
'
time
'
:
(
new
Date
()).
toISOString
(),
'
message
'
:
text
?
u
.
httpToGeoUri
(
u
.
shortnameToUnicode
(
text
),
_converse
)
:
undefined
,
'
is_spoiler
'
:
is_spoiler
,
'
spoiler_hint
'
:
is_spoiler
?
spoiler_hint
:
undefined
,
'
type
'
:
this
.
get
(
'
message_type
'
)
'
time
'
:
(
new
Date
()).
toISOString
(),
'
type
'
:
this
.
get
(
'
message_type
'
),
body
,
is_spoiler
,
origin_id
}
},
...
...
src/headless/converse-emoji.js
View file @
be20b8e1
This diff is collapsed.
Click to expand it.
src/headless/converse-muc.js
View file @
be20b8e1
...
...
@@ -964,8 +964,6 @@ converse.plugins.add('converse-muc', {
if
(
!
raw_mentions
)
return
[
original_message
,
[]];
const
known_nicknames
=
this
.
getAllKnownNicknames
();
const
known_nicknames_with_at_regex
=
this
.
getAllKnownNicknamesRegex
();
const
getMatchesForNickRegex
=
nick_regex
=>
[...
findRegexInMessage
(
nick_regex
)];
const
getMatchingNickname
=
p
.
findFirstMatchInArray
(
known_nicknames
);
const
uriFromNickname
=
nickname
=>
{
...
...
@@ -985,7 +983,7 @@ converse.plugins.add('converse-muc', {
return
{
begin
,
end
,
value
,
type
,
uri
}
}
const
mentions
=
getMatchesForNickRegex
(
known_nicknames_with_at_regex
)
;
const
mentions
=
[...
findRegexInMessage
(
this
.
getAllKnownNicknamesRegex
())]
;
const
references
=
mentions
.
map
(
matchToReference
);
const
[
updated_message
,
updated_references
]
=
p
.
reduceTextFromReferences
(
...
...
src/headless/emojis.json
View file @
be20b8e1
{
"custom"
:
{
":converse:"
:{
"sn"
:
":converse:"
,
"url"
:
"/dist/custom_emojis/converse.png"
,
"c"
:
"custom"
},
":xmpp:"
:{
"sn"
:
":xmpp:"
,
"url"
:
"/dist/custom_emojis/xmpp.png"
,
"c"
:
"custom"
}
":converse:"
:{
"sn"
:
":converse:"
,
"url"
:
"/dist/
images/
custom_emojis/converse.png"
,
"c"
:
"custom"
},
":xmpp:"
:{
"sn"
:
":xmpp:"
,
"url"
:
"/dist/
images/
custom_emojis/xmpp.png"
,
"c"
:
"custom"
}
},
"smileys"
:
{
":smiley:"
:{
"sn"
:
":smiley:"
,
"cp"
:
"1f603"
,
"sns"
:[],
"c"
:
"smileys"
},
...
...
src/templates/directives/body.js
View file @
be20b8e1
...
...
@@ -30,12 +30,12 @@ class MessageBodyRenderer extends String {
text
=
text
.
replace
(
/
\n\n
+/g
,
'
\n\n
'
);
text
=
u
.
geoUriToHttp
(
text
,
_converse
.
geouri_replacement
);
const
process
=
(
text
)
=>
{
text
=
u
.
addEmoji
(
text
);
return
addMentionsMarkup
(
text
,
this
.
model
.
get
(
'
references
'
),
this
.
model
.
collection
.
chatbox
);
}
const
list
=
await
Promise
.
all
(
u
.
addHyperlinks
(
text
));
this
.
list
=
list
.
reduce
((
acc
,
i
)
=>
isString
(
i
)
?
[...
acc
,
...
proces
s
(
i
)]
:
[...
acc
,
i
],
[]);
let
list
=
await
Promise
.
all
(
u
.
addHyperlinks
(
text
));
list
=
list
.
reduce
((
acc
,
i
)
=>
isString
(
i
)
?
[...
acc
,
...
u
.
addEmoji
(
i
)]
:
[...
acc
,
i
],
[]
);
const
addMentions
=
text
=>
addMentionsMarkup
(
text
,
this
.
model
.
get
(
'
references
'
),
this
.
model
.
collection
.
chatbox
)
list
=
list
.
reduce
((
acc
,
i
)
=>
isString
(
i
)
?
[...
acc
,
...
addMention
s
(
i
)]
:
[...
acc
,
i
],
[]);
/**
* Synchronous event which provides a hook for transforming a chat message's body text
* after the default transformations have been applied.
...
...
@@ -45,8 +45,7 @@ class MessageBodyRenderer extends String {
* @example _converse.api.listen.on('afterMessageBodyTransformed', (view, text) => { ... });
*/
await
api
.
trigger
(
'
afterMessageBodyTransformed
'
,
this
.
model
,
text
,
{
'
Synchronous
'
:
true
});
return
this
.
list
;
return
list
;
}
async
render
()
{
...
...
src/templates/emoji_picker.js
View file @
be20b8e1
import
{
html
}
from
"
lit-html
"
;
import
{
__
}
from
'
@converse/headless/i18n
'
;
import
{
unsafeHTML
}
from
'
lit-html/directives/unsafe-html.js
'
;
import
xss
from
"
xss/dist/xss
"
;
const
i18n_search
=
__
(
'
Search
'
);
...
...
@@ -10,7 +8,6 @@ const skintones = ['tone1', 'tone2', 'tone3', 'tone4', 'tone5'];
const
emoji_category
=
(
o
)
=>
{
const
category_emoji
=
unsafeHTML
(
xss
.
filterXSS
(
o
.
transformCategory
(
o
.
emoji_categories
[
o
.
category
]),
{
'
whiteList
'
:
{
'
img
'
:
[
'
class
'
,
'
draggable
'
,
'
alt
'
,
'
src
'
,
'
title
'
]}}));
return
html
`
<li data-category="
${
o
.
category
}
"
class="emoji-category
${
o
.
category
}
${(
o
.
current_category
===
o
.
category
)
?
'
picked
'
:
''
}
"
...
...
@@ -19,7 +16,7 @@ const emoji_category = (o) => {
<a class="pick-category"
@click=
${
o
.
onCategoryPicked
}
href="#emoji-picker-
${
o
.
category
}
"
data-category="
${
o
.
category
}
">
${
category_emoji
}
</a>
data-category="
${
o
.
category
}
">
${
o
.
transformCategory
(
o
.
emoji_categories
[
o
.
category
])
}
</a>
</li>
`
;
}
...
...
@@ -30,12 +27,10 @@ const emoji_picker_header = (o) => html`
</ul>
`
;
const
emoji_item
=
(
o
)
=>
{
const
emoji
=
unsafeHTML
(
xss
.
filterXSS
(
o
.
transform
(
o
.
emoji
.
sn
),
{
'
whiteList
'
:
{
'
img
'
:
[
'
class
'
,
'
draggable
'
,
'
alt
'
,
'
src
'
,
'
title
'
]}}));
return
html
`
<li class="emoji insert-emoji
${
o
.
shouldBeHidden
(
o
.
emoji
.
sn
)
?
'
hidden
'
:
''
}
" data-emoji="
${
o
.
emoji
.
sn
}
" title="
${
o
.
emoji
.
sn
}
">
<a href="#" @click=
${
o
.
onEmojiPicked
}
data-emoji="
${
o
.
emoji
.
sn
}
">
${
emoji
}
</a>
<a href="#" @click=
${
o
.
onEmojiPicked
}
data-emoji="
${
o
.
emoji
.
sn
}
">
${
o
.
transform
(
o
.
emoji
.
sn
)
}
</a>
</li>
`
;
}
...
...
@@ -58,11 +53,9 @@ const emojis_for_category = (o) => html`
const
skintone_emoji
=
(
o
)
=>
{
const
shortname
=
'
:
'
+
o
.
skintone
+
'
:
'
;
const
emoji
=
unsafeHTML
(
xss
.
filterXSS
(
o
.
transform
(
shortname
),
{
'
whiteList
'
:
{
'
img
'
:
[
'
class
'
,
'
draggable
'
,
'
alt
'
,
'
src
'
,
'
title
'
]}}));
return
html
`
<li data-skintone="
${
o
.
skintone
}
" class="emoji-skintone
${(
o
.
current_skintone
===
o
.
skintone
)
?
'
picked
'
:
''
}
">
<a class="pick-skintone" href="#" data-skintone="
${
o
.
skintone
}
" @click=
${
o
.
onSkintonePicked
}
>
${
emoji
}
</a>
<a class="pick-skintone" href="#" data-skintone="
${
o
.
skintone
}
" @click=
${
o
.
onSkintonePicked
}
>
${
o
.
transform
(
'
:
'
+
o
.
skintone
+
'
:
'
)
}
</a>
</li>
`
;
}
...
...
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