Changes for page MentionsMacro


on 2023-02-01 12:03

on 2020-06-29 20:57
Summary
Details
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,37 +1,57 @@ 1 1 require.config({ 2 2 paths: { 3 - 'xwiki-suggestUsers': $jsontool.serialize($xwiki.getSkinFile('uicomponents/suggest/suggestUsersAndGroups.js')) 3 + 'xwiki-suggestUsers': "$xwiki.getSkinFile('uicomponents/suggest/suggestUsersAndGroups.js', true))" + 4 + "?v=$escapetool.url($xwiki.version)" 4 4 } 5 5 }); 6 -require(['deferred!ckeditor', 'xwiki-suggestUsers', 'jquery', 'xwiki-meta'], function (ckeditorPromise, suggestUsers, $, xm) { 7 - 7 +require(['deferred!ckeditor', 'xwiki-suggestUsers', 'jquery'], function (ckeditorPromise, suggestUsers, $) { 8 + /* 9 + * Keep records of the added anchors during the current edit session. 10 + * Note that the anchors saved here are not only the ones added on the current session, 11 + * but also those already present in the document. 12 + * For more information, see #getAnchor. 13 + * The information are stored on the form: 14 + * { reference: Array<String> } 15 + */ 16 + const anchorIds = {}; 17 + 8 8 /** 9 9 * Get the current wiki scope for displaying global, local or global and local users 10 10 */ 11 11 const userScope = "$!services.wiki.user.userScope"; 12 - 13 - // see https://stackoverflow.com/a/6248722/657524 14 - function random6chars() { 15 - // I generate the UID from two parts here 16 - // to ensure the random number provide enough bits. 17 - var firstPart = (Math.random() * 46656) | 0; 18 - var secondPart = (Math.random() * 46656) | 0; 19 - firstPart = ("000" + firstPart.toString(36)).slice(-3); 20 - secondPart = ("000" + secondPart.toString(36)).slice(-3); 21 - return firstPart + secondPart; 22 - } 23 - 22 + 24 24 /** 25 25 * Compute a new unique anchor for the given reference. 26 - * The unique anchor isbasedonthementionned user id,concatenaedwitha random stringof6 alphanumeric27 - * c haracters.28 - * Thechancesofcollisionare quite low,about46kmentionsforagivenmentioneduseronagivenpage (assuming29 - * thatnomentionsare ever deleted).25 + * The uniqueness of the anchor is given by two mechanisms: 26 + * - retrieve on first call all mentions available on current document and store them 27 + * - then use that information to compute a next anchor not overlapping an existing one on the current document. 28 + * The mechanism is obviously not perfect and might be improved later but should be enough for most usage. 30 30 */ 31 31 const getAnchor = function (reference) { 32 - const refId = reference.replace(/[.:]/g, '-'); 33 - const randomId = random6chars(); 34 - return refId + '-' + randomId; 31 + var existingIds; 32 + 33 + if (anchorIds.hasOwnProperty(reference)) { 34 + existingIds = anchorIds[reference]; 35 + } else { 36 + existingIds = []; 37 + $('.xwiki-mention').each(function() { 38 + var mention = $(this); 39 + if (mention.attr('data-reference') === reference) { 40 + existingIds.push(mention.attr('id')); 41 + } 42 + }); 43 + anchorIds[reference] = existingIds; 44 + } 45 + 46 + var counter = existingIds.length + 1; 47 + var refId = reference.replace(/[.:]/g, '-'); 48 + var proposedAnchor = refId + "-" + counter; 49 + while (existingIds.indexOf(proposedAnchor) != -1) { 50 + counter++; 51 + proposedAnchor = refId + "-" + counter; 52 + } 53 + anchorIds[reference].push(proposedAnchor); 54 + return proposedAnchor; 35 35 }; 36 36 37 37 const search = function (text, callback) { ... ... @@ -39,8 +39,8 @@ 39 39 'input': text, 40 40 'limit': 6, 41 41 }; 42 - suggestUsers.loadUsers(userScope, params).then(user s=>{43 - const cct = user s.map(function (x) {62 + $.when(suggestUsers.loadUsers(userScope, params)).then(function (user) { 63 + const cct = user.map(function (x) { 44 44 // insert an id because that's required by the mentions plugins. 45 45 x.id = x.value; 46 46 // Make sure to display the icon avatar or the image one. ... ... @@ -56,11 +56,11 @@ 56 56 return x; 57 57 }); 58 58 callback(cct); 59 - }) ;79 + }) 60 60 } 61 61 62 - ckeditorPromise. then(ckeditor=>{63 - function getUserMentionsConfig(editor) {82 + ckeditorPromise.done(function (ckeditor) { 83 + function confMentions(name) { 64 64 return { 65 65 feed: function (opts, callback) { 66 66 search(opts.query, callback); ... ... @@ -68,21 +68,21 @@ 68 68 marker: '@', 69 69 minChars: 0, 70 70 itemsLimit: 6, 71 - itemTemplate: 72 - `<li data-id="{id}" class="ckeditor-autocomplete-item"> 73 - <div> 74 - <span class="ckeditor-autocomplete-item-icon-wrapper"> 75 - <span class="{cssClass}"></span> 76 - <img src="{imgUrl}" class="{imgClass}"/> 77 - </span> 78 - <span class="ckeditor-autocomplete-item-label">{label}</span> 79 - </div> 80 - </li>`, 91 + itemTemplate: '<li data-id="{id}" class="ckeditor-autocomplete-item">'+ 92 + '<div>'+ 93 + '<span class="ckeditor-autocomplete-item-icon-wrapper">'+ 94 + '<span class="{cssClass}"></span>'+ 95 + '<img src="{imgUrl}" class="{imgClass}"/>'+ 96 + '</span>'+ 97 + '<span class="ckeditor-autocomplete-item-label">{label}</span>'+ 98 + '</div>'+ 99 + '</li>', 81 81 outputTemplate: function (param) { 82 - editor.once('afterInsertHtml', function() { 101 + var editor = ckeditor.instances[name]; 102 + editor.once('afterInsertHtml', function () { 83 83 editor.execCommand('xwiki-macro-insert', { 84 84 name: 'mention', 85 - inline: 'enforce',105 + inline: true, 86 86 parameters: { 87 87 reference: param.id, 88 88 style: 'FULL_NAME', ... ... @@ -97,19 +97,22 @@ 97 97 }; 98 98 } 99 99 100 - function updateConfig(editor) { 101 - editor.config.mentions = editor.config.mentions || []; 102 - editor.config.mentions.push(getUserMentionsConfig(editor)); 120 + function updateConf(config, name) { 121 + const newConf = config; 122 + newConf.mentions = newConf.mentions || []; 123 + newConf.mentions.push(confMentions(name)); 124 + return newConf; 103 103 } 104 104 105 - ckeditor. on('instanceCreated', function(event) {106 - // Theeditorinstancewascreated butit notyet initialized. Unfortunatelytheconfigurationobject passed when107 - // theinstancewascreatedhasnot beenmerged withtheglobalconfigurationyet.108 - event.editor.once('configLoaded', function(event) {109 - // The editor configuration has been loaded (the instance configuration has been merged with the global110 - // configuration) but the editorhas not been fully initializedyetso wecan modifythe configuration.111 - updateConfig(event.editor);112 - });113 - } );127 + var oldReplace = ckeditor.replace; 128 + ckeditor.replace = function (element, config) { 129 + return oldReplace.call(this, element, updateConf(config, element.id)); 130 + }; 131 + 132 + var oldInline = ckeditor.inline; 133 + ckeditor.inline = function (element, config) { 134 + return oldInline.call(this, element, updateConf(config, element.id)); 135 + }; 114 114 }); 115 115 }); 138 +
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -11,7 +11,3 @@ 11 11 .xwiki-mention.removed { 12 12 text-decoration: line-through; 13 13 } 14 - 15 -blockquote.mention-quote { 16 - font-size: inherit; 17 -}
- XWiki.WikiMacroClass[0]
-
- Macro code
-
... ... @@ -1,18 +1,26 @@ 1 1 {{velocity}} 2 2 #set ($reference = $wikimacro.parameters.reference) 3 3 #set ($style = $wikimacro.parameters.style) 4 -#set ($type = "$!wikimacro.parameters.type") 5 -#set ($content = $services.mentions.format($reference.reference, $style, $type)) 6 6 #set ($anchor = $wikimacro.parameters.anchor) 7 -#set ($isCurrentUser = $xcontext.userReference == $reference.reference && ($type == '' || $type == 'user')) 5 +#set ($userProperties = $services.user.getProperties($reference)) 6 +#set ($firstName = $userProperties.getFirstName()) 7 +#set ($lastName = $userProperties.getLastName()) 8 +#set ($isCurrentUser = $xcontext.userReference == $reference.reference) 8 8 #set ($cssClasses = ['xwiki-mention', 'user']) 9 9 #if ($isCurrentUser) 10 10 #set ($discard = $cssClasses.add('self')) 11 11 #end 13 +#if ("$!firstName" == "") 14 + #set($content = "@$reference.reference.name") 15 +#elseif ($style == 'FIRST_NAME') 16 + #set($content = "@$firstName") 17 +#elseif ($style == 'LOGIN') 18 + #set($content = "@$reference.reference.name") 19 +#else 20 + #set($content = "@$firstName $!lastName") 21 +#end 12 12 #set ($link = $xwiki.getURL($reference.reference, 'view')) 13 13 {{html}} 14 -<a id="$escapetool.xml($anchor)" class="$stringtool.join($cssClasses, ' ')" data-reference="$escapetool.xml($services.model.serialize($reference.reference, 'default'))" href="$escapetool.xml($link)">## 15 - $escapetool.xml($content)## Do not remove this comment as it ensures that the spacing after mention is not broken. 16 -</a> 24 +<a id="$anchor" class="$stringtool.join($cssClasses, ' ')" data-reference="$services.model.serialize($reference.reference, 'compactwiki')" href="$link">$content</a> 17 17 {{/html}} 18 18 {{/velocity}} - Macro description
-
... ... @@ -1,1 +1,1 @@ 1 -Insert sa user mention.1 +Insert a user mention. - Default categories
-
... ... @@ -1,1 +1,0 @@ 1 -Notifications
- XWiki.WikiMacroParameterClass[3]
-
- Parameter description
-
... ... @@ -1,1 +1,0 @@ 1 -The type of mentioned actor. - Parameter name
-
... ... @@ -1,1 +1,0 @@ 1 -type - Parameter type
-
... ... @@ -1,1 +1,0 @@ 1 -java.lang.String