0 Votes

Changes for page Attachments

Last modified by Сергей Коршунов on 2025/09/03 11:22

From version 4.1
edited by Сергей Коршунов
on 2022/07/28 10:57
Change comment: Migrated property [defaultCategories] from class [XWiki.WikiMacroClass]
To version 18.1
edited by Сергей Коршунов
on 2025/09/03 11:22
Change comment: Install extension [org.xwiki.platform:xwiki-platform-attachment-ui/17.7.0]

Summary

Details

Page properties
Content
... ... @@ -38,7 +38,7 @@
38 38   * @param $targetAttachDocument the document to list/save attachments to
39 39   * @param $options generic picker options
40 40   *#
41 -#macro (attachmentPicker_displayAttachmentGallery $targetDocument, $targetAttachDocument, $options)
41 +#macro (_attachmentPicker_displayAttachmentGallery $targetDocument, $targetAttachDocument, $options)
42 42   #set ($currentValue = $targetDocument.getValue($options.property))
43 43   #if ("$!{targetAttachDocument.getAttachment($currentValue)}" == '')
44 44   #set ($currentValue = "$!{options.defaultValue}")
... ... @@ -45,16 +45,19 @@
45 45   #end
46 46   (% class="gallery" %)(((
47 47   ## Only display the upload form if they have edit permission on targetAttachDocument
48 - #if ($xwiki.hasAccessLevel('edit',$xcontext.user,${targetAttachDocument.fullName}))
49 - #attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
48 + #_attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
49 + #_attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
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}") )
50 50   #end
51 - #attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
52 - #set ($sortedAttachments = $collectiontool.sort($targetAttachDocument.getAttachmentList(), "${options.sortAttachmentsBy}") )
53 53   #foreach ($attachment in $sortedAttachments)
54 54   #set ($extension = $attachment.getFilename())
55 55   #set ($extension = $extension.substring($mathtool.add($extension.lastIndexOf('.'), 1)).toLowerCase())
56 56   #if ($options.filter.size() == 0 || $options.filter.contains($extension))
57 - #attachmentPicker_displayAttachmentBox($attachment $targetDocument $targetAttachDocument, $options $currentValue)
60 + #_attachmentPicker_displayAttachmentBox($attachment $targetDocument $targetAttachDocument, $options $currentValue)
58 58   #end
59 59   #end
60 60   )))
... ... @@ -68,14 +68,26 @@
68 68   * @param $options generic picker options
69 69   * @param $currentValue the currently selected file, used for determining if the box should be highlighted as the current value
70 70   *#
71 -#macro (attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
72 - #if ($options.displayImage && $attachment.isImage())
73 - #set ($cssClass = 'gallery_image')
74 +#macro (_attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
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)
74 74   #else
75 - #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)
76 76   #end
77 - #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "$!{cssClass}"} $currentValue)
78 - #attachmentPicker_displayAttachmentDetails($attachment $options)
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)
93 + #_attachmentPicker_displayAttachmentDetails($attachment $options)
79 79   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
80 80   #set ($deleteURL = $targetAttachDocument.getAttachmentURL($attachment.filename, 'delattachment', "xredirect=${returnURL}&form_token=$!{services.csrf.getToken()}") )
81 81   #set ($viewURL = $targetAttachDocument.getAttachmentURL($attachment.filename) )##{'name' : 'download', 'url' : $viewURL, 'rel' : '__blank'}
... ... @@ -83,7 +83,20 @@
83 83   "${options.get('classname')}_${options.get('object')}_${options.get('property')}": ${attachment.filename},
84 84   'form_token': $!{services.csrf.getToken()}
85 85   })))
86 - #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}, {'name' : 'delete', 'url' : $deleteURL}])
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, 'icon' : 'check', 'extraCssClass' : 'btn btn-xs btn-success'}])
104 + #if($canDeleteAttachment)
105 + #set ($discard = $attachmentActions.add({'name' : 'delete', 'url' : $deleteURL, 'icon' : 'cross', 'extraCssClass' : 'btn btn-xs btn-danger'}))
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)
87 87  #end
88 88  
89 89  #**
... ... @@ -93,9 +93,10 @@
93 93   * the title to display (boxOptions.text), optional extra CSS classnames to put on the box (boxOptions.cssClass)
94 94   * @param $currentValue the currently selected file, used for determining if this attachment should be highlighted as the current value
95 95   *#
96 -#macro (attachmentPicker_displayStartFrame $boxOptions $currentValue)
124 +#macro (_attachmentPicker_displayStartFrame $boxOptions $currentValue)
97 97   (% class="gallery_attachmentbox $!{boxOptions.cssClass} #if ("$!{boxOptions.value}" == $currentValue) current#{end}" %)(((
98 98   (% class="gallery_attachmenttitle" title="$services.rendering.escape($!{boxOptions.value}, 'xwiki/2.1')" %)(((
127 + #if($!{boxOptions.cssClass} == 'gallery_upload')$services.icon.render('add') #end##
99 99   $services.rendering.escape($boxOptions.text, 'xwiki/2.1')
100 100   )))
101 101   (% class="gallery_attachmentframe" %)(((
... ... @@ -108,7 +108,7 @@
108 108   * @param $attachment the target attachment to display
109 109   * @param $options generic picker options
110 110   *#
111 -#macro (attachmentPicker_displayAttachmentDetails $attachment $options)
140 +#macro (_attachmentPicker_displayAttachmentDetails $attachment $options)
112 112   #if ($attachment)
113 113   ## Compute the attachment reference because there's no getter.
114 114   #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
... ... @@ -139,14 +139,18 @@
139 139   * <dt>rel</dt>
140 140   * <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>
141 141   * </dl>
171 + * @param $additionalContent optional additional content that does not follow the structure of the actions
142 142   *#
143 -#macro (attachmentPicker_displayEndFrame $actions)
173 +#macro (_attachmentPicker_displayEndFrame $actions $additionalContent)
144 144   )))## attachmentframe
145 145   (% class="gallery_actions" %)(((
146 146   #foreach ($action in $actions)
147 147   #set( $actionname = $services.localization.render("${translationPrefix}.actions.${action.name}") )
148 - [[${actionname}>>path:${action.url}||class="tool ${action.name}" title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
178 + [[${services.icon.render($action.icon)}(% class="sr-only"%)${actionname}(%%)>>##
179 + path:${action.url}||class="tool ${action.name} $!{action.extraCssClass}"##
180 + title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
149 149   #end
182 + $!additionalContent
150 150   )))## actions
151 151   )))## attachmentbox
152 152  #end
... ... @@ -158,8 +158,8 @@
158 158   * @param $targetAttachDocument the document to upload the attachment to
159 159   * @param $options generic picker options
160 160   *#
161 -#macro (attachmentPicker_displayUploadForm $targetDocument, $targetAttachDocument, $options)
162 -#attachmentPicker_displayStartFrame({
194 +#macro (_attachmentPicker_displayUploadForm $targetDocument, $targetAttachDocument, $options)
195 +#_attachmentPicker_displayStartFrame({
163 163   'value' : $services.localization.render("${translationPrefix}.upload.title"),
164 164   'text' : $services.localization.render("${translationPrefix}.upload.title"),
165 165   'cssClass' : 'gallery_upload'
... ... @@ -206,7 +206,7 @@
206 206   </div>
207 207  </form>
208 208  {{/html}}
209 -#attachmentPicker_displayEndFrame ([])
242 +#_attachmentPicker_displayEndFrame ([])
210 210  #end
211 211  
212 212  #**
... ... @@ -217,7 +217,7 @@
217 217   * @param $options generic picker options
218 218   * @param $currentValue the currently selected file, used for determining if the empty box should be highlighted as the current value
219 219   *#
220 -#macro (attachmentPicker_displayAttachmentGalleryEmptyValue $targetDocument, $targetAttachDocument, $options, $currentValue)
253 +#macro (_attachmentPicker_displayAttachmentGalleryEmptyValue $targetDocument, $targetAttachDocument, $options, $currentValue)
221 221   #if ("$!{options.get('defaultValue')}" != '')
222 222   #set ($reference = ${options.get('defaultValue')})
223 223   #set ($docNameLimit = $reference.indexOf('@'))
... ... @@ -232,11 +232,11 @@
232 232   #set($dcssClass = 'gallery_image')
233 233   #end
234 234   #end
235 - #attachmentPicker_displayStartFrame({'cssClass' : "gallery_emptyChoice $!{dcssClass}", 'text' : $services.localization.render("${translationPrefix}.default"), 'value' : "${options.defaultValue}"} $currentValue)
236 - #attachmentPicker_displayAttachmentDetails($defaultAttachment $options)
268 + #_attachmentPicker_displayStartFrame({'cssClass' : "gallery_emptyChoice $!{dcssClass}", 'text' : $services.localization.render("${translationPrefix}.default"), 'value' : "${options.defaultValue}"} $currentValue)
269 + #_attachmentPicker_displayAttachmentDetails($defaultAttachment $options)
237 237   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
238 238   #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, "${options.get('classname')}_${options.get('object')}_${options.get('property')}=&form_token=$!{services.csrf.getToken()}"))
239 - #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}])
272 + #_attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL, 'icon' : 'check', 'extraCssClass' : 'btn btn-xs btn-success'}])
240 240  #end
241 241  {{/velocity}}
242 242  
... ... @@ -301,10 +301,12 @@
301 301   'versionSummary': $request.versionSummary.equals('true')
302 302   })
303 303   $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
304 - #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
337 + #_attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
305 305  
339 + #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
340 + #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
306 306   (% class="gallery_buttons buttons" %)(((
307 - (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")>>${targetDocument}||class="button secondary" id="attachment-picker-close"]]
342 + (% class="buttonwrapper secondary" %)[[$cancelLinkName>>$cancelLinkTarget||class="button secondary" id="attachment-picker-close"]]
308 308   )))
309 309  #end
310 310  {{/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));
XWiki.StyleSheetExtension[0]
Code
... ... @@ -25,9 +25,12 @@
25 25   margin: 0;
26 26  }
27 27  .gallery_attachmentbox {
28 + display: grid;
29 + gap: .2rem;
28 28   background: $theme.pageContentBackgroundColor;
31 + padding: .2rem;
29 29   border: 1px solid $theme.borderColor;
30 - border-radius: 5px;
33 + border-radius: var(--border-radius-base);
31 31   float: left;
32 32   margin: ${boxMargin}px;
33 33   overflow: hidden;
... ... @@ -36,8 +36,6 @@
36 36  }
37 37  .gallery .current {
38 38   background-color: $theme.highlightColor;
39 - border-width: 3px;
40 - margin: 3px;
41 41  }
42 42  .gallery .current .gallery_attachmenttitle {
43 43   font-weight: bold;
... ... @@ -47,9 +47,7 @@
47 47  }
48 48  
49 49  .gallery_attachmenttitle {
50 - background: $theme.backgroundSecondaryColor;
51 - border-bottom: 1px dotted $theme.borderColor;
52 - border-radius: 5px 5px 0px 0px;
51 + grid-area: 1 / 1 / 2 / 2;
53 53   font-size: 85%;
54 54   padding: 3px ${boxPadding}px;
55 55   overflow: hidden;
... ... @@ -62,7 +62,7 @@
62 62  }
63 63  
64 64  .gallery_attachmentframe {
65 - padding: ${boxPadding}px;
64 + grid-area: 2 / 1 / 3 / 3;
66 66   height: ${imgSize}px;
67 67   overflow: hidden;
68 68   position: relative;
... ... @@ -101,39 +101,16 @@
101 101  }
102 102  
103 103  /* Actions */
104 -.gallery_actions {
105 - width: auto;
106 - position: absolute;
107 - bottom: 0px;
108 - right: ${boxPadding}px;
103 +.gallery_actions p {
104 + grid-area: 1 / 2 / 2 / 3;
105 + display: flex;
106 + justify-content: flex-end;
107 + gap: .2rem;
109 109  }
110 110  .gallery_actions .tool {
111 - background: none no-repeat 50% transparent;
112 112   cursor: pointer;
113 113   display: block;
114 - float: left;
115 - height: ${actionsHeight}px;
116 - padding: 0 !important;
117 - overflow: hidden;
118 - text-indent: -1000em;
119 - opacity: 0.6;
120 - width: ${actionsWidth}px;
121 121  }
122 -.gallery_actions .tool:hover {
123 - opacity: 1;
124 -}
125 -.gallery_actions .select {
126 - background-image: url("$xwiki.getSkinFile('icons/silk/tick.png')");
127 -}
128 -.gallery_actions .delete {
129 - background-image: url("$xwiki.getSkinFile('icons/silk/cross.png')");
130 -}
131 -.gallery_actions .view {
132 - background-image: url("$xwiki.getSkinFile('icons/silk/link.png')");
133 -}
134 -.gallery_actions .download {
135 - background-image: url("$xwiki.getSkinFile('icons/silk/arrow_down.png')");
136 -}
137 137  /*--------------------------------------------------*/
138 138  /* Upload form */
139 139  .gallery_upload {
... ... @@ -144,12 +144,6 @@
144 144   background-color: $theme.backgroundSecondaryColor;
145 145  }
146 146  
147 -.gallery_upload .gallery_attachmenttitle {
148 - background-position: 1px center;
149 - background-image: url("$xwiki.getSkinFile('icons/silk/bullet_add.png')");
150 - background-repeat: no-repeat;
151 - padding-left: 16px;
152 -}
153 153  .gallery_upload .gallery_attachmentframe {
154 154   height: auto;
155 155  }
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -33,7 +33,7 @@
33 33  #set ($property = "$!{xcontext.macro.params.property}")
34 34  #set ($object = $numbertool.toNumber("$!{xcontext.macro.params.object}").intValue())
35 35  #if ("$!{object}" != $!{xcontext.macro.params.object})
36 - #set ($object = ${doc.getObject($classname).number})
36 + #set ($object = ${targetdoc.getObject($classname).number})
37 37   #if ("$!{object}" == '')
38 38   #set ($object = 0)
39 39   #end
... ... @@ -94,10 +94,10 @@
94 94   #set ($savemode = 'form')
95 95  #end
96 96  
97 -#set ($propValue = "$!{doc.getObject($classname, $object).getProperty($property).value}")
97 +#set ($propValue = "$!{targetdoc.getObject($classname, $object).getProperty($property).value}")
98 98  ##
99 99  
100 -#macro (attachmentPicker_displayAttachment $name $displayImage $withLink $forceElement)
100 +#macro (_attachmentPicker_displayAttachment $name $displayImage $withLink $forceElement)
101 101   #set ($attachment = $targetdoc.getAttachment("$!{name}"))
102 102   #if ("$!{name}" != '' && "$!{attachment}" != '')
103 103   #set ($attachmentRef = $services.model.createAttachmentReference(${targetdoc.documentReference}, ${name}))
... ... @@ -123,7 +123,7 @@
123 123   #if ($displayImage)
124 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)))##
125 125   #else
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(%%)##
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(%%)##
127 127   #end
128 128  #end
129 129  
... ... @@ -130,8 +130,8 @@
130 130  ## Display the "Choose an attachment" button if they can:
131 131  ## 1. Edit the current page
132 132  ## 2. View the target attachment page. (can be the same page)
133 -#macro (attachmentPicker_displayButton)
134 - #if ($hasEdit && $targetPermView)
133 +#macro (_attachmentPicker_displayButton)
134 + #if ($targetPermView)
135 135   #set ($queryString = {
136 136   'docname': $doc.fullName,
137 137   'classname': $classname,
... ... @@ -155,13 +155,13 @@
155 155  
156 156  {{velocity}}
157 157  #if ("${savemode}" == 'direct')
158 - (% class="attachment-picker" %)(((#attachmentPicker_displayAttachment($propValue $displayImage $link true) #attachmentPicker_displayButton())))
158 + (% class="attachment-picker" %)(((#_attachmentPicker_displayAttachment($propValue $displayImage $link true) #_attachmentPicker_displayButton())))
159 159  #elseif ($xcontext.action == 'inline' || $xcontext.action == 'edit')
160 160   (% class="attachment-picker" %)(((##
161 - #attachmentPicker_displayAttachment($propValue $displayImage false true) #attachmentPicker_displayButton()##
162 - {{html}}<input type="hidden" name="${classname}_${object}_${property}" value="${propValue}"/>{{/html}}##
161 + #_attachmentPicker_displayAttachment($propValue $displayImage false true) #_attachmentPicker_displayButton()##
162 + {{html}}<input type="hidden" name="$escapetool.xml("${classname}_${object}_${property}")" value="$escapetool.xml("${propValue}")" class="property-reference"/>{{/html}}##
163 163   )))
164 164  #else
165 - #attachmentPicker_displayAttachment($propValue $displayImage $link false)
165 + #_attachmentPicker_displayAttachment($propValue $displayImage $link false)
166 166  #end
167 167  {{/velocity}}
Default category
... ... @@ -1,1 +1,0 @@
1 -Development
Default categories
... ... @@ -1,0 +1,1 @@
1 +Development