@@ -1097,7 +1097,7 @@ class UserMentionNode extends MentionNode {
10971097
10981098 /// The ID of the user being mentioned.
10991099 ///
1100- /// This is null for wildcard mentions, user group mentions,
1100+ /// This is null for wildcard mentions
11011101 /// or when the user ID is unavailable in the HTML (e.g., legacy mentions).
11021102 final int ? userId;
11031103
@@ -1108,6 +1108,27 @@ class UserMentionNode extends MentionNode {
11081108 }
11091109}
11101110
1111+ class UserGroupMentionNode extends MentionNode {
1112+ const UserGroupMentionNode ({
1113+ super .debugHtmlNode,
1114+ required super .nodes,
1115+ required super .isSilent,
1116+ required this .userGroupId,
1117+ });
1118+
1119+ /// The ID of the user group being mentioned.
1120+ ///
1121+ /// This is non-nullable because user group mentions
1122+ /// always have data-user-group-id.
1123+ final int userGroupId;
1124+
1125+ @override
1126+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
1127+ super .debugFillProperties (properties);
1128+ properties.add (IntProperty ('userGroupId' , userGroupId));
1129+ }
1130+ }
1131+
11111132// TODO(#646) add WildcardMentionNode
11121133
11131134sealed class EmojiNode extends InlineContentNode {
@@ -1325,15 +1346,16 @@ class _ZulipInlineContentParser {
13251346 i++ ;
13261347 }
13271348
1349+ String ? mentionType;
13281350 if (i >= classes.length) return null ;
13291351 if ((classes[i] == 'topic-mention' && ! hasChannelWildcardClass)
13301352 || classes[i] == 'user-mention'
13311353 || (classes[i] == 'user-group-mention' && ! hasChannelWildcardClass)) {
13321354 // The class we already knew we'd find before we called this function.
1333- // We ignore the distinction between these; see [UserMentionNode].
1334- // Also, we don't expect "user-group-mention" and "channel-wildcard-mention"
1355+ // We don't expect "user-group-mention" and "channel-wildcard-mention"
13351356 // to be in the list at the same time and neither we expect "topic-mention"
13361357 // and "channel-wildcard-mention" to be in the list at the same time.
1358+ mentionType = classes[i];
13371359 i++ ;
13381360 }
13391361
@@ -1342,21 +1364,35 @@ class _ZulipInlineContentParser {
13421364 return null ;
13431365 }
13441366
1345- final userId = switch (element.attributes['data-user-id' ]) {
1346- // For legacy, user group or wildcard mentions.
1347- null || '*' => null ,
1348- final userIdString => int .tryParse (userIdString, radix: 10 ),
1349- };
1350-
13511367 // TODO assert MentionNode can't contain LinkNode;
13521368 // either a debug-mode check, or perhaps we can make expectations much
13531369 // tighter on a MentionNode's contents overall.
13541370 final nodes = parseInlineContentList (element.nodes);
1355- return UserMentionNode (
1356- nodes: nodes,
1357- userId: userId,
1358- isSilent: isSilent,
1359- debugHtmlNode: debugHtmlNode);
1371+
1372+ if (mentionType case 'user-group-mention' ) {
1373+ final userGroupId = int .tryParse (
1374+ element.attributes['data-user-group-id' ] ?? '' ,
1375+ radix: 10 );
1376+ if (userGroupId == null ) {
1377+ return null ;
1378+ }
1379+ return UserGroupMentionNode (
1380+ nodes: nodes,
1381+ isSilent: isSilent,
1382+ userGroupId: userGroupId,
1383+ debugHtmlNode: debugHtmlNode);
1384+ } else {
1385+ final userId = switch (element.attributes['data-user-id' ]) {
1386+ // For legacy or wildcard mentions.
1387+ null || '*' => null ,
1388+ final userIdString => int .tryParse (userIdString, radix: 10 ),
1389+ };
1390+ return UserMentionNode (
1391+ nodes: nodes,
1392+ isSilent: isSilent,
1393+ userId: userId,
1394+ debugHtmlNode: debugHtmlNode);
1395+ }
13601396 }
13611397
13621398 /// The links found so far in the current block inline container.
0 commit comments