Changes for page Attachments

Last modified by Ludovic Dubost on 2024/07/22 15:50

From version 9.1
edited by Ludovic Dubost
on 2019/08/02 10:59
Change comment: Migrated property [contentJavaType] from class [XWiki.WikiMacroClass]
To version 17.1
edited by Ludovic Dubost
on 2024/07/22 15:50
Change comment: Install extension [org.xwiki.platform:xwiki-platform-attachment-ui/16.5.0]

Summary

Details

Page properties
Content
... ... @@ -1,17 +1,21 @@
1 1  {{velocity output="false"}}
2 +#set ($translationPrefix = 'xe.attachmentSelector')
3 +
2 2  #if ($request.xaction == 'postUpload')
3 3   #set ($targetDocument = $xwiki.getDocument($request.get('docname')))
4 4   #set ($targetAttachDocument = $xwiki.getDocument($request.get('targetdocname')))
5 5  
6 6   #set ($fieldname = $request.get('fieldname'))
9 + #set ($comment = $services.localization.render("${translationPrefix}.postUpload.comment", [$fieldname]))
7 7   #set ($docAction = $request.get('docAction'))
8 8   #set ($attachmentList = $targetAttachDocument.getAttachmentList())
9 9   #if ($attachmentList && $attachmentList.size() > 0)
10 - #set ($sortedAttachments = $sorttool.sort($attachmentList, 'date:desc'))
13 + #set ($sortedAttachments = $collectiontool.sort($attachmentList, 'date:desc'))
11 11   #set ($lastAttachment = $sortedAttachments.get(0))
12 12   #end
13 13   $response.sendRedirect($targetDocument.getURL($docAction, $escapetool.url({
14 14   $fieldname: $lastAttachment.filename,
18 + 'comment': $comment,
15 15   'form_token': $request.form_token
16 16   })))
17 17   #stop
... ... @@ -22,7 +22,6 @@
22 22  ##
23 23  ## Macros
24 24  ##
25 -#set ($translationPrefix = 'xe.attachmentSelector')
26 26  #set ($attachmentPickerDocName = 'XWiki.AttachmentSelector')
27 27  
28 28  $xwiki.ssx.use($attachmentPickerDocName)
... ... @@ -42,11 +42,14 @@
42 42   #end
43 43   (% class="gallery" %)(((
44 44   ## Only display the upload form if they have edit permission on targetAttachDocument
45 - #if ($xwiki.hasAccessLevel('edit',$xcontext.user,${targetAttachDocument.fullName}))
46 - #attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
47 - #end
48 + #attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
48 48   #attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
49 - #set ($sortedAttachments = $sorttool.sort($targetAttachDocument.getAttachmentList(), "${options.sortAttachmentsBy}") )
50 + #if ("$!services.temporaryAttachments" != '')
51 + #set ($unsortedAttachments = $services.temporaryAttachments.listAllAttachments($targetAttachDocument))
52 + #set ($sortedAttachments = $collectiontool.sort($unsortedAttachments, "${options.sortAttachmentsBy}"))
53 + #else
54 + #set ($sortedAttachments = $collectiontool.sort($targetAttachDocument.getAttachmentList(), "${options.sortAttachmentsBy}") )
55 + #end
50 50   #foreach ($attachment in $sortedAttachments)
51 51   #set ($extension = $attachment.getFilename())
52 52   #set ($extension = $extension.substring($mathtool.add($extension.lastIndexOf('.'), 1)).toLowerCase())
... ... @@ -66,18 +66,46 @@
66 66   * @param $currentValue the currently selected file, used for determining if the box should be highlighted as the current value
67 67   *#
68 68  #macro (attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
69 - #if ($options.displayImage && $attachment.isImage())
70 - #set ($cssClass = 'gallery_image')
75 + #set ($hasTemporaryAttachment = "$!services.temporaryAttachments" != '')
76 + #set ($canEdit = $xwiki.hasAccessLevel('edit', $xcontext.user, ${targetAttachDocument.fullName}))
77 + #set ($isTemporaryAttachment = false)
78 + #if(!$hasTemporaryAttachment)
79 + #set ($canDeleteAttachment = $canEdit)
71 71   #else
72 - #set ($cssClass = '')
81 + #set ($isTemporaryAttachment = $services.temporaryAttachments.temporaryAttachmentExists($attachment))
82 + ## TODO: Update once it is made possible to delete temporary attachments (see XWIKI-20225).
83 + #set ($canDeleteAttachment = !$isTemporaryAttachment && $canEdit)
73 73   #end
74 - #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "$!{cssClass}"} $currentValue)
85 + #set ($cssClasses = [])
86 + #if ($options.displayImage && $attachment.isImage())
87 + #set ($discard = $cssClasses.add('gallery_image'))
88 + #end
89 + #if ($isTemporaryAttachment)
90 + #set ($discard = $cssClasses.add('temporary_attachment'))
91 + #end
92 + #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "${stringtool.join($cssClasses, ' ')}"} $currentValue)
75 75   #attachmentPicker_displayAttachmentDetails($attachment $options)
76 76   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
77 77   #set ($deleteURL = $targetAttachDocument.getAttachmentURL($attachment.filename, 'delattachment', "xredirect=${returnURL}&form_token=$!{services.csrf.getToken()}") )
78 78   #set ($viewURL = $targetAttachDocument.getAttachmentURL($attachment.filename) )##{'name' : 'download', 'url' : $viewURL, 'rel' : '__blank'}
79 - #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, "${options.get('classname')}_${options.get('object')}_${options.get('property')}=${attachment.filename}&form_token=$!{services.csrf.getToken()}"))
80 - #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}, {'name' : 'delete', 'url' : $deleteURL}])
97 + #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, $escapetool.url({
98 + "${options.get('classname')}_${options.get('object')}_${options.get('property')}": ${attachment.filename},
99 + 'form_token': $!{services.csrf.getToken()}
100 + })))
101 + ## Delete action is only proposed for users with the edit right on the document.
102 + ## If the temporary attachment is available, the delete action is only allowed for non-temporary attachments.
103 + #set ($attachmentActions = [{'name' : 'select', 'url' : $selectURL}])
104 + #if($canDeleteAttachment)
105 + #set ($discard = $attachmentActions.add({'name' : 'delete', 'url' : $deleteURL}))
106 + #end
107 + #define($additionalContent)
108 + #if ($isTemporaryAttachment)
109 + #set ($titleMessage = $services.localization.render('attachment.attachmentSelector.attachmentBox.temporaryAttachmentTitle'))
110 + #set ($titleMessage = $services.rendering.escape($titleMessage, 'xwiki/2.1'))
111 + (% title="$titleMessage" %)$services.icon.render('clock')(%%)
112 + #end
113 + #end
114 + #attachmentPicker_displayEndFrame ($attachmentActions $additionalContent)
81 81  #end
82 82  
83 83  #**
... ... @@ -89,7 +89,9 @@
89 89   *#
90 90  #macro (attachmentPicker_displayStartFrame $boxOptions $currentValue)
91 91   (% class="gallery_attachmentbox $!{boxOptions.cssClass} #if ("$!{boxOptions.value}" == $currentValue) current#{end}" %)(((
92 - (% class="gallery_attachmenttitle" title="$!{boxOptions.value}" %)((($boxOptions.text)))
126 + (% class="gallery_attachmenttitle" title="$services.rendering.escape($!{boxOptions.value}, 'xwiki/2.1')" %)(((
127 + $services.rendering.escape($boxOptions.text, 'xwiki/2.1')
128 + )))
93 93   (% class="gallery_attachmentframe" %)(((
94 94  #end
95 95  
... ... @@ -105,16 +105,16 @@
105 105   ## Compute the attachment reference because there's no getter.
106 106   #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
107 107   $attachment.filename))
108 - #set ($attachmentStringReference = $services.model.serialize($attachmentReference, 'default'))
144 + #set ($attachmentStringReference = $services.rendering.escape($services.model.serialize($attachmentReference, 'default'), 'xwiki/2.1'))
109 109   #if ($attachment.isImage() && $options.displayImage)
110 110   ## We add the version to the query string in order to invalidate the cache when an image attachment is replaced.
111 111   #set ($queryString = $escapetool.url({'version': $attachment.version}))
112 - [[[[image:$attachmentStringReference||width=180 queryString="$queryString"]]>>attach:$attachmentStringReference]]
148 + [[[[image:${attachmentStringReference}||width=180 queryString="$queryString"]]>>attach:$attachmentStringReference]]
113 113   #else
114 - * (% class="mime" %){{html wiki=false clean=false}}#mimetypeimg($attachment.getMimeType().toLowerCase() $attachment.getFilename().toLowerCase()){{/html}}(%%) (% class="filename" %)$attachment.getFilename()(% %)
150 + * (% class="mime" %){{html wiki=false clean=false}}#mimetypeimg($attachment.getMimeType().toLowerCase() $attachment.getFilename().toLowerCase()){{/html}}(%%) (% class="filename" %)$services.rendering.escape($attachment.getFilename(), 'xwiki/2.1')(% %)
115 115   * v$attachment.getVersion() (#dynamicsize($attachment.longSize))
116 116   * $services.localization.render('core.viewers.attachments.author', [$!{xwiki.getUserName($attachment.author, false)}]) $services.localization.render('core.viewers.attachments.date', [$!{xwiki.formatDate($attachment.date, 'dd/MM/yyyy hh:mm')}])
117 - * (% class="buttonwrapper" %)[[${services.localization.render("${translationPrefix}.actions.download")}>>attach:$attachmentStringReference||title="$services.localization.render("${translationPrefix}.actions.download")" rel="__blank" class="button"]](%%)
153 + * (% class="buttonwrapper" %)[[${services.localization.render("${translationPrefix}.actions.download")}>>attach:${attachmentStringReference}||title="$services.localization.render("${translationPrefix}.actions.download")" rel="__blank" class="button"]](%%)
118 118   #end
119 119   #end
120 120  #end
... ... @@ -131,8 +131,9 @@
131 131   * <dt>rel</dt>
132 132   * <dd>an optional parameter to be used in the "rel" HTML attribute; for example "__blank" can be used to open the link in a new tab/window</dd>
133 133   * </dl>
170 + * @param $additionalContent optional additional content that does not follow the structure of the actions
134 134   *#
135 -#macro (attachmentPicker_displayEndFrame $actions)
172 +#macro (attachmentPicker_displayEndFrame $actions $additionalContent)
136 136   )))## attachmentframe
137 137   (% class="gallery_actions" %)(((
138 138   #foreach ($action in $actions)
... ... @@ -139,6 +139,7 @@
139 139   #set( $actionname = $services.localization.render("${translationPrefix}.actions.${action.name}") )
140 140   [[${actionname}>>path:${action.url}||class="tool ${action.name}" title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
141 141   #end
179 + $!additionalContent
142 142   )))## actions
143 143   )))## attachmentbox
144 144  #end
... ... @@ -282,7 +282,7 @@
282 282   #end
283 283   #set ($options = {
284 284   'classname' : ${request.get('classname')},
285 - 'object' : $!{mathtool.toInteger($request.object)},
323 + 'object' : $!{numbertool.toNumber($request.object).intValue()},
286 286   'property' : ${request.property},
287 287   'displayImage' : ${displayImage},
288 288   'docAction' : ${docAction},
... ... @@ -295,8 +295,10 @@
295 295   $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
296 296   #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
297 297  
336 + #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
337 + #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
298 298   (% class="gallery_buttons buttons" %)(((
299 - (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")>>$targetDocument||class="button secondary" id="attachment-picker-close"]]
339 + (% class="buttonwrapper secondary" %)[[$cancelLinkName>>$cancelLinkTarget||class="button secondary" id="attachment-picker-close"]]
300 300   )))
301 301  #end
302 302  {{/velocity}}
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,4 +1,66 @@
1 1  var XWiki = (function(XWiki) {
2 + function uploadTemporaryAttachment() {
3 + // Require jquery locally until we are able to fully migrate this code away from prototype.
4 + const form = this.property.up('form');
5 + require(['jquery'], function ($) {
6 + const data = new FormData();
7 + const uploadedFile = $('#attachfile')[0].files[0];
8 + const filenameCheckbox = $("#uploadAttachment input[name='filename']");
9 +
10 + // TODO: Fix replace currently selected checkbox (see XWIKI-20181).
11 + data.append('upload', uploadedFile);
12 + const notification = new XWiki.widgets.Notification(
13 + "$services.localization.render('xe.attachmentSelector.upload.inProgress')", 'inprogress');
14 + const params = {
15 + 'form_token': $(form).find('[name="form_token"]').val(),
16 + 'sheet': 'CKEditor.FileUploader',
17 + 'outputSyntax': 'plain'
18 + };
19 +
20 + // Update the name of the file with the name of the currently selected attachment if required.
21 + if (filenameCheckbox.prop('checked')) {
22 + params['filename'] = filenameCheckbox.val()
23 + }
24 +
25 + $.ajax({
26 + 'url': XWiki.currentDocument.getURL('get', new URLSearchParams(params).toString()),
27 + method: 'POST',
28 + data: data,
29 + processData: false,
30 + contentType: false, // Sets the 'multipart/form-data' automatically
31 + headers: {
32 + 'X-XWiki-Temporary-Attachment-Support': true
33 + }
34 + }).done(function (response) {
35 + #set ($successMessage = $escapetool.javascript($services.localization.render('attachment.attachmentSelector.temporaryUpload.success')))
36 + notification.replace(new XWiki.widgets.Notification("$successMessage", 'done'));
37 + // Add a field with the name of the uploaded file so that it is moved from the temporary
38 + // attachments to the persisded ones on save.
39 + $(form).append($('<input/>')
40 + .prop('type', 'hidden')
41 + .prop('name', 'uploadedFiles')
42 + .prop('value', response.fileName))
43 + $(form).find('input[type="hidden"].property-reference').prop('value', response.fileName);
44 + this.updateAttachment(response.fileName, response.url);
45 + this.dialog.closeDialog();
46 + }.bind(this)).fail(function () {
47 + #set ($errorMessage = $escapetool.javascript($services.localization.render('attachment.attachmentSelector.temporaryUpload.failure')))notification.replace(new XWiki.widgets.Notification("$errorMessage", 'error'));
48 + });
49 + }.bind(this));
50 + }
51 +
52 + function directUploadAttachment(uploadForm) {
53 + // FIXME This fails in HTML5, will deal with it later:
54 + // this.property.down('input').value = uploadForm.down('input[type="file"]').value;
55 + // uploadForm.xredirect.value = window.location.pathname;
56 + document.observe('xwiki:document:saved', function () {
57 + new XWiki.widgets.Notification("$services.localization.render('xe.attachmentSelector.upload.inProgress')",
58 + 'inprogress');
59 + uploadForm.submit();
60 + })
61 + document.fire('xwiki:actions:save', {'continue': true, form: this.property.up('form')});
62 + }
63 +
2 2   /** Handles the gallery buttons directly in the current page without reloading the window. */
3 3   XWiki.AttachmentPicker = Class.create({
4 4   /**
... ... @@ -60,21 +60,23 @@
60 60   new XWiki.widgets.Notification("$services.localization.render('xe.attachmentSelector.upload.error.badExtension')", 'error');
61 61   hasErrors = true;
62 62   }
125 + const beforeUploadEvent = Event.fire(document, 'xwiki:actions:beforeUpload', {
126 + file: fileInput.files[0]
127 + });
128 +
129 + if (beforeUploadEvent.defaultPrevented) {
130 + hasErrors = true;
131 + }
63 63   }.bind(this));
64 - // No form submission by AJAX right now, because file uploads can't be done this way without HTML5, this is future work
65 - // Save the document before submitting, since the current form data will be lost otherwise
66 66   if (!hasErrors) {
67 67   if (this.directSave) {
68 68   uploadForm.submit();
69 69   } else {
70 - // FIXME This fails in HTML5, will deal with it later:
71 - // this.property.down('input').value = uploadForm.down('input[type="file"]').value;
72 - // uploadForm.xredirect.value = window.location.pathname;
73 - document.observe('xwiki:document:saved', function() {
74 - new XWiki.widgets.Notification("$services.localization.render('xe.attachmentSelector.upload.inProgress')", 'inprogress');
75 - uploadForm.submit();
76 - })
77 - document.fire('xwiki:actions:save', {'continue': true, form: this.property.up('form')});
137 + if ("$!services.temporaryAttachments" != '') {
138 + uploadTemporaryAttachment.call(this);
139 + } else {
140 + directUploadAttachment.call(this, uploadForm);
141 + }
78 78   }
79 79   }
80 80   }.bindAsEventListener(this));
... ... @@ -173,10 +173,7 @@
173 173   this.dialog.closeDialog();
174 174   }.bindAsEventListener(this),
175 175   onFailure : function(response) {
176 - var failureReason = response.statusText;
177 - if (response.statusText == '' /* No response */ || response.status == 12031 /* In IE */) {
178 - failureReason = 'Server not responding';
179 - }
240 + var failureReason = response.statusText || 'Server not responding';
180 180   if (targetElement._x_notif) {
181 181   targetElement._x_notif.replace(new XWiki.widgets.Notification("$services.localization.render('core.widgets.confirmationBox.notification.failed')" + failureReason, "error"));
182 182   } else {
... ... @@ -183,9 +183,6 @@
183 183   new XWiki.widgets.Notification(this.interactionParameters.failureMessageText + failureReason, "error");
184 184   }
185 185   },
186 - on1223 : function(response) {
187 - response.request.options.onSuccess(response);
188 - },
189 189   on0 : function(response) {
190 190   response.request.options.onFailure(response);
191 191   },
XWiki.StyleSheetExtension[0]
Code
... ... @@ -27,7 +27,7 @@
27 27  .gallery_attachmentbox {
28 28   background: $theme.pageContentBackgroundColor;
29 29   border: 1px solid $theme.borderColor;
30 - border-radius: 5px;
30 + border-radius: 8px;
31 31   float: left;
32 32   margin: ${boxMargin}px;
33 33   overflow: hidden;
... ... @@ -49,7 +49,7 @@
49 49  .gallery_attachmenttitle {
50 50   background: $theme.backgroundSecondaryColor;
51 51   border-bottom: 1px dotted $theme.borderColor;
52 - border-radius: 5px 5px 0px 0px;
52 + border-radius: 8px 8px 0px 0px;
53 53   font-size: 85%;
54 54   padding: 3px ${boxPadding}px;
55 55   overflow: hidden;
... ... @@ -140,9 +140,6 @@
140 140   ## Make this box twice as large as the others
141 141   width: ${uploadBoxSize}px;
142 142  }
143 -* html .gallery_upload {
144 - width: ${mathtool.add($uploadBoxSize, 2)}px;
145 -}
146 146  .gallery_upload, .gallery_upload:hover {
147 147   background-color: $theme.backgroundSecondaryColor;
148 148  }
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -3,7 +3,6 @@
3 3  $xwiki.ssfx.use('js/xwiki/widgets/modalPopup.css', true)##
4 4  $xwiki.jsx.use($xcontext.macro.doc.fullName)##
5 5  $xwiki.ssx.use($xcontext.macro.doc.fullName)##
6 -$xwiki.jsfx.use('js/scriptaculous/builder.js')##
7 7  ## Integrates the optional Lightbox widget (from http://extensions.xwiki.org/xwiki/bin/view/Extension/Lightbox+Application )
8 8  #if ($xwiki.exists('XWiki.Lightbox'))
9 9   $xwiki.jsx.use('XWiki.Lightbox')
... ... @@ -32,9 +32,9 @@
32 32  #end
33 33  #set ($classname = "$!{xcontext.macro.params.classname}")
34 34  #set ($property = "$!{xcontext.macro.params.property}")
35 -#set ($object = $mathtool.toInteger("$!{xcontext.macro.params.object}"))
34 +#set ($object = $numbertool.toNumber("$!{xcontext.macro.params.object}").intValue())
36 36  #if ("$!{object}" != $!{xcontext.macro.params.object})
37 - #set ($object = ${doc.getObject($classname).number})
36 + #set ($object = ${targetdoc.getObject($classname).number})
38 38   #if ("$!{object}" == '')
39 39   #set ($object = 0)
40 40   #end
... ... @@ -46,9 +46,18 @@
46 46   #set ($displayImage = false)
47 47  #end
48 48  #if ($displayImage)
49 - #set ($alt = "$!{xcontext.macro.params.alternateText}")
50 - #set ($width = "$!{xcontext.macro.params.width}")
51 - #set ($height = "$!{xcontext.macro.params.height}")
48 + #set ($alt = '')
49 + #set ($width = '')
50 + #set ($height = '')
51 + #if ($xcontext.macro.params.alternateText)
52 + #set ($alt = "$services.rendering.escape($!{xcontext.macro.params.alternateText}, 'xwiki/2.1')")
53 + #end
54 + #if ($xcontext.macro.params.width)
55 + #set ($width = "$services.rendering.escape($!{xcontext.macro.params.width}, 'xwiki/2.1')")
56 + #end
57 + #if ($xcontext.macro.params.height)
58 + #set ($height = "$services.rendering.escape($!{xcontext.macro.params.height}, 'xwiki/2.1')")
59 + #end
52 52   #set ($imageParams = '')
53 53   #if ("${width}" != '')
54 54   #set($imageParams = "$!{imageParams} width=${width}")
... ... @@ -86,7 +86,7 @@
86 86   #set ($savemode = 'form')
87 87  #end
88 88  
89 -#set ($propValue = "$!{doc.getObject($classname, $object).getProperty($property).value}")
97 +#set ($propValue = "$!{targetdoc.getObject($classname, $object).getProperty($property).value}")
90 90  ##
91 91  
92 92  #macro (attachmentPicker_displayAttachment $name $displayImage $withLink $forceElement)
... ... @@ -113,9 +113,9 @@
113 113   #set ($attachmentResource = '')
114 114   #end
115 115   #if ($displayImage)
116 - (% class="$!{cssClass}#if (!$attachment) hidden#end" %)(((#if ("$!{attachmentResource}" != '' || $forceElement)#if($withLink)[[#end[[image:${attachmentResource}$!{imageParams}]]#if($withLink)>>attach:${attachmentResource}||rel=lightbox]]#{end}#end)))##
124 + (% class="$!{cssClass}#if (!$attachment) hidden#end" %)(((#if ("$!{attachmentResource}" != '' || $forceElement)#if($withLink)[[#end[[image:$services.rendering.escape(${attachmentResource}, 'xwiki/2.1')$!{imageParams}]]#if($withLink)>>attach:$services.rendering.escape(${attachmentResource},'xwiki/2.1')||rel=lightbox]]#{end}#end)))##
117 117   #else
118 - (% class="$!{cssClass}" %)#if ("$!{attachmentResource}" != '' || $forceElement)#if ($withLink)[[attach:${attachmentResource}||rel=__blank]]#{else}(% class="displayed" %)#if($targetPermView)$!{attachmentName}#{else}Access Denied#{end}(% %)#{end}#end(%%)##
126 + (% class="$!{cssClass}" %)#if ("$!{attachmentResource}" != '' || $forceElement)#if ($withLink)[[attach:${attachmentResource}||rel=__blank]]#{else}(% class="displayed" %)#if($targetPermView)$!{services.rendering.escape($!{attachmentName}, 'xwiki/2.1')}#{else}Access Denied#{end}(% %)#{end}#end(%%)##
119 119   #end
120 120  #end
121 121  
... ... @@ -123,7 +123,7 @@
123 123  ## 1. Edit the current page
124 124  ## 2. View the target attachment page. (can be the same page)
125 125  #macro (attachmentPicker_displayButton)
126 - #if ($hasEdit && $targetPermView)
134 + #if ($targetPermView)
127 127   #set ($queryString = {
128 128   'docname': $doc.fullName,
129 129   'classname': $classname,
... ... @@ -138,8 +138,9 @@
138 138   #if ($hasTargetDoc)
139 139   #set ($queryString.targetdocname = $targetdoc.fullName)
140 140   #end
141 - (% class="buttonwrapper" %)[[$buttontext>>$xcontext.macro.doc.fullName||queryString="$escapetool.url($queryString)"
142 - class="attachment-picker-start button" title="$buttontext"]](%%)##
149 + #set ($linkLabel = $services.rendering.escape($services.rendering.escape($buttontext, 'xwiki/2.1'), 'xwiki/2.1'))
150 + (% class="buttonwrapper" %)[[$linkLabel>>${xcontext.macro.doc.fullName}||queryString="$escapetool.url($queryString)"
151 + class="attachment-picker-start button" title="$services.rendering.escape($buttontext, 'xwiki/2.1')"]](%%)##
143 143   #end
144 144  #end
145 145  {{/velocity}}
... ... @@ -150,7 +150,7 @@
150 150  #elseif ($xcontext.action == 'inline' || $xcontext.action == 'edit')
151 151   (% class="attachment-picker" %)(((##
152 152   #attachmentPicker_displayAttachment($propValue $displayImage false true) #attachmentPicker_displayButton()##
153 - {{html}}<input type="hidden" name="${classname}_${object}_${property}" value="${propValue}"/>{{/html}}##
162 + {{html}}<input type="hidden" name="$escapetool.xml("${classname}_${object}_${property}")" value="$escapetool.xml("${propValue}")" class="property-reference"/>{{/html}}##
154 154   )))
155 155  #else
156 156   #attachmentPicker_displayAttachment($propValue $displayImage $link false)
Default category
... ... @@ -1,1 +1,0 @@
1 -Development
Cached
... ... @@ -1,0 +1,1 @@
1 +No
Asynchronous rendering
... ... @@ -1,0 +1,1 @@
1 +No
Default categories
... ... @@ -1,0 +1,1 @@
1 +Development
XWiki.WikiMacroParameterClass[0]
Parameter type
... ... @@ -1,0 +1,1 @@
1 +org.xwiki.model.reference.DocumentReference
XWiki.WikiMacroParameterClass[10]
Parameter type
... ... @@ -1,0 +1,1 @@
1 +org.xwiki.model.reference.AttachmentReference
XWiki.WikiMacroParameterClass[18]
Parameter type
... ... @@ -1,0 +1,1 @@
1 +org.xwiki.model.reference.DocumentReference