From 1df832e936e817ba4733497d09a14e321627e215 Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Thu, 1 Aug 2024 10:32:58 +0200 Subject: [PATCH 001/696] XWIKI-22378: Javascript console error XWiki.watchlist is undefined --- .../resources/js/xwiki/compatibility.js | 170 +++++++++--------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/js/xwiki/compatibility.js b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/js/xwiki/compatibility.js index e9637f9322a6..7649a29134e4 100644 --- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/js/xwiki/compatibility.js +++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/js/xwiki/compatibility.js @@ -374,7 +374,7 @@ Object.extend(XWiki.constants, { * Extracts the file name from the value of the specified file input. * @deprecated since 16.6.0RC1 */ - extractFileName: function(fileInput) { + extractFileName: function (fileInput) { warn("XWiki.extractFileName is deprecated since 16.6.0RC1."); fileInput = $(fileInput); if (fileInput.files && fileInput.files.length > 0) { @@ -397,99 +397,99 @@ Object.extend(XWiki.constants, { // The file input value is just the file name. return fileInput.value; } + } +}); + +/** + * Watchlist methods. + * + * @deprecated Since XWiki 7.4, the watchlist UI is implemented in a UI extension. This code is still there to not + * break the retro-compatibility but we can consider removing it. + */ +XWiki.watchlist = XWiki.watchlist || {}; +Object.extend(XWiki.watchlist, { + /** + * Mapping between link IDs and associated actions. + */ + actionsMap : { + 'tmWatchDocument' : 'adddocument', + 'tmUnwatchDocument' : 'removedocument', + 'tmWatchSpace' : 'addspace', + 'tmUnwatchSpace' : 'removespace', + 'tmWatchWiki' : 'addwiki', + 'tmUnwatchWiki' : 'removewiki' + }, + + /** + * Mapping allowing to know which action to display when a previous action has been executed. + */ + flowMap : { + 'tmWatchDocument' : 'tmUnwatchDocument', + 'tmUnwatchDocument' : 'tmWatchDocument', + 'tmWatchSpace' : 'tmUnwatchSpace', + 'tmUnwatchSpace' : 'tmWatchSpace', + 'tmWatchWiki' : 'tmUnwatchWiki', + 'tmUnwatchWiki' : 'tmWatchWiki' }, /** - * Watchlist methods. + * Execute a watchlist action (add or remove the given document/space/wiki from watchlist). * - * @deprecated Since XWiki 7.4, the watchlist UI is implemented in a UI extension. This code is still there to not - * break the retro-compatibility but we can consider removing it. + * @param element the element that fired the action. */ - watchlist : { - - /** - * Mapping between link IDs and associated actions. - */ - actionsMap : { - 'tmWatchDocument' : 'adddocument', - 'tmUnwatchDocument' : 'removedocument', - 'tmWatchSpace' : 'addspace', - 'tmUnwatchSpace' : 'removespace', - 'tmWatchWiki' : 'addwiki', - 'tmUnwatchWiki' : 'removewiki' - }, - - /** - * Mapping allowing to know which action to display when a previous action has been executed. - */ - flowMap : { - 'tmWatchDocument' : 'tmUnwatchDocument', - 'tmUnwatchDocument' : 'tmWatchDocument', - 'tmWatchSpace' : 'tmUnwatchSpace', - 'tmUnwatchSpace' : 'tmWatchSpace', - 'tmWatchWiki' : 'tmUnwatchWiki', - 'tmUnwatchWiki' : 'tmWatchWiki' - }, - - /** - * Execute a watchlist action (add or remove the given document/space/wiki from watchlist). - * - * @param element the element that fired the action. - */ - executeAction : function(element) { - warn("XWiki.watchlist is deprecated since 7.4."); - var surl = window.docgeturl + "?xpage=watch&do=" + this.actionsMap[element.id]; - new Ajax.Request( - surl, - { - method: 'get', - onComplete: function() { - if (element.nodeName == 'A') { - element.up().toggleClassName('hidden'); - $(XWiki.watchlist.flowMap[element.id]).up().toggleClassName('hidden'); - } else { - element.toggleClassName('hidden'); - $(XWiki.watchlist.flowMap[element.id]).toggleClassName('hidden'); - } - } - }); - }, - - /** - * Initialize watchlist UI. - */ - initialize: function(container) { - container = $(container || 'body'); - for (var button in XWiki.watchlist.actionsMap) { - var element = container.down('#' + button); - if (element) { - if (element.nodeName != 'A') { - element = $(button).down('A'); + executeAction : function(element) { + warn("XWiki.watchlist is deprecated since 7.4."); + var surl = window.docgeturl + "?xpage=watch&do=" + this.actionsMap[element.id]; + new Ajax.Request( + surl, + { + method: 'get', + onComplete: function() { + if (element.nodeName == 'A') { + element.up().toggleClassName('hidden'); + $(XWiki.watchlist.flowMap[element.id]).up().toggleClassName('hidden'); + } else { + element.toggleClassName('hidden'); + $(XWiki.watchlist.flowMap[element.id]).toggleClassName('hidden'); } + } + }); + }, - if (!element) { - // This is supposed to happen every time since the watchlist icons are implemented in the - // notifications - // menu. The watchlist icons are now implemented as a UI extension, and the inputs are handled - // with a - // custom solution (bootstrap-switch). - // For these reasons, we stop the initialization here. - // We keep this function for old skins (like Colibri), that still have the old-fashioned - // watchlist icons. - return; - } + /** + * Initialize watchlist UI. + */ + initialize: function(container) { + container = $(container || 'body'); + for (var button in XWiki.watchlist.actionsMap) { + var element = container.down('#' + button); + if (element) { + if (element.nodeName != 'A') { + element = $(button).down('A'); + } - // unregister previously registered handler if any - element.stopObserving('click'); - element.observe('click', function(event) { - Event.stop(event); - var element = event.element(); - while (element.id == '') { - element = element.up(); - } - XWiki.watchlist.executeAction(element); - }); + if (!element) { + // This is supposed to happen every time since the watchlist icons are implemented in the + // notifications + // menu. The watchlist icons are now implemented as a UI extension, and the inputs are handled + // with a + // custom solution (bootstrap-switch). + // For these reasons, we stop the initialization here. + // We keep this function for old skins (like Colibri), that still have the old-fashioned + // watchlist icons. + return; } + + // unregister previously registered handler if any + element.stopObserving('click'); + element.observe('click', function(event) { + Event.stop(event); + var element = event.element(); + while (element.id == '') { + element = element.up(); + } + XWiki.watchlist.executeAction(element); + }); } } } From 7da4650cc79ef2b1dc3ec8664a9d0ae26d12eb0f Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 11:40:53 +0300 Subject: [PATCH 002/696] XWIKI-22373: User suggest picker doesn't honor the limit for local users * Use the limit specified on the request, defaulting to 10 when no limit is specified. --- .../src/main/resources/templates/uorgsuggest.vm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/uorgsuggest.vm b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/uorgsuggest.vm index eb23703114b8..b981b20d0353 100644 --- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/uorgsuggest.vm +++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/uorgsuggest.vm @@ -43,9 +43,14 @@ #set ($query = $query.bindValue('input').anyChars().literal($input).anyChars().query()) #set ($rawResults = $query.execute()) #set ($results = []) - ## Iterate over the results and select the first 10 results that are accessible to the current user. - #foreach($rawResult in $rawResults) - #if($results.size() >= 10) + #set ($limit = $numbertool.toNumber($request.limit)) + #if ("$!limit" == '') + #set ($limit = 10) + #end + ## Iterate over the results and select the first N results (based on the limit request parameter) that are accessible + ## to the current user. + #foreach ($rawResult in $rawResults) + #if ($results.size() >= $limit) #break #end #if ($services.security.authorization.hasAccess('view', $services.model.resolveDocument($rawResult, $wikiReference))) From 5204f119a84b2c6ffda301d02ceaf7286549539a Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 12:25:54 +0300 Subject: [PATCH 003/696] XWIKI-22374: Incorrect saving of annotations when there are special characters (%, *) in the document name * Fix the way the space names are decoded when the annotation REST resources are called. --- .../internal/AnnotationsRESTResource.java | 18 ++++++++------- .../AnnotationsTranslationRESTResource.java | 22 ++++++++++--------- .../SingleAnnotationRESTResource.java | 21 +++++++++--------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsRESTResource.java b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsRESTResource.java index 5cd4c4501fe5..4eb0205491f3 100644 --- a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsRESTResource.java +++ b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsRESTResource.java @@ -21,6 +21,7 @@ import javax.inject.Named; import javax.inject.Singleton; +import javax.ws.rs.Encoded; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -45,7 +46,7 @@ public class AnnotationsRESTResource extends AbstractAnnotationsRESTResource { /** * @param wiki the wiki of the document to get annotations for - * @param space the space of the document to get annotations for + * @param spaceNames the space names of the document to get annotations for * @param page the name of the document to get annotation for * @return annotations of a given XWiki page. Note that we're returning a response holding the AnnotatedContent * instead of an AnnotatedContent object because we need to be able to set custom expire fields to prevent @@ -53,10 +54,10 @@ public class AnnotationsRESTResource extends AbstractAnnotationsRESTResource * @throws XWikiRestException when failing to parse space */ @GET - public Response doGetAnnotatedContent(@PathParam("spaceName") String space, @PathParam("pageName") String page, - @PathParam("wikiName") String wiki) throws XWikiRestException + public Response doGetAnnotatedContent(@PathParam("spaceName") @Encoded String spaceNames, + @PathParam("pageName") String page, @PathParam("wikiName") String wiki) throws XWikiRestException { - DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(space), page); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page); return getAnnotatedContent(documentReference); } @@ -64,17 +65,18 @@ public Response doGetAnnotatedContent(@PathParam("spaceName") String space, @Pat * Add annotation to a given page. * * @param wiki the wiki of the document to add annotation on - * @param space the space of the document to add annotation on + * @param spaceNames the space names of the document to add annotation on * @param page the name of the document to add annotation on * @param request the request object with the annotation to be added * @return AnnotationRequestResponse, responseCode = 0 if no error * @throws XWikiRestException when failing to parse space */ @POST - public AnnotationResponse doPostAnnotation(@PathParam("wikiName") String wiki, @PathParam("spaceName") String space, - @PathParam("pageName") String page, AnnotationAddRequest request) throws XWikiRestException + public AnnotationResponse doPostAnnotation(@PathParam("wikiName") String wiki, + @PathParam("spaceName") @Encoded String spaceNames, @PathParam("pageName") String page, + AnnotationAddRequest request) throws XWikiRestException { - DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(space), page); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page); return postAnnotation(documentReference, request); } } diff --git a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsTranslationRESTResource.java b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsTranslationRESTResource.java index 9b53f2427294..a4ee36055511 100644 --- a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsTranslationRESTResource.java +++ b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/AnnotationsTranslationRESTResource.java @@ -23,6 +23,7 @@ import javax.inject.Named; import javax.inject.Singleton; +import javax.ws.rs.Encoded; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @@ -49,7 +50,7 @@ public class AnnotationsTranslationRESTResource extends AbstractAnnotationsRESTR { /** * @param wiki the wiki of the document to get annotations for - * @param space the space of the document to get annotations for + * @param spaceNames the space names of the document to get annotations for * @param page the name of the document to get annotation for * @param language the language of the translation of the document to get the annotation for * @return annotations of a given XWiki page. Note that we're returning a response holding the AnnotatedContent @@ -58,11 +59,12 @@ public class AnnotationsTranslationRESTResource extends AbstractAnnotationsRESTR * @throws XWikiRestException when failing to parse space */ @GET - public Response doGetAnnotatedContent(@PathParam("spaceName") String space, @PathParam("pageName") String page, - @PathParam("wikiName") String wiki, @PathParam("language") String language) throws XWikiRestException + public Response doGetAnnotatedContent(@PathParam("spaceName") @Encoded String spaceNames, + @PathParam("pageName") String page, @PathParam("wikiName") String wiki, @PathParam("language") String language) + throws XWikiRestException { - DocumentReference documentReference = - new DocumentReference(wiki, parseSpaceSegments(space), page, LocaleUtils.toLocale(language, Locale.ROOT)); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page, + LocaleUtils.toLocale(language, Locale.ROOT)); return getAnnotatedContent(documentReference); } @@ -70,7 +72,7 @@ public Response doGetAnnotatedContent(@PathParam("spaceName") String space, @Pat * Add annotation to a given page. * * @param wiki the wiki of the document to add annotation on - * @param space the space of the document to add annotation on + * @param spaceNames the space names of the document to add annotation on * @param page the name of the document to add annotation on * @param language he language of the translation of the document to add the annotation on * @param request the request object with the annotation to be added @@ -78,11 +80,11 @@ public Response doGetAnnotatedContent(@PathParam("spaceName") String space, @Pat * @throws XWikiRestException when failing to parse space */ @POST - public AnnotationResponse doPostAnnotation(@PathParam("wikiName") String wiki, @PathParam("spaceName") String space, - @PathParam("pageName") String page, @PathParam("language") String language, AnnotationAddRequest request) - throws XWikiRestException + public AnnotationResponse doPostAnnotation(@PathParam("wikiName") String wiki, + @PathParam("spaceName") @Encoded String spaceNames, @PathParam("pageName") String page, + @PathParam("language") String language, AnnotationAddRequest request) throws XWikiRestException { - DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(space), page); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page); return postAnnotation(documentReference, request); } } diff --git a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/SingleAnnotationRESTResource.java b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/SingleAnnotationRESTResource.java index 4025047abd63..d46eed56864f 100644 --- a/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/SingleAnnotationRESTResource.java +++ b/xwiki-platform-core/xwiki-platform-annotation/xwiki-platform-annotation-rest/src/main/java/org/xwiki/annotation/rest/internal/SingleAnnotationRESTResource.java @@ -26,6 +26,7 @@ import javax.inject.Named; import javax.inject.Singleton; import javax.ws.rs.DELETE; +import javax.ws.rs.Encoded; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -59,7 +60,7 @@ public class SingleAnnotationRESTResource extends AbstractAnnotationRESTResource /** * Deletes the specified annotation. * - * @param space the space of the document to delete the annotation from + * @param spaceNames the space names of the document to delete the annotation from * @param page the name of the document to delete the annotation from * @param wiki the wiki of the document to delete the annotation from * @param id the id of the annotation to delete @@ -69,12 +70,12 @@ public class SingleAnnotationRESTResource extends AbstractAnnotationRESTResource * @throws XWikiRestException when failing to parse space */ @DELETE - public AnnotationResponse doDelete(@PathParam("spaceName") String space, @PathParam("pageName") String page, - @PathParam("wikiName") String wiki, @PathParam("id") String id, AnnotationRequest request) - throws XWikiRestException + public AnnotationResponse doDelete(@PathParam("spaceName") @Encoded String spaceNames, + @PathParam("pageName") String page, @PathParam("wikiName") String wiki, @PathParam("id") String id, + AnnotationRequest request) throws XWikiRestException { try { - DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(space), page); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page); // Initialize the context with the correct value. updateContext(documentReference); @@ -102,7 +103,7 @@ public AnnotationResponse doDelete(@PathParam("spaceName") String space, @PathPa /** * Updates the specified annotation with the values of the fields in received collection. * - * @param space the space of the document to update the annotation from + * @param spaceNames the space names of the document to update the annotation from * @param page the name of the document to update the annotation from * @param wiki the wiki of the document to update the annotation from * @param id the id of the annotation to update @@ -111,12 +112,12 @@ public AnnotationResponse doDelete(@PathParam("spaceName") String space, @PathPa * @throws XWikiRestException when failing to parse space */ @PUT - public AnnotationResponse doUpdate(@PathParam("spaceName") String space, @PathParam("pageName") String page, - @PathParam("wikiName") String wiki, @PathParam("id") String id, AnnotationUpdateRequest updateRequest) - throws XWikiRestException + public AnnotationResponse doUpdate(@PathParam("spaceName") @Encoded String spaceNames, + @PathParam("pageName") String page, @PathParam("wikiName") String wiki, @PathParam("id") String id, + AnnotationUpdateRequest updateRequest) throws XWikiRestException { try { - DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(space), page); + DocumentReference documentReference = new DocumentReference(wiki, parseSpaceSegments(spaceNames), page); // Initialize the context with the correct value. updateContext(documentReference); From 5a361269e2be13df58896c32f0dd661b15fe45f4 Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Thu, 1 Aug 2024 11:31:45 +0200 Subject: [PATCH 004/696] XWIKI-22380: Not getting any specific message when there are errors in the job log --- .../src/main/resources/templates/job_macros.vm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/job_macros.vm b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/job_macros.vm index a05aaf292ab8..0aa586c76f69 100644 --- a/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/job_macros.vm +++ b/xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-templates/src/main/resources/templates/job_macros.vm @@ -117,7 +117,7 @@ $services.template.execute('logging_macros.vm') #elseif ($status.canceled) #set($messageKeys = [$canceledKey, "${translationPrefix}.finish.canceled", "job.status.${status.jobType}.canceled", 'job.status.canceled']) #set($messageClass = 'warningmessage') - #elseif ($jobStatus.logTail.hasLogLevel('error')) + #elseif ($status.logTail.hasLogLevel('error')) #set($messageKeys = [$warningKey, "${translationPrefix}.finish.warning", "job.status.${status.jobType}.warning", 'job.status.warning']) #set($messageClass = 'warningmessage') #else From 9c7c4a629d7dcc1194744273c71ba8174d8294fc Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 12:59:45 +0300 Subject: [PATCH 005/696] [misc] Apply xar:format --- .../src/main/resources/XWiki/Like/LikeTranslations.ko.xml | 2 +- .../src/main/resources/XWiki/Like/UserProfileUIX.xml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ko.xml b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ko.xml index 5cc45bd1fcf6..4d0e9141dfbb 100644 --- a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ko.xml +++ b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/LikeTranslations.ko.xml @@ -64,4 +64,4 @@ XWiki.Like.LikeConfigurationClass_cacheCapacity.hint=캐시에 보관된 좋아 XWiki.Like.LikeConfigurationClass_enabled=좋아요 기능 활성화 XWiki.Like.LikeConfigurationClass_enabled.hint=선택을 취소하면 좋아요 기능이 비활성화되고 좋아요와 관련된 정보가 숨겨집니다. - + diff --git a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml index f8fd7e042341..80fd20046788 100644 --- a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml +++ b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + XWiki.Like UserProfileUIX @@ -77,7 +77,7 @@ |, 5 0 - action=Action|doc.reference=Document|icon.theme=Icon theme|locale=Language|rendering.defaultsyntax=Default syntax|rendering.restricted=Restricted|rendering.targetsyntax=Target syntax|request.base=Request base URL|request.parameters=Request parameters|request.url=Request URL|request.wiki=Request wiki|user=User|wiki=Wiki + action=Action|doc.reference=Document|doc.revision|icon.theme=Icon theme|locale=Language|rendering.defaultsyntax=Default syntax|rendering.restricted=Restricted|rendering.targetsyntax=Target syntax|request.base=Request base URL|request.cookies|request.headers|request.parameters=Request parameters|request.remoteAddr|request.session|request.url=Request URL|request.wiki=Request wiki|sheet|user=User|wiki=Wiki com.xpn.xwiki.objects.classes.StaticListClass @@ -97,6 +97,7 @@ content 1 Executed Content + 0 25 120 0 @@ -127,6 +128,7 @@ parameters 7 Extension Parameters + 0 10 40 0 From af69ff126636960f608e259f47162e0e8c0c4c19 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 13:00:18 +0300 Subject: [PATCH 006/696] XWIKI-22360: The "likers" section in the user profile uses wrong escaping --- .../src/main/resources/XWiki/Like/UserProfileUIX.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml index 80fd20046788..3b5ae201ce20 100644 --- a/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml +++ b/xwiki-platform-core/xwiki-platform-like/xwiki-platform-like-ui/src/main/resources/XWiki/Like/UserProfileUIX.xml @@ -167,7 +167,8 @@ {{velocity}} -==$escapetool.xml($services.localization.render('like.userprofile.menu'))== +(% id="HLikedPages" %) +== {{translation key="like.userprofile.menu" /}} == #set ($docTitleDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.title'))) #set ($docLocationDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.location'))) #set ($likesDisplayName = $escapetool.xml($services.localization.render('like.livetable.column.likes'))) From d1784746bc338f13759a00443f739df9131ddf05 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 14:18:54 +0300 Subject: [PATCH 007/696] [misc] Apply xar:format --- .../src/main/resources/XWiki/ForgotUsernameMailContent.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml index fce2357fbb05..6ba06ef793ac 100644 --- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml +++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + XWiki ForgotUsernameMailContent @@ -58,6 +58,7 @@ html 4 HTML + 0 15 80 0 @@ -88,6 +89,7 @@ text 3 Text + 0 15 80 0 From 6696e9c0606b12056bf66e897203c6f37cceab10 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 14:19:31 +0300 Subject: [PATCH 008/696] XWIKI-22355: Double colon displayed in Forgot username mail content * Simplify the mail content and make the text version consistent with the HTML version * Apply XML escaping in the HTML version --- .../XWiki/ForgotUsernameMailContent.xml | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml index 6ba06ef793ac..059e581828ba 100644 --- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml +++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-ui/src/main/resources/XWiki/ForgotUsernameMailContent.xml @@ -98,28 +98,21 @@ <h2>Hello,</h2> -#set ($wikiurl = $xwiki.getURL($services.model.resolveDocument('', 'default', $doc.documentReference.extractReference('WIKI')))) +#set ($wikiURL = $xwiki.getURL($services.model.resolveDocument('', 'default', $doc.documentReference.extractReference('WIKI')))) #set ($xwikiLoginURL = $xwiki.getURL('XWiki.XWikiLogin', 'login')) -#set ($wikiname = $request.serverName) -#set ($severalUsernames = ($usernames.size() > 0)) -<p>A forgot username request has been performed on <a href="$wikiurl">$wikiname</a>. +#set ($wikiName = $request.serverName) +<p>A forgot username request has been made on <a href="$escapetool.xml($wikiURL)">$escapetool.xml($wikiName)</a>. If you did not make the request, please ignore this message.</p> -<p>We found the following username#if($severalUsernames)s#end related to this email address: -:<br/> -#if ($severalUsernames) +<p>We found the following usernames related to this email address:</p> <ul> #foreach ($username in $usernames) - <li>$username</li> + <li>$escapetool.xml($username)</li> #end </ul> -#else -<strong>$usernames.get(0)</strong> -#end <p> -You can login from this page: <a href="$xwikiLoginURL">XWiki Login</a>. -</p> - +You can login from this page: <a href="$escapetool.xml($xwikiLoginURL)">XWiki Login</a>. +</p> en @@ -130,14 +123,15 @@ You can login from this page: <a href="$xwikiLoginURL">XWiki Login</a&g Hello, -A forgot username request has been made on ${request.getServerName()}. -We found the following username(s) related to this email address: +A forgot username request has been made on ${request.getServerName()}. If you did not make the request, please ignore this message. + +We found the following usernames related to this email address: #foreach ($username in $usernames) $usernames #end -You can login with this username from this URL: $xwiki.getURL('XWiki.XWikiLogin', 'login'). +You can login from this URL: $xwiki.getURL('XWiki.XWikiLogin', 'login'). From 1efb8c5c4a2f8b05eadd12b568c7b614386a9d06 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 14:45:34 +0300 Subject: [PATCH 009/696] [misc] Apply xar:format --- .../src/main/resources/XWiki/DocumentTreeTranslations.ko.xml | 2 +- .../src/main/resources/XWiki/DocumentTreeTranslations.uk.xml | 2 +- .../src/main/resources/XWiki/DocumentTreeTranslations.xml | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.ko.xml b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.ko.xml index efb48e3d46ee..7e2e4dece443 100644 --- a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.ko.xml +++ b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.ko.xml @@ -91,4 +91,4 @@ index.documentTree.more={0}개 더 ... rendering.macro.documentTree.parameter.showChildDocuments.name=하위 문서 표시 rendering.macro.documentTree.parameter.showChildDocuments.description=문서 상위 필드를 기반으로 하위 문서를 표시할지 여부입니다. - + diff --git a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.uk.xml b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.uk.xml index 54fa7d7415d3..18727840877a 100644 --- a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.uk.xml +++ b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.uk.xml @@ -91,4 +91,4 @@ index.documentTree.more=ще {0}... rendering.macro.documentTree.parameter.showChildDocuments.name=Показати дочірні документи rendering.macro.documentTree.parameter.showChildDocuments.description=Чи показувати дочірні документи на основі батьківського поля документа. - + diff --git a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml index 2f13cf3c3170..1b6786bf6395 100644 --- a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml +++ b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + XWiki DocumentTreeTranslations @@ -109,6 +109,8 @@ rendering.macro.documentTree.parameter.showChildDocuments.description=Whether to 0 0 select + forbidden + 0 0 scope 1 From 603d4fce79f06adc8b4514e731eaa7f2bc2ae764 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 14:45:59 +0300 Subject: [PATCH 010/696] XWIKI-22346: The children macro isn't translated --- .../src/main/resources/XWiki/DocumentTreeTranslations.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml index 1b6786bf6395..0e7bee2fa164 100644 --- a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml +++ b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.xml @@ -83,6 +83,9 @@ rendering.macro.documentTree.parameter.limit.description=The maximum number of c rendering.macro.documentTree.parameter.exclusions.name=Exclusions rendering.macro.documentTree.parameter.exclusions.description=The list of nodes to exclude from the tree. The nodes are specified by their id and separated by comma. +rendering.macro.children.name=Children +rendering.macro.children.description=Displays a tree of children pages of the current page + index.documentTree.empty=No pages found index.documentTree.more={0} more ... From 3c93eec5ac8154253545f229986f407d83007cac Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Thu, 1 Aug 2024 16:20:12 +0300 Subject: [PATCH 011/696] XWIKI-22326: "newline" special character in page name breaks the navigation tree --- .../src/main/webjar/tree.js | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-tree/xwiki-platform-tree-webjar/src/main/webjar/tree.js b/xwiki-platform-core/xwiki-platform-tree/xwiki-platform-tree-webjar/src/main/webjar/tree.js index 56026e50128c..d56dfadfbdc6 100644 --- a/xwiki-platform-core/xwiki-platform-tree/xwiki-platform-tree-webjar/src/main/webjar/tree.js +++ b/xwiki-platform-core/xwiki-platform-tree/xwiki-platform-tree-webjar/src/main/webjar/tree.js @@ -29,11 +29,24 @@ define([ // jsTree uses the underscore notation for its API, instead of camel case. // jshint camelcase:false,maxstatements:false - // Fix the regular expression used by jsTree to escape special characters in CSS selectors. It is mainly used to be - // able to find a tree node by its id using Element#querySelector. We overwrite the default value used by jsTree in - // order to add the following special characters: - // * \s (any white space character, such as non breaking space, not just the plain space) - $.jstree.idregex = /[\\:&!^|()\[\]<>@*'+~#";.,=\-\s\/${}%?`]/g; + // jsTree node identifiers are used without any escaping in HTML id attributes. When finding the DOM node associated + // with a jsTree node, the jsTree node identifier needs to be escaped in order to avoid breaking the CSS selector + // used. Instead of using CSS.escape(), jsTree performs its own custom CSS escaping, based on a regular expression. + // This regular expression doesn't include all the special characters (e.g. doesn't escape all white space characters, + // such as non-breaking space) and doesn't handle well new line and line feed characters which need special treatment. + // For this reason we overwrite the String.replace() function to perform CSS escaping when the passed arguments are + // the jsTree ID regular expression and the escape string. + // FIXME: Drop this hack when jsTree replaces its custom CSS escaping code with CSS.escape(). + if ($.jstree.idregex) { + const originalStringReplace = String.prototype.replace; + String.prototype.replace = function(...args) { + if (args[1] === '\\$&' && args[0] === $?.jstree?.idregex) { + return CSS.escape(this); + } else { + return originalStringReplace.apply(this, args); + } + }; + } var formToken = $('meta[name=form_token]').attr('content'); From f30140fb440e896713142ea8647d47cfdb4dbfa5 Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Thu, 1 Aug 2024 17:01:34 +0200 Subject: [PATCH 012/696] XWIKI-11624: When a user page is restored from trashbin it's not put back in XWikiAllGroup --- .../ui/UsersGroupsRightsManagementIT.java | 9 +++ .../src/main/java/com/xpn/xwiki/XWiki.java | 45 ++++++++--- .../UserInstanceOutputFilterStream.java | 7 -- .../user/UserCreatedEventListener.java | 78 +++++++++++++++++++ .../main/resources/META-INF/components.txt | 1 + 5 files changed, 124 insertions(+), 16 deletions(-) create mode 100644 xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/user/UserCreatedEventListener.java diff --git a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/UsersGroupsRightsManagementIT.java b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/UsersGroupsRightsManagementIT.java index d89655f0d309..e75c5973da1f 100644 --- a/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/UsersGroupsRightsManagementIT.java +++ b/xwiki-platform-core/xwiki-platform-administration/xwiki-platform-administration-test/xwiki-platform-administration-test-docker/src/test/it/org/xwiki/administration/test/ui/UsersGroupsRightsManagementIT.java @@ -35,6 +35,7 @@ import org.xwiki.test.docker.junit5.UITest; import org.xwiki.test.ui.TestUtils; import org.xwiki.test.ui.po.ConfirmationModal; +import org.xwiki.test.ui.po.DeletePageOutcomePage; import org.xwiki.test.ui.po.EditRightsPane; import org.xwiki.test.ui.po.ViewPage; import org.xwiki.test.ui.po.editor.RightsEditPage; @@ -251,6 +252,7 @@ void createGroupWhenGroupAlreadyExists(TestUtils setup, TestReference testRefere *
  • Validate user disable/enable
  • *
  • Validate user deletion.
  • *
  • Validate groups automatically cleaned from deleted users.
  • + *
  • Validate default groups are updated when a deleted user is restored.
  • * */ @Test @@ -303,6 +305,13 @@ void createAndDeleteUser(TestUtils setup, TestReference testReference) // Verify that when a user is removed, they are removed from the groups they belong to. groupsPage = GroupsPage.gotoPage(); assertEquals(0, groupsPage.clickEditGroup("XWikiAllGroup").filterMembers(userName).countRows()); + + // Verify that when a user is restored, it's put back in the default group + setup.gotoPage("XWiki", userName); + DeletePageOutcomePage deletePageOutcomePage = new DeletePageOutcomePage(); + deletePageOutcomePage.getDeletedTerminalPagesEntries().get(0).clickRestore(); + groupsPage = GroupsPage.gotoPage(); + assertEquals(1, groupsPage.clickEditGroup("XWikiAllGroup").filterMembers(userName).countRows()); } /** diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java index 71f85d95ffff..c288c57fe6ff 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java @@ -4237,9 +4237,6 @@ public int createUser(String userName, Map map, EntityReference paren saveDocument(doc, localizePlainOrKey("core.comment.createdUser"), context); - // Now let's add the user to XWiki.XWikiAllGroup - setUserDefaultGroup(doc.getFullName(), context); - return 1; } catch (Exception e) { Object[] args = { "XWiki." + userName }; @@ -4259,7 +4256,26 @@ public int createUser(String xwikiname, Map map, String parent, Strin return createUser(xwikiname, map, parent, content, Syntax.XWIKI_1_0.toIdString(), userRights, context); } - public void setUserDefaultGroup(String fullwikiname, XWikiContext context) throws XWikiException + /** + * @param documentReference the reference of the user document + * @param xcontext the XWiki context + * @since 16.7.0RC1 + */ + @Unstable + public void setUserDefaultGroup(DocumentReference documentReference, XWikiContext xcontext) + { + WikiReference currentWikiReference = xcontext.getWikiReference(); + + try { + xcontext.setWikiReference(documentReference.getWikiReference()); + + setUserDefaultGroup(getLocalStringEntityReferenceSerializer().serialize(documentReference), xcontext); + } finally { + xcontext.setWikiReference(currentWikiReference); + } + } + + public void setUserDefaultGroup(String fullwikiname, XWikiContext context) { String groupsPreference = isAllGroupImplicit() ? getConfiguration().getProperty("xwiki.users.initialGroups") : getConfiguration().getProperty("xwiki.users.initialGroups", "XWiki.XWikiAllGroup"); @@ -4268,7 +4284,13 @@ public void setUserDefaultGroup(String fullwikiname, XWikiContext context) throw String[] groups = groupsPreference.split(","); for (String groupName : groups) { if (StringUtils.isNotBlank(groupName)) { - addUserToGroup(fullwikiname, groupName.trim(), context); + String cleanedGroupName = groupName.trim(); + + try { + addUserToGroup(fullwikiname, cleanedGroupName, context); + } catch (Exception e) { + LOGGER.error("Failed to update group [{}] with member [{}]", cleanedGroupName, fullwikiname, e); + } } } } @@ -4279,12 +4301,17 @@ protected void addUserToGroup(String userName, String groupName, XWikiContext co XWikiDocument groupDoc = getDocument(groupName, context); DocumentReference groupClassReference = getGroupClass(context).getDocumentReference(); - BaseObject memberObject = - groupDoc.newXObject(groupClassReference.removeParent(groupClassReference.getWikiReference()), context); - memberObject.setStringValue("member", userName); + // Make sure the user is not already part of the group + if (groupDoc.getXObject(groupClassReference, "member", userName, + false) == null) { + BaseObject memberObject = + groupDoc.newXObject(groupClassReference.removeParent(groupClassReference.getWikiReference()), context); - this.saveDocument(groupDoc, localizePlainOrKey("core.comment.addedUserToGroup"), context); + memberObject.setStringValue("member", userName); + + saveDocument(groupDoc, localizePlainOrKey("core.comment.addedUserToGroup"), context); + } } public void protectUserPage(String userName, String userRights, XWikiDocument doc, XWikiContext context) diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/filter/output/UserInstanceOutputFilterStream.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/filter/output/UserInstanceOutputFilterStream.java index 7fae3e9da747..936ea6d20d6f 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/filter/output/UserInstanceOutputFilterStream.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/filter/output/UserInstanceOutputFilterStream.java @@ -270,13 +270,6 @@ public void beginUser(String name, FilterEventParameters parameters) throws Filt } catch (XWikiException e) { throw new FilterException("Failed to save user document", e); } - - // Add the user to default groups - try { - xcontext.getWiki().setUserDefaultGroup(userDocument.getFullName(), xcontext); - } catch (XWikiException e) { - throw new FilterException("Failed to add user to default groups", e); - } } @Override diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/user/UserCreatedEventListener.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/user/UserCreatedEventListener.java new file mode 100644 index 000000000000..3ccda21c105e --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/user/UserCreatedEventListener.java @@ -0,0 +1,78 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xpn.xwiki.internal.user; + +import javax.annotation.Priority; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; +import org.xwiki.observation.AbstractEventListener; +import org.xwiki.observation.event.Event; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.internal.event.XObjectAddedEvent; +import com.xpn.xwiki.internal.mandatory.XWikiUsersDocumentInitializer; +import com.xpn.xwiki.objects.BaseObjectReference; + +/** + * Automatically add new users to the configured groups. + * + * @version $Id$ + * @since 16.7.0RC1 + */ +@Component +@Singleton +@Named(UserCreatedEventListener.NAME) +// We want to execute it as early as possible so that other listeners end up with a user which have all its expected +// rights +@Priority(500) +public class UserCreatedEventListener extends AbstractEventListener +{ + /** + * Name of the listener. + */ + public static final String NAME = "com.xpn.xwiki.internal.user.UserCreatedEventListener"; + + @Inject + private Provider xcontextProvider; + + /** + * Default constructor. + */ + public UserCreatedEventListener() + { + super(NAME, + new XObjectAddedEvent(BaseObjectReference.any(XWikiUsersDocumentInitializer.CLASS_REFERENCE_STRING))); + } + + @Override + public void onEvent(Event event, Object source, Object data) + { + XWikiContext xcontext = this.xcontextProvider.get(); + XWiki xwiki = xcontext.getWiki(); + + xwiki.setUserDefaultGroup(((XWikiDocument) source).getDocumentReference(), xcontext); + } +} diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/META-INF/components.txt b/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/META-INF/components.txt index 4514dff5c267..656ff8ff6927 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/META-INF/components.txt +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/resources/META-INF/components.txt @@ -160,6 +160,7 @@ com.xpn.xwiki.internal.render.OldRenderingProvider com.xpn.xwiki.internal.render.groovy.ParseGroovyFromString com.xpn.xwiki.internal.user.MyPersistentLoginManagerProvider com.xpn.xwiki.internal.user.UserAuthenticatedEventNotifier +com.xpn.xwiki.internal.user.UserCreatedEventListener com.xpn.xwiki.internal.velocity.DefaultVelocityEvaluator org.xwiki.internal.web.EffectiveAuthorSetterListener org.xwiki.internal.web.GetDocExistValidator From 76ca536d2000cedae43431ff1af183e8f398efe9 Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Mon, 5 Aug 2024 08:16:52 +0200 Subject: [PATCH 013/696] XWIKI-22388: Upgrade to RequireJS 2.3.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 53bcd987d14b..c78e6557a2de 100644 --- a/pom.xml +++ b/pom.xml @@ -444,7 +444,7 @@ org.webjars requirejs - 2.3.6 + 2.3.7 runtime From c70584417823465f698b5614ae6126b8cde7e295 Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Mon, 5 Aug 2024 08:22:20 +0200 Subject: [PATCH 014/696] XWIKI-22389: Upgrade Ukrainian Morfologik dictionaries to 6.4.5 --- .../xwiki-platform-search-solr-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/pom.xml b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/pom.xml index c51ec45a074c..4ed7fe3aefc6 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/pom.xml +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-api/pom.xml @@ -60,7 +60,7 @@ ua.net.nlp morfologik-ukrainian-lt - 6.4.4 + 6.4.5 org.apache.lucene From c236ce5822b996876868714450a4e25c8c449960 Mon Sep 17 00:00:00 2001 From: Simpel Date: Sat, 3 Aug 2024 07:39:53 +0000 Subject: [PATCH 015/696] Translated using Weblate (German) Currently translated at 100.0% (52 of 52 strings) Translation: XWiki Platform/xwiki-platform-index-tree-macro DocumentTreeTranslations Translate-URL: https://l10n.xwiki.org/projects/xwiki-platform/xwiki-platform-index/xwiki-documenttreetranslations/de/ --- .../main/resources/XWiki/DocumentTreeTranslations.de.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.de.xml b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.de.xml index 099128e988c6..1d271e4815dc 100644 --- a/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.de.xml +++ b/xwiki-platform-core/xwiki-platform-index/xwiki-platform-index-tree/xwiki-platform-index-tree-macro/src/main/resources/XWiki/DocumentTreeTranslations.de.xml @@ -82,7 +82,8 @@ rendering.macro.documentTree.parameter.limit.name=Limit rendering.macro.documentTree.parameter.limit.description=Die maximale Anzahl der Kindknoten, die beim ersten Aufklappen eines übergeordneten Knotens angezeigt werden sollen. Der Rest der Kindknoten ist über einen "mehr ..."-Link zugänglich. Dieser Parameter dient im Wesentlichen dazu, die Kindknoten zu paginieren und hilft so bei der Skalierung des Baums, wenn die Anzahl der Kindknoten groß ist. rendering.macro.documentTree.parameter.exclusions.name=Ausschlüsse rendering.macro.documentTree.parameter.exclusions.description=Die Liste der Knoten, die aus dem Baum ausgeschlossen werden sollen. Die Knoten werden durch ihre ID angegeben und durch Komma getrennt. - +rendering.macro.children.name=Unterseiten +rendering.macro.children.description=Zeigt einen Baum von Unterseiten der aktuellen Seite an index.documentTree.empty=Keine Seiten gefunden index.documentTree.more={0} mehr ... @@ -90,5 +91,6 @@ index.documentTree.more={0} mehr ... ## Until 7.2M2 rendering.macro.documentTree.parameter.showChildDocuments.name=Kinddokumente anzeigen -rendering.macro.documentTree.parameter.showChildDocuments.description=Ob die untergeordneten Dokumente basierend auf dem übergeordneten Feld des Dokuments angezeigt werden sollen. +rendering.macro.documentTree.parameter.showChildDocuments.description=Ob die untergeordneten Dokumente basierend auf dem übergeordneten Feld des Dokuments angezeigt werden sollen. +
    From 8f1817a0dde969a9eb6361d8da312c9a8aabc913 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 5 Aug 2024 14:19:45 +0000 Subject: [PATCH 016/696] Update dependency org.xwiki.contrib.numbered.content:application-numbered-content-headings-ui to v1.10.2 --- .../xwiki-platform-export-pdf-test-content/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/pom.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/pom.xml index 0813700ae25b..1d9646891faf 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/pom.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/pom.xml @@ -66,7 +66,7 @@ org.xwiki.contrib.numbered.content application-numbered-content-headings-ui - 1.10.1 + 1.10.2 xar From 37ec9de7ec3537714d8ba40fbfbd24d036d24dcb Mon Sep 17 00:00:00 2001 From: Thomas Mortagne Date: Tue, 6 Aug 2024 10:52:53 +0200 Subject: [PATCH 017/696] XWIKI-22394: When accessing directly Tomcat, the resolved source URL can contain an extra port --- .../container/servlet/HttpServletUtils.java | 23 ++++++++++++++++++- .../servlet/HttpServletUtilsTest.java | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/main/java/org/xwiki/container/servlet/HttpServletUtils.java b/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/main/java/org/xwiki/container/servlet/HttpServletUtils.java index 1859fdf703e6..5b95727cc72e 100644 --- a/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/main/java/org/xwiki/container/servlet/HttpServletUtils.java +++ b/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/main/java/org/xwiki/container/servlet/HttpServletUtils.java @@ -28,6 +28,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.http.HeaderElement; import org.apache.http.message.BasicHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xwiki.container.servlet.internal.ForwardedHeader; /** @@ -64,6 +66,8 @@ public final class HttpServletUtils private static final String HTTPS = "https"; + private static final Logger LOGGER = LoggerFactory.getLogger(HttpServletUtils.class); + private HttpServletUtils() { // Utility class @@ -187,7 +191,24 @@ private static void appendHostPort(HttpServletRequest request, StringBuilder bui return; } - // Received host:port + // Ask the application server (we don't start with that because it's very often wrong or badly configured + // behind an HTTP proxy...) + String requestURLString = request.getRequestURL().toString(); + try { + URL requestURL = new URL(requestURLString); + builder.append(requestURL.getHost()); + int port = requestURL.getPort(); + if (port != -1) { + builder.append(':'); + builder.append(port); + } + return; + } catch (MalformedURLException e) { + LOGGER.error("The request URL indicated by the application server is wrong: {}", requestURLString, e); + } + + // Ask the application server another way (in which we cannot be sure if the port is explicitly indicated or + // not) builder.append(request.getServerName()); int port = request.getServerPort(); if (port != -1) { diff --git a/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/test/java/org/xwiki/container/servlet/HttpServletUtilsTest.java b/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/test/java/org/xwiki/container/servlet/HttpServletUtilsTest.java index 22c75b6d7efb..0dc2f5994b36 100644 --- a/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/test/java/org/xwiki/container/servlet/HttpServletUtilsTest.java +++ b/xwiki-platform-core/xwiki-platform-container/xwiki-platform-container-servlet/src/test/java/org/xwiki/container/servlet/HttpServletUtilsTest.java @@ -49,6 +49,7 @@ private HttpServletRequest request(String urlString, Map... head when(request.getScheme()).thenReturn(url.getProtocol()); when(request.getServerName()).thenReturn(url.getHost()); when(request.getServerPort()).thenReturn(url.getPort()); + when(request.getRequestURL()).thenReturn(new StringBuffer(urlString)); for (Map headers : headerGroup) { for (Map.Entry entry : headers.entrySet()) { From 04225d5b7c25eac014c5e24e58b40753a6199c22 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Tue, 6 Aug 2024 11:51:50 +0300 Subject: [PATCH 018/696] XWIKI-22385: The WYSIWYG editor remains read-only after it reconnects to the realtime session * Pair the existing setEditable(false) with an setEditable(true) * Upgrade Netflux WebSocket WebJar to fix a bug related to how sessions with large lag are disconnected --- .../xwiki-platform-realtime-webjar/pom.xml | 2 +- .../src/main/webjar/wysiwygEditor.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/pom.xml b/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/pom.xml index e856a6623929..b9352db25a1a 100644 --- a/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/pom.xml +++ b/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-webjar/pom.xml @@ -55,7 +55,7 @@ org.xwiki.contrib chainpad-netflux-webjar - 1.1.0 + 1.2.0 runtime diff --git a/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-webjar/src/main/webjar/wysiwygEditor.js b/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-webjar/src/main/webjar/wysiwygEditor.js index 47e22f5ff418..dab4af4b180d 100644 --- a/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-webjar/src/main/webjar/wysiwygEditor.js +++ b/xwiki-platform-core/xwiki-platform-realtime/xwiki-platform-realtime-wysiwyg/xwiki-platform-realtime-wysiwyg-webjar/src/main/webjar/wysiwygEditor.js @@ -524,11 +524,17 @@ define('xwiki-realtime-wysiwyg', [ } else { // The Netflux channel used before the WebSocket connection closed is not available anymore so we have to // abort the current realtime session. - this.setEditable(false); this._onAbort(); if (!this._saver.getLocalEditFlag()) { // Fortunately we don't have any unsaved local changes so we can rejoin the realtime session using the new // Netflux channel. + // + // The editor was previously put in read-only mode when we got disconnected from the WebSocket (i.e. when + // the WebSocket connection status changed, see above). The editor takes into account nested calls to + // setReadOnly so we need to make sure the previous setEditable(false) has a corresponding call to + // setEditable(true). The user won't be able to edit right away because the editor is put back in read-only + // mode while we reconnect to the realtime session (in _startRealtimeSync). + this.setEditable(true); this._startRealtimeSync(); } else { // We can't rejoin the realtime session using the new Netflux channel because we would lose the unsaved From ac352781f21d076e505d51d62456764833290ef7 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Tue, 6 Aug 2024 12:53:05 +0300 Subject: [PATCH 019/696] XWIKI-22267: Velocity content not processed in inline javascript of access rights of terminal pages * Bulletproofing --- .../src/main/resources/flamingo/edit.vm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/edit.vm b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/edit.vm index 57f562bed2f9..7a0240b80919 100644 --- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/edit.vm +++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/edit.vm @@ -173,7 +173,8 @@ ## This javascript must be placed here since it uses velocity variables set in the template above. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + diff --git a/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/.jshintrc b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/.jshintrc new file mode 100644 index 000000000000..22e878512ba1 --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/.jshintrc @@ -0,0 +1,6 @@ +{ + "extends" : "../../.jshintrc", + "devel" : true, + "es3" : false, + "qunit" : true +} diff --git a/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/affix.js b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/affix.js new file mode 100644 index 000000000000..98dfb52c6358 --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/affix.js @@ -0,0 +1,123 @@ +$(function () { + 'use strict'; + + QUnit.module('affix plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).affix, 'affix method is defined') + }) + + QUnit.module('affix', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapAffix = $.fn.affix.noConflict() + }, + afterEach: function () { + $.fn.affix = $.fn.bootstrapAffix + delete $.fn.bootstrapAffix + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.affix, undefined, 'affix was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('
    ').appendTo('#qunit-fixture') + var $affix = $el.bootstrapAffix() + assert.ok($affix instanceof $, 'returns jquery collection') + assert.strictEqual($affix[0], $el[0], 'collection contains element') + }) + + QUnit.test('should exit early if element is not visible', function (assert) { + assert.expect(1) + var $affix = $('
    ') + .appendTo('#qunit-fixture') + .bootstrapAffix() + + $affix.data('bs.affix').checkPosition() + assert.ok(!$affix.hasClass('affix'), 'affix class was not added') + }) + + QUnit.test('should trigger affixed event after affix', function (assert) { + // Disable for iOS because of: https://bugs.webkit.org/show_bug.cgi?id=172854 + if (window.navigator.userAgent.match(/iPhone/i)) { + assert.expect(0) + return + } + + assert.expect(2) + var done = assert.async() + + var templateHTML = '
    ' + + '
      ' + + '
    • Please affix
    • ' + + '
    • And unaffix
    • ' + + '
    ' + + '
    ' + + '
    ' + $(templateHTML).appendTo(document.body) + + $('#affixTarget').bootstrapAffix({ + offset: $('#affixTarget ul').position() + }) + + $('#affixTarget') + .on('affix.bs.affix', function () { + assert.ok(true, 'affix event fired') + }).on('affixed.bs.affix', function () { + assert.ok(true, 'affixed event fired') + $('#affixTarget, #affixAfter').remove() + done() + }) + + setTimeout(function () { + window.scrollTo(0, document.body.scrollHeight - 5) + + // for testing in a browser + setTimeout(function () { + window.scroll(0, 0) + }, 150) + }, 0) + }) + + QUnit.test('should affix-top when scrolling up to offset when parent has padding', function (assert) { + // Disable for iOS because of: https://bugs.webkit.org/show_bug.cgi?id=172854 + if (window.navigator.userAgent.match(/iPhone/i)) { + assert.expect(0) + return + } + + assert.expect(1) + var done = assert.async() + + var templateHTML = '
    ' + + '
    ' + + '

    Testing affix-top class is added

    ' + + '
    ' + + '
    ' + + '
    ' + $(templateHTML).appendTo(document.body) + + $('#affixTopTarget') + .bootstrapAffix({ + offset: { top: 120, bottom: 0 } + }) + .on('affixed-top.bs.affix', function () { + assert.ok($('#affixTopTarget').hasClass('affix-top'), 'affix-top class applied') + $('#padding-offset').remove() + done() + }) + + setTimeout(function () { + window.scrollTo(0, document.body.scrollHeight - 5) + + setTimeout(function () { + window.scroll(0, 119) + }, 250) + }, 0) + }) +}) diff --git a/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/alert.js b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/alert.js new file mode 100644 index 000000000000..ef9bdf22ef1b --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/alert.js @@ -0,0 +1,83 @@ +$(function () { + 'use strict'; + + QUnit.module('alert plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).alert, 'alert method is defined') + }) + + QUnit.module('alert', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapAlert = $.fn.alert.noConflict() + }, + afterEach: function () { + $.fn.alert = $.fn.bootstrapAlert + delete $.fn.bootstrapAlert + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.alert, undefined, 'alert was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('
    ') + var $alert = $el.bootstrapAlert() + assert.ok($alert instanceof $, 'returns jquery collection') + assert.strictEqual($alert[0], $el[0], 'collection contains element') + }) + + QUnit.test('should fade element out on clicking .close', function (assert) { + assert.expect(1) + var alertHTML = '
    ' + + '×' + + '

    Holy guacamole! Best check yo self, you\'re not looking too good.

    ' + + '
    ' + var $alert = $(alertHTML).bootstrapAlert() + + $alert.find('.close').trigger('click') + + assert.strictEqual($alert.hasClass('in'), false, 'remove .in class on .close click') + }) + + QUnit.test('should remove element when clicking .close', function (assert) { + assert.expect(2) + var done = assert.async() + + var alertHTML = '
    ' + + '×' + + '

    Holy guacamole! Best check yo self, you\'re not looking too good.

    ' + + '
    ' + var $alert = $(alertHTML).appendTo('#qunit-fixture').bootstrapAlert() + + assert.notEqual($('#qunit-fixture').find('.alert').length, 0, 'element added to dom') + + $alert.on('closed.bs.alert', function () { + assert.strictEqual($('#qunit-fixture').find('.alert').length, 0, 'element removed from dom') + done() + }) + + $alert.find('.close').trigger('click') + }) + + QUnit.test('should not fire closed when close is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + $('
    ') + .on('close.bs.alert', function (e) { + e.preventDefault() + assert.ok(true, 'close event fired') + done() + }) + .on('closed.bs.alert', function () { + assert.ok(false, 'closed event fired') + }) + .bootstrapAlert('close') + }) + +}) diff --git a/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/button.js b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/button.js new file mode 100644 index 000000000000..691796c42885 --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/button.js @@ -0,0 +1,168 @@ +$(function () { + 'use strict'; + + QUnit.module('button plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).button, 'button method is defined') + }) + + QUnit.module('button', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapButton = $.fn.button.noConflict() + }, + afterEach: function () { + $.fn.button = $.fn.bootstrapButton + delete $.fn.bootstrapButton + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.button, undefined, 'button was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('
    ') + var $button = $el.bootstrapButton() + assert.ok($button instanceof $, 'returns jquery collection') + assert.strictEqual($button[0], $el[0], 'collection contains element') + }) + + QUnit.test('should return set state to loading', function (assert) { + assert.expect(4) + var $btn = $('') + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + $btn.bootstrapButton('loading') + var done = assert.async() + setTimeout(function () { + assert.strictEqual($btn.html(), 'fat', 'btn text equals fat') + assert.ok($btn[0].hasAttribute('disabled'), 'btn is disabled') + assert.ok($btn.hasClass('disabled'), 'btn has disabled class') + done() + }, 0) + }) + + QUnit.test('should return reset state', function (assert) { + assert.expect(7) + var $btn = $('') + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + $btn.bootstrapButton('loading') + var doneOne = assert.async() + setTimeout(function () { + assert.strictEqual($btn.html(), 'fat', 'btn text equals fat') + assert.ok($btn[0].hasAttribute('disabled'), 'btn is disabled') + assert.ok($btn.hasClass('disabled'), 'btn has disabled class') + doneOne() + var doneTwo = assert.async() + $btn.bootstrapButton('reset') + setTimeout(function () { + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + assert.ok(!$btn[0].hasAttribute('disabled'), 'btn is not disabled') + assert.ok(!$btn.hasClass('disabled'), 'btn does not have disabled class') + doneTwo() + }, 0) + }, 0) + }) + + QUnit.test('should work with an empty string as reset state', function (assert) { + assert.expect(7) + var $btn = $('') + assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + $btn.bootstrapButton('toggle') + assert.ok($btn.hasClass('active'), 'btn has class active') + }) + + QUnit.test('should toggle active when btn children are clicked', function (assert) { + assert.expect(2) + var $btn = $('') + var $inner = $('') + $btn + .append($inner) + .appendTo('#qunit-fixture') + assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + $inner.trigger('click') + assert.ok($btn.hasClass('active'), 'btn has class active') + }) + + QUnit.test('should toggle aria-pressed', function (assert) { + assert.expect(2) + var $btn = $('') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $btn.bootstrapButton('toggle') + assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + + QUnit.test('should toggle aria-pressed when btn children are clicked', function (assert) { + assert.expect(2) + var $btn = $('') + var $inner = $('') + $btn + .append($inner) + .appendTo('#qunit-fixture') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $inner.trigger('click') + assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + + QUnit.test('should check for closest matching toggle', function (assert) { + assert.expect(12) + var groupHTML = '
    ' + + '' + + '' + + '' + + '
    ' + var $group = $(groupHTML).appendTo('#qunit-fixture') + + var $btn1 = $group.children().eq(0) + var $btn2 = $group.children().eq(1) + + assert.ok($btn1.hasClass('active'), 'btn1 has active class') + assert.ok($btn1.find('input').prop('checked'), 'btn1 is checked') + assert.ok(!$btn2.hasClass('active'), 'btn2 does not have active class') + assert.ok(!$btn2.find('input').prop('checked'), 'btn2 is not checked') + $btn2.find('input').trigger('click') + assert.ok(!$btn1.hasClass('active'), 'btn1 does not have active class') + assert.ok(!$btn1.find('input').prop('checked'), 'btn1 is not checked') + assert.ok($btn2.hasClass('active'), 'btn2 has active class') + assert.ok($btn2.find('input').prop('checked'), 'btn2 is checked') + + $btn2.find('input').trigger('click') // clicking an already checked radio should not un-check it + assert.ok(!$btn1.hasClass('active'), 'btn1 does not have active class') + assert.ok(!$btn1.find('input').prop('checked'), 'btn1 is not checked') + assert.ok($btn2.hasClass('active'), 'btn2 has active class') + assert.ok($btn2.find('input').prop('checked'), 'btn2 is checked') + }) + +}) diff --git a/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/carousel.js b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/carousel.js new file mode 100644 index 000000000000..39d2505980cb --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-bootstrap/src/tests/unit/carousel.js @@ -0,0 +1,718 @@ +$(function () { + 'use strict'; + + QUnit.module('carousel plugin') + + QUnit.test('should be defined on jQuery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).carousel, 'carousel method is defined') + }) + + QUnit.module('carousel', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapCarousel = $.fn.carousel.noConflict() + }, + afterEach: function () { + $.fn.carousel = $.fn.bootstrapCarousel + delete $.fn.bootstrapCarousel + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.carousel, undefined, 'carousel was set back to undefined (orig value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('
    ') + var $carousel = $el.bootstrapCarousel() + assert.ok($carousel instanceof $, 'returns jquery collection') + assert.strictEqual($carousel[0], $el[0], 'collection contains element') + }) + + QUnit.test('should not fire slid when slide is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + $('