Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
solid-xmpp-chat
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Components
solid-xmpp-chat
Merge requests
!113
History, Reply to messages and RAI
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
History, Reply to messages and RAI
beta
into
master
Overview
0
Commits
39
Pipelines
7
Changes
7
Merged
Emmanuel Vodor
requested to merge
beta
into
master
4 years ago
Overview
0
Commits
39
Pipelines
7
Changes
3
Expand
Contains
History loading various fixes
Reply button on messages (mucs and chats)
Replaced the original RAI implementation with the converse one
Closes
#262 (closed)
Edited
4 years ago
by
Emmanuel Vodor
0
0
Merge request reports
Compare
version 2
version 6
f7f7e29c
4 years ago
version 5
14c1699e
4 years ago
version 4
c337afe3
4 years ago
version 3
4df52a35
4 years ago
version 2
d4548a8b
4 years ago
version 1
e42a84c9
4 years ago
master (base)
and
version 3
latest version
22b64d40
39 commits,
4 years ago
version 6
f7f7e29c
37 commits,
4 years ago
version 5
14c1699e
35 commits,
4 years ago
version 4
c337afe3
32 commits,
4 years ago
version 3
4df52a35
31 commits,
4 years ago
version 2
d4548a8b
19 commits,
4 years ago
version 1
e42a84c9
17 commits,
4 years ago
Show latest version
3 files
+
110
−
182
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
3
Search (e.g. *.vue) (Ctrl+P)
src/plugins/converse-rai.js
+
104
−
179
Options
(
function
()
{
let
Strophe
,
$iq
,
$msg
,
$pres
,
$build
,
b64_sha1
,
_
,
Backbone
,
dayjs
,
_converse
;
let
interestingServers
=
new
Set
();
let
subscribedServers
=
new
Set
();
converse
.
plugins
.
add
(
'
converse-rai
'
,
{
'
dependencies
'
:
[],
'
initialize
'
:
function
()
{
_converse
=
this
.
_converse
;
Strophe
=
converse
.
env
.
Strophe
;
$iq
=
converse
.
env
.
$iq
;
$msg
=
converse
.
env
.
$msg
;
$pres
=
converse
.
env
.
$pres
;
$build
=
converse
.
env
.
$build
;
b64_sha1
=
converse
.
env
.
b64_sha1
;
_
=
converse
.
env
.
_
;
Backbone
=
converse
.
env
.
Backbone
;
dayjs
=
converse
.
env
.
dayjs
;
_converse
.
api
.
settings
.
extend
({
rai_notification
:
true
,
rai_notification_label
:
'
Room Activity Indicator
'
,
});
_converse
.
api
.
listen
.
on
(
'
connected
'
,
function
()
{
setupRoomActivityIndicators
();
});
_converse
.
api
.
listen
.
on
(
'
chatRoomViewInitialized
'
,
function
(
view
)
{
const
jid
=
view
.
model
.
get
(
'
jid
'
);
if
(
view
.
model
.
get
(
'
num_unread
'
)
>
0
||
view
.
model
.
get
(
'
num_unread_general
'
)
>
0
)
{
emitNotification
(
jid
);
}
});
_converse
.
api
.
listen
.
on
(
'
raiRoomsUpdated
'
,
function
(
rooms
)
{
interestingServers
=
new
Set
(
rooms
.
filter
(
room
=>
room
).
map
(
Strophe
.
getDomainFromJid
));
if
(
_converse
.
api
.
connection
.
connected
())
{
updateSubscriptions
();
}
});
_converse
.
api
.
listen
.
on
(
'
chatBoxScrolledDown
'
,
function
(
view
)
{
const
jid
=
view
.
chatbox
.
get
(
'
jid
'
);
const
id_attr
=
'
stanza_id
'
+
jid
;
const
messages
=
view
.
chatbox
.
messages
;
if
(
!
getUnreadStatus
(
jid
))
{
return
;
}
for
(
let
i
=
messages
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
message
=
messages
.
at
(
i
);
if
(
message
.
has
(
id_attr
))
{
let
id
=
message
.
get
(
id_attr
);
if
(
id
!=
sessionStorage
.
getItem
(
'
rai_displayed.
'
+
jid
))
{
sessionStorage
.
setItem
(
'
rai_displayed.
'
+
jid
,
id
);
setUnreadStatus
(
jid
,
false
);
setTimeout
(()
=>
sendMarker
(
jid
,
id
,
'
displayed
'
),
0
);
/**
* Add RAI support to MUCs.
* @see https://xmpp.org/extensions/inbox/room-activity-indicators.html
*/
converse
.
plugins
.
add
(
'
converse-rai
'
,
{
dependencies
:
[
'
converse-chatboxes
'
,
],
overrides
:
{
ChatRoom
:
{
async
initialize
()
{
await
this
.
__super__
.
initialize
.
apply
(
this
,
arguments
);
this
.
listenTo
(
this
,
'
change:hidden
'
,
this
.
onHiddenChange
);
},
/**
* Handler that gets called when the 'hidden' flag is toggled.
* @private
* @method _converse.ChatRoom#onHiddenChange
*/
async
onHiddenChange
()
{
const
conn_status
=
this
.
session
.
get
(
'
connection_status
'
);
const
{
api
}
=
this
.
__super__
.
_converse
;
if
(
this
.
get
(
'
hidden
'
)
&&
conn_status
===
converse
.
ROOMSTATUS
.
ENTERED
)
{
if
(
api
.
settings
.
get
(
'
muc_subscribe_to_rai
'
)
&&
this
.
getOwnAffiliation
()
!==
'
none
'
)
{
if
(
conn_status
!==
converse
.
ROOMSTATUS
.
DISCONNECTED
)
{
this
.
sendMarkerForLastMessage
(
'
received
'
,
true
);
await
this
.
leave
();
await
this
.
close
();
}
break
;
}
}
else
if
(
conn_status
===
converse
.
ROOMSTATUS
.
DISCONNECTED
)
{
await
this
.
rejoin
();
}
});
_converse
.
api
.
listen
.
on
(
'
chatBoxInsertedIntoDOM
'
,
function
(
view
)
{
const
jid
=
view
.
model
.
get
(
'
jid
'
);
},
},
ChatBox
:
{
/**
* Finds the last eligible message and then sends a XEP-0333 chat marker for it.
* @param { ('received'|'displayed'|'acknowledged') } [type='displayed']
* @param { Boolean } force - Whether a marker should be sent for the
* message, even if it didn't include a `markable` element.
*/
sendMarkerForLastMessage
(
type
=
'
displayed
'
,
force
=
false
)
{
const
msgs
=
Array
.
from
(
this
.
messages
.
models
);
msgs
.
reverse
();
const
msg
=
msgs
.
find
(
m
=>
m
.
get
(
'
sender
'
)
===
'
them
'
&&
(
force
||
m
.
get
(
'
is_markable
'
)));
msg
&&
this
.
sendMarkerForMessage
(
msg
,
type
,
force
);
},
},
},
initialize
()
{
const
{
Strophe
,
_
,
$pres
,
u
,
sizzle
,
log
}
=
converse
.
env
;
const
_converse
=
this
.
_converse
;
const
{
api
}
=
_converse
;
// Register namespace
Strophe
.
addNamespace
(
'
RAI
'
,
'
urn:xmpp:rai:0
'
);
// Register settings
api
.
settings
.
extend
({
muc_subscribe_to_rai
:
false
,
});
if
(
view
.
model
.
get
(
'
num_unread
'
)
>
0
)
{
emitNotification
(
jid
);
Object
.
assign
(
api
.
rooms
,
{
/**
* Send an RAI stanza for the given jids.
* The presence stanza is sent for a whole muc domain.
*
* @param {string|Array} jids
* @returns {void}
*/
subscribe
(
jids
)
{
if
(
!
api
.
settings
.
get
(
'
muc_subscribe_to_rai
'
))
{
console
.
error
(
'
Can
\'
t subscribe to RAI, this feature is not enabled
'
);
}
});
_converse
.
api
.
listen
.
on
(
'
message
'
,
function
(
data
)
{
var
chatbox
=
data
.
chatbox
;
var
history
=
data
.
attrs
.
is_archived
;
var
sender
=
data
.
attrs
.
sender
;
var
body
=
data
.
attrs
.
body
;
if
(
!
history
&&
body
&&
chatbox
&&
sender
!==
'
me
'
)
{
const
alert
=
chatbox
.
get
(
'
num_unread
'
)
>
0
;
const
notify
=
chatbox
.
get
(
'
num_unread_general
'
)
>
0
;
if
(
alert
||
notify
)
{
emitNotification
(
chatbox
.
get
(
'
jid
'
),
alert
);
}
if
(
typeof
jids
===
'
string
'
)
{
jids
=
[
jids
];
}
});
},
});
const
muc_domains
=
jids
.
map
(
jid
=>
Strophe
.
getDomainFromJid
(
jid
));
function
subscribeServer
(
server_name
)
{
const
id
=
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
);
_converse
.
connection
.
send
(
converse
.
env
.
$pres
({
to
:
server_name
,
id
:
id
,
}).
c
(
'
rai
'
,
{
'
xmlns
'
:
'
xmpp:prosody.im/protocol/rai
'
,
}));
}
function
unsubscribeServer
(
server_name
)
{
_converse
.
connection
.
send
(
converse
.
env
.
$pres
({
to
:
server_name
,
type
:
'
unavailable
'
,
}).
c
(
'
rai
'
,
{
'
xmlns
'
:
'
xmpp:prosody.im/protocol/rai
'
,
}));
}
function
updateSubscriptions
()
{
var
new_servers
=
new
Set
([...
interestingServers
].
filter
(
server
=>
!
subscribedServers
.
has
(
server
)));
var
obsolete_servers
=
new
Set
([...
subscribedServers
].
filter
(
server
=>
!
interestingServers
.
has
(
server
)));
for
(
let
server
of
obsolete_servers
)
{
unsubscribeServer
(
server
);
}
for
(
let
server
of
new_servers
)
{
subscribeServer
(
server
);
}
}
_
.
uniq
(
muc_domains
).
forEach
(
muc_domain
=>
{
const
rai
=
$pres
({
to
:
muc_domain
,
id
:
u
.
getUniqueId
()
}).
c
(
'
rai
'
,
{
'
xmlns
'
:
Strophe
.
NS
.
RAI
,
});
api
.
send
(
rai
);
console
.
log
(
'
Sent RAI stanza for muc_domain
'
,
muc_domain
,
rai
.
toString
());
});
},
});
function
setupRoomActivityIndicators
()
{
updateSubscriptions
();
// If we already have unread notifications stored for this session, emit them now
for
(
var
i
=
0
;
i
<
sessionStorage
.
length
;
i
++
)
{
if
(
sessionStorage
.
key
(
i
).
indexOf
(
'
rai_notify.
'
)
==
0
)
{
const
jid
=
sessionStorage
.
key
(
i
).
substring
(
11
);
emitNotification
(
jid
);
/**
* Triggers an event if a jid has activity.
*
* @param message
* @returns {boolean}
*/
function
mucActivityHandler
(
message
)
{
const
rai
=
sizzle
(
`rai[xmlns="
${
Strophe
.
NS
.
RAI
}
"]`
,
message
).
pop
();
if
(
rai
)
{
rai
.
querySelectorAll
(
'
activity
'
).
forEach
(
activity
=>
{
const
jid
=
activity
.
textContent
;
log
.
debug
(
`Received activity for the room:
${
jid
}
`
);
api
.
trigger
(
'
chatRoomHasActivity
'
,
jid
);
});
}
}
// Listen for incoming RAI from the server
_converse
.
connection
.
addHandler
(
function
(
message
)
{
const
from_jid
=
message
.
attributes
.
from
?.
nodevalue
;
const
room_jid
=
from_jid
?.
split
(
'
/
'
)[
0
];
const
room
=
''
;
let
ignore
=
false
;
for
(
let
i
=
0
;
i
<
_converse
.
chatboxes
.
models
.
length
;
i
++
)
{
if
(
_converse
.
chatboxes
.
models
[
i
].
id
===
room_jid
)
{
room
=
_converse
.
chatboxes
.
models
[
i
].
id
;
break
;
}
}
if
(
room
&&
from_jid
&&
room_jid
)
{
if
(
from_jid
===
room_jid
+
'
/
'
+
room
.
get
(
'
nick
'
))
{
ignore
=
true
;
}
}
if
(
message
&&
!
ignore
)
message
.
querySelectorAll
(
'
activity
'
).
forEach
(
function
(
activity
)
{
if
(
activity
&&
activity
.
namespaceURI
==
'
xmpp:prosody.im/protocol/rai
'
)
{
const
jid
=
activity
.
textContent
;
setUnreadStatus
(
jid
,
true
);
emitNotification
(
jid
);
}
});
return
true
;
},
null
,
'
message
'
);
}
function
setUnreadStatus
(
jid
,
flag
)
{
if
(
flag
)
{
sessionStorage
.
setItem
(
'
rai_notify.
'
+
jid
,
'
true
'
);
}
else
{
sessionStorage
.
removeItem
(
'
rai_notify.
'
+
jid
);
}
}
function
getUnreadStatus
(
jid
)
{
return
sessionStorage
.
getItem
(
'
rai_notify.
'
+
jid
)
==
'
true
'
;
}
function
emitNotification
(
jid
,
alert
)
{
_converse
.
api
.
trigger
(
'
chatRoomActivityIndicators
'
,
jid
);
}
function
sendMarker
(
to_jid
,
id
,
type
)
{
const
stanza
=
converse
.
env
.
$msg
({
'
from
'
:
_converse
.
connection
.
jid
,
'
id
'
:
Math
.
random
().
toString
(
36
).
substr
(
2
,
9
),
'
to
'
:
to_jid
,
'
type
'
:
'
groupchat
'
,
}).
c
(
type
,
{
'
xmlns
'
:
converse
.
env
.
Strophe
.
NS
.
MARKERS
,
'
id
'
:
id
,
// Register our RAI handler
api
.
listen
.
on
(
'
connected
'
,
()
=>
{
_converse
.
connection
.
addHandler
(
mucActivityHandler
,
null
,
'
message
'
);
});
_converse
.
api
.
send
(
stanza
);
}
})();
},
});
Loading