Skip to content

Commit

Permalink
fix: Fix the users mention in CKeditor for the kudos case - MEED-2749 -
Browse files Browse the repository at this point in the history
Meeds-io/meeds#1200 (#3090)

This change will generalize the mention of users, which are not members of the space selected, in the ckeditor in order to use it in the kudos module and other modules.
  • Loading branch information
MayTekayaa authored and boubaker committed Oct 27, 2023
1 parent ef26f20 commit d0fbc14
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ CKEDITOR.editorConfig = function(config) {

// Here is configure for suggester
var peopleSearchCached = {};
document.addEventListener('suggester-clear-people-cache', () => peopleSearchCached = {});
var lastNoResultQuery = false;
config.suggester = {
suffix: '\u00A0',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@
use-draft-management
autofocus
@attachments-edited="attachmentsEdit" />
<div v-if="containInvalidUsers" class="mt-4">{{ $t('activity.composer.invalidUsers.message') }}</div>
</v-card-text>
<v-card-actions class="d-flex px-4">
<extension-registry-components
Expand Down Expand Up @@ -194,8 +193,7 @@ export default {
postToNetwork: eXo.env.portal.postToNetworkEnabled,
audienceChoice: 'yourNetwork',
audience: '',
username: eXo.env.portal.userName,
containInvalidUsers: false
username: eXo.env.portal.userName
};
},
computed: {
Expand Down Expand Up @@ -287,9 +285,6 @@ export default {
if (newVal === 'yourNetwork') {
this.removeAudience();
}
},
spaceURL() {
this.resetRichEditorData();
}
},
created() {
Expand Down Expand Up @@ -344,16 +339,7 @@ export default {
postMessage() {
// Using a ref to the editor component and the getMessage method is mandatory to
// be sure to get the most up to date value of the message
let message = this.ckEditorInstance.getMessage();
const tempdiv = $('<div class=\'temp\'/>').html(message || '');
tempdiv.find('[data-atwho-at-value]')
.each(function() {
const value = $(this).attr('data-atwho-at-value');
const pattern = new RegExp(`<span class="atwho-inserted" data-atwho-at-query="[^"]*" data-atwho-at-value="${value}"[^>]*>(.*?)</span> </span>`, 'g');
message = message.replace(pattern, value ? `@${value}` : '');
});
this.templateParams.comment = message;
this.templateParams.default_title = message;
const message = this.ckEditorInstance.getMessage();
if (this.activityId) {
let activityType = this.activityType;
if (this.templateParams && this.templateParams.link && !this.activityType) {
Expand Down Expand Up @@ -457,76 +443,7 @@ export default {
},
removeAudience() {
this.audience = '';
},
replaceValidSuggestedUser(message, profile, pattern) {
return message.replace(new RegExp(pattern, 'g'), ExtendedDomPurify.purify(`
<span class="atwho-inserted" data-atwho-at-query="@${profile.username}" data-atwho-at-value="${profile.username}" contenteditable="false">
<span class="exo-mention">${profile.fullname}${profile.isExternal === 'true' ? ` (${ this.$t('UsersManagement.type.external') })` : ''}<a href="#" class="remove"><i class="uiIconClose uiIconLightGray"></i></a></span>
</span>
`));
},
replaceInvalidSuggestedUser(message, profile, pattern) {
return message.replace(new RegExp(pattern, 'g'), ExtendedDomPurify.purify(`
<span class="atwho-inserted" data-atwho-at-query="@${profile.username}" data-atwho-at-value="" contenteditable="false" title="${this.$t('activity.composer.invalidUser.message')}">
<span class="exo-mention">
<i aria-hidden="true" class="v-icon notranslate fa fa-exclamation-triangle theme--light orange--text error-color" style="font-size: 16px;">
</i>
<del>${profile.fullname}${profile.isExternal === 'true' ? ` (${ this.$t('UsersManagement.type.external') })` : ''}</del>
<a href="#" class="remove">
<i class="uiIconClose uiIconLightGray"></i>
</a>
</span>
</span>
`));
},
resetRichEditorData() {
let message = this.ckEditorInstance.getMessage();
const mentionedUsers = message.match(/@([A-Za-z0-9_'.+-]+)/g)?.map(a => a.replace('@', '')) || null;
this.containInvalidUsers = false;
if (mentionedUsers?.length) {
// Clear suggester cache
document.dispatchEvent(new CustomEvent('suggester-clear-people-cache'));
Promise
.all(mentionedUsers.map(username => {
return this.$identityService.getIdentityByProviderIdAndRemoteId('organization', username)
.then(identity => {
if (!identity?.profile) {
return null;
}
if (this.audience?.spaceId) {
return this.$spaceService.isSpaceMember(this.audience.spaceId, username)
.then(data => {
if (data) {
const profile = identity.profile;
profile.isMember = data?.isMember === 'true';
return profile;
} else {
return null;
}
});
} else {
const profile = identity.profile;
profile.isMember = true;
return profile;
}
});
}))
.then(userProfiles => userProfiles.filter(p => p))
.then(userProfiles => {
const containsExoMentionClass = message.search('exo-mention') >= 0;
this.containInvalidUsers = !!userProfiles.find(profile => profile.isMember !== true);
userProfiles.forEach(profile => {
const pattern = containsExoMentionClass ? `<span class="atwho-inserted" data-atwho-at-query="@${profile.username}"[^>]*>(.*?)</span> </span>` : `@${profile.username}`;
if (profile.isMember) {
message = this.replaceValidSuggestedUser(message, profile, pattern);
} else {
message = this.replaceInvalidSuggestedUser(message, profile, pattern);
}
});
this.ckEditorInstance?.initCKEditorData?.(message);
});
}
},
}
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<i class="uiIconMessageLength"></i>
</div>
</div>
<div v-if="containInvalidUsers" class="mt-4 text-sub-title">{{ $t('activity.composer.invalidUsers.message') }}</div>
<attachments-image-input
v-if="displayAttachmentEditor"
ref="attachmentsInput"
Expand Down Expand Up @@ -158,6 +159,9 @@ export default {
oembedParams: null,
editor: null,
baseUrl: eXo.env.server.portalBaseURL,
containInvalidUsers: false,
spaceId: null,
backUpMessage: null
}),
computed: {
ckEditorInstanceId() {
Expand Down Expand Up @@ -223,14 +227,25 @@ export default {
},
suggesterSpaceURL() {
if (this.editorReady) {
this.editor.config.spaceURL = this.suggesterSpaceURL;
if (this.suggesterSpaceURL) {
this.getSpaceId().then(() => this.initCKEditor(true, this.backUpMessage));
} else {
this.spaceId = null;
this.initCKEditor(true, this.backUpMessage);
}
}
},
displayAttachmentEditor(newVal, oldVal) {
if (newVal && !oldVal) {
this.$nextTick().then(() => this.$refs?.attachmentsInput?.init());
}
},
editor() {
const mentionedUsers = this.backUpMessage?.match(/@([A-Za-z0-9_'.+-]+)/g)?.map(a => a.replace('@', '')) || null;
if (mentionedUsers?.length && !this.spaceId) {
this.replaceSuggestedUsers(this.backUpMessage, mentionedUsers, this.spaceId);
}
}
},
created() {
// Load CKEditor only when needed
Expand Down Expand Up @@ -465,6 +480,10 @@ export default {
if (!content) {
return '';
}
const mentionedUsers = content.match(/@([A-Za-z0-9_'.+-]+)/g)?.map(a => a.replace('@', '')) || null;
if (mentionedUsers?.length) {
this.replaceSuggestedUsers(content, mentionedUsers, this.spaceId);
}
if (content.includes('<oembed>') && content.includes('</oembed>')) {
const oembedUrl = window.decodeURIComponent(content.match(/<oembed>(.*)<\/oembed>/i)[1]);
content = content.replace(/<oembed>(.*)<\/oembed>/g, '');
Expand All @@ -482,6 +501,7 @@ export default {
return this.getContentNoEmbed(content);
},
getContentToSave(content) {
content = this.updateMessageBeforPost(content);
return this.getContent(content, true);
},
getContent(content, cleanOembedParams) {
Expand Down Expand Up @@ -602,6 +622,84 @@ export default {
});
return tempdiv.html();
},
replaceValidSuggestedUser(message, profile, pattern) {
return message.replace(new RegExp(pattern, 'g'), ExtendedDomPurify.purify(`
<span class="atwho-inserted" data-atwho-at-query="@${profile.username}" data-atwho-at-value="${profile.username}" contenteditable="false">
<span class="exo-mention">${profile.fullname}${profile.isExternal === 'true' ? ` (${ this.$t('UsersManagement.type.external') })` : ''}<a href="#" class="remove"><i class="uiIconClose uiIconLightGray"></i></a></span>
</span>
`));
},
replaceInvalidSuggestedUser(message, profile, pattern) {
return message.replace(new RegExp(pattern, 'g'), ExtendedDomPurify.purify(`
<span class="atwho-inserted" data-atwho-at-query="@${profile.username}" data-atwho-at-value="" contenteditable="false" title="${this.$t('activity.composer.invalidUser.message')}">
<span class="exo-mention">
<i aria-hidden="true" class="v-icon notranslate fa fa-exclamation-triangle theme--light orange--text error-color" style="font-size: 16px;">
</i>
<del>${profile.fullname}${profile.isExternal === 'true' ? ` (${ this.$t('UsersManagement.type.external') })` : ''}</del>
<a href="#" class="remove">
<i class="uiIconClose uiIconLightGray"></i>
</a>
</span>
</span>
`));
},
replaceSuggestedUsers(message, mentionedUsers, spaceId) {
this.containInvalidUsers = false;
Promise
.all(mentionedUsers.map(username => {
return this.$identityService.getIdentityByProviderIdAndRemoteId('organization', username)
.then(identity => {
if (!identity?.profile) {
return null;
}
if (spaceId) {
return this.$spaceService.isSpaceMember(spaceId, username)
.then(data => {
if (data) {
const profile = identity.profile;
profile.isMember = data?.isMember === 'true';
return profile;
} else {
return null;
}
});
} else {
const profile = identity.profile;
profile.isMember = true;
return profile;
}
});
}))
.then(userProfiles => userProfiles.filter(p => p))
.then(userProfiles => {
const containsExoMentionClass = message.search('exo-mention') >= 0;
this.containInvalidUsers = !!userProfiles.find(profile => profile.isMember !== true);
userProfiles.forEach(profile => {
const pattern = containsExoMentionClass ? `<span [^>]* data-atwho-at-query="@${profile.username}" class="atwho-inserted">(.*?)</span> </span>` : `@${profile.username}`;
if (profile.isMember) {
message = this.replaceValidSuggestedUser(message, profile, pattern);
} else {
message = this.replaceInvalidSuggestedUser(message, profile, pattern);
}
});
this.backUpMessage = message;
this.editor?.setData(message);
});
},
updateMessageBeforPost(message) {
const tempdiv = $('<div class=\'temp\'/>').html(message || '');
tempdiv.find('[data-atwho-at-value]')
.each(function() {
const value = $(this).attr('data-atwho-at-value');
const pattern = new RegExp(`<span class="atwho-inserted" data-atwho-at-query="[^"]*" data-atwho-at-value="${value}"[^>]*>(.*?)</span> </span>`, 'g');
message = message.replace(pattern, value ? `@${value}` : '');
});
return message;
},
getSpaceId() {
return this.$spaceService.getSpaceByPrettyName(this.suggesterSpaceURL)
.then(space => this.spaceId = space.id);
}
}
};
</script>

0 comments on commit d0fbc14

Please sign in to comment.