Changes for page Attachments

Last modified by Drunk Monkey on 2025-09-01 07:39

From version 20.1
edited by Drunk Monkey
on 2025-09-01 07:39
Change comment: Install extension [org.xwiki.platform:xwiki-platform-attachment-ui/17.7.0]
To version 19.1
edited by Drunk Monkey
on 2025-07-01 07:23
Change comment: Migrated property [contentOrder] from class [XWiki.WikiMacroClass]

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,8 +45,8 @@
45 45   #end
46 46   (% class="gallery" %)(((
47 47   ## Only display the upload form if they have edit permission on targetAttachDocument
48 - #_attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
49 - #_attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
48 + #attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
49 + #attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
50 50   #if ("$!services.temporaryAttachments" != '')
51 51   #set ($unsortedAttachments = $services.temporaryAttachments.listAllAttachments($targetAttachDocument))
52 52   #set ($sortedAttachments = $collectiontool.sort($unsortedAttachments, "${options.sortAttachmentsBy}"))
... ... @@ -57,7 +57,7 @@
57 57   #set ($extension = $attachment.getFilename())
58 58   #set ($extension = $extension.substring($mathtool.add($extension.lastIndexOf('.'), 1)).toLowerCase())
59 59   #if ($options.filter.size() == 0 || $options.filter.contains($extension))
60 - #_attachmentPicker_displayAttachmentBox($attachment $targetDocument $targetAttachDocument, $options $currentValue)
60 + #attachmentPicker_displayAttachmentBox($attachment $targetDocument $targetAttachDocument, $options $currentValue)
61 61   #end
62 62   #end
63 63   )))
... ... @@ -71,7 +71,7 @@
71 71   * @param $options generic picker options
72 72   * @param $currentValue the currently selected file, used for determining if the box should be highlighted as the current value
73 73   *#
74 -#macro (_attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
74 +#macro (attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
75 75   #set ($hasTemporaryAttachment = "$!services.temporaryAttachments" != '')
76 76   #set ($canEdit = $xwiki.hasAccessLevel('edit', $xcontext.user, ${targetAttachDocument.fullName}))
77 77   #set ($isTemporaryAttachment = false)
... ... @@ -89,8 +89,8 @@
89 89   #if ($isTemporaryAttachment)
90 90   #set ($discard = $cssClasses.add('temporary_attachment'))
91 91   #end
92 - #_attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "${stringtool.join($cssClasses, ' ')}"} $currentValue)
93 - #_attachmentPicker_displayAttachmentDetails($attachment $options)
92 + #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "${stringtool.join($cssClasses, ' ')}"} $currentValue)
93 + #attachmentPicker_displayAttachmentDetails($attachment $options)
94 94   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
95 95   #set ($deleteURL = $targetAttachDocument.getAttachmentURL($attachment.filename, 'delattachment', "xredirect=${returnURL}&form_token=$!{services.csrf.getToken()}") )
96 96   #set ($viewURL = $targetAttachDocument.getAttachmentURL($attachment.filename) )##{'name' : 'download', 'url' : $viewURL, 'rel' : '__blank'}
... ... @@ -100,9 +100,9 @@
100 100   })))
101 101   ## Delete action is only proposed for users with the edit right on the document.
102 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'}])
103 + #set ($attachmentActions = [{'name' : 'select', 'url' : $selectURL}])
104 104   #if($canDeleteAttachment)
105 - #set ($discard = $attachmentActions.add({'name' : 'delete', 'url' : $deleteURL, 'icon' : 'cross', 'extraCssClass' : 'btn btn-xs btn-danger'}))
105 + #set ($discard = $attachmentActions.add({'name' : 'delete', 'url' : $deleteURL}))
106 106   #end
107 107   #define($additionalContent)
108 108   #if ($isTemporaryAttachment)
... ... @@ -111,7 +111,7 @@
111 111   (% title="$titleMessage" %)$services.icon.render('clock')(%%)
112 112   #end
113 113   #end
114 - #_attachmentPicker_displayEndFrame ($attachmentActions $additionalContent)
114 + #attachmentPicker_displayEndFrame ($attachmentActions $additionalContent)
115 115  #end
116 116  
117 117  #**
... ... @@ -121,10 +121,9 @@
121 121   * the title to display (boxOptions.text), optional extra CSS classnames to put on the box (boxOptions.cssClass)
122 122   * @param $currentValue the currently selected file, used for determining if this attachment should be highlighted as the current value
123 123   *#
124 -#macro (_attachmentPicker_displayStartFrame $boxOptions $currentValue)
124 +#macro (attachmentPicker_displayStartFrame $boxOptions $currentValue)
125 125   (% class="gallery_attachmentbox $!{boxOptions.cssClass} #if ("$!{boxOptions.value}" == $currentValue) current#{end}" %)(((
126 126   (% class="gallery_attachmenttitle" title="$services.rendering.escape($!{boxOptions.value}, 'xwiki/2.1')" %)(((
127 - #if($!{boxOptions.cssClass} == 'gallery_upload')$services.icon.render('add') #end##
128 128   $services.rendering.escape($boxOptions.text, 'xwiki/2.1')
129 129   )))
130 130   (% class="gallery_attachmentframe" %)(((
... ... @@ -137,7 +137,7 @@
137 137   * @param $attachment the target attachment to display
138 138   * @param $options generic picker options
139 139   *#
140 -#macro (_attachmentPicker_displayAttachmentDetails $attachment $options)
139 +#macro (attachmentPicker_displayAttachmentDetails $attachment $options)
141 141   #if ($attachment)
142 142   ## Compute the attachment reference because there's no getter.
143 143   #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
... ... @@ -170,14 +170,12 @@
170 170   * </dl>
171 171   * @param $additionalContent optional additional content that does not follow the structure of the actions
172 172   *#
173 -#macro (_attachmentPicker_displayEndFrame $actions $additionalContent)
172 +#macro (attachmentPicker_displayEndFrame $actions $additionalContent)
174 174   )))## attachmentframe
175 175   (% class="gallery_actions" %)(((
176 176   #foreach ($action in $actions)
177 177   #set( $actionname = $services.localization.render("${translationPrefix}.actions.${action.name}") )
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]]##
177 + [[${actionname}>>path:${action.url}||class="tool ${action.name}" title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
181 181   #end
182 182   $!additionalContent
183 183   )))## actions
... ... @@ -191,8 +191,8 @@
191 191   * @param $targetAttachDocument the document to upload the attachment to
192 192   * @param $options generic picker options
193 193   *#
194 -#macro (_attachmentPicker_displayUploadForm $targetDocument, $targetAttachDocument, $options)
195 -#_attachmentPicker_displayStartFrame({
191 +#macro (attachmentPicker_displayUploadForm $targetDocument, $targetAttachDocument, $options)
192 +#attachmentPicker_displayStartFrame({
196 196   'value' : $services.localization.render("${translationPrefix}.upload.title"),
197 197   'text' : $services.localization.render("${translationPrefix}.upload.title"),
198 198   'cssClass' : 'gallery_upload'
... ... @@ -239,7 +239,7 @@
239 239   </div>
240 240  </form>
241 241  {{/html}}
242 -#_attachmentPicker_displayEndFrame ([])
239 +#attachmentPicker_displayEndFrame ([])
243 243  #end
244 244  
245 245  #**
... ... @@ -250,7 +250,7 @@
250 250   * @param $options generic picker options
251 251   * @param $currentValue the currently selected file, used for determining if the empty box should be highlighted as the current value
252 252   *#
253 -#macro (_attachmentPicker_displayAttachmentGalleryEmptyValue $targetDocument, $targetAttachDocument, $options, $currentValue)
250 +#macro (attachmentPicker_displayAttachmentGalleryEmptyValue $targetDocument, $targetAttachDocument, $options, $currentValue)
254 254   #if ("$!{options.get('defaultValue')}" != '')
255 255   #set ($reference = ${options.get('defaultValue')})
256 256   #set ($docNameLimit = $reference.indexOf('@'))
... ... @@ -265,11 +265,11 @@
265 265   #set($dcssClass = 'gallery_image')
266 266   #end
267 267   #end
268 - #_attachmentPicker_displayStartFrame({'cssClass' : "gallery_emptyChoice $!{dcssClass}", 'text' : $services.localization.render("${translationPrefix}.default"), 'value' : "${options.defaultValue}"} $currentValue)
269 - #_attachmentPicker_displayAttachmentDetails($defaultAttachment $options)
265 + #attachmentPicker_displayStartFrame({'cssClass' : "gallery_emptyChoice $!{dcssClass}", 'text' : $services.localization.render("${translationPrefix}.default"), 'value' : "${options.defaultValue}"} $currentValue)
266 + #attachmentPicker_displayAttachmentDetails($defaultAttachment $options)
270 270   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
271 271   #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, "${options.get('classname')}_${options.get('object')}_${options.get('property')}=&form_token=$!{services.csrf.getToken()}"))
272 - #_attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL, 'icon' : 'check', 'extraCssClass' : 'btn btn-xs btn-success'}])
269 + #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}])
273 273  #end
274 274  {{/velocity}}
275 275  
... ... @@ -334,7 +334,7 @@
334 334   'versionSummary': $request.versionSummary.equals('true')
335 335   })
336 336   $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
337 - #_attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
334 + #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
338 338  
339 339   #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
340 340   #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
XWiki.StyleSheetExtension[0]
Code
... ... @@ -25,12 +25,9 @@
25 25   margin: 0;
26 26  }
27 27  .gallery_attachmentbox {
28 - display: grid;
29 - gap: .2rem;
30 30   background: $theme.pageContentBackgroundColor;
31 - padding: .2rem;
32 32   border: 1px solid $theme.borderColor;
33 - border-radius: var(--border-radius-base);
30 + border-radius: 8px;
34 34   float: left;
35 35   margin: ${boxMargin}px;
36 36   overflow: hidden;
... ... @@ -39,6 +39,8 @@
39 39  }
40 40  .gallery .current {
41 41   background-color: $theme.highlightColor;
39 + border-width: 3px;
40 + margin: 3px;
42 42  }
43 43  .gallery .current .gallery_attachmenttitle {
44 44   font-weight: bold;
... ... @@ -48,7 +48,9 @@
48 48  }
49 49  
50 50  .gallery_attachmenttitle {
51 - grid-area: 1 / 1 / 2 / 2;
50 + background: $theme.backgroundSecondaryColor;
51 + border-bottom: 1px dotted $theme.borderColor;
52 + border-radius: 8px 8px 0px 0px;
52 52   font-size: 85%;
53 53   padding: 3px ${boxPadding}px;
54 54   overflow: hidden;
... ... @@ -61,7 +61,7 @@
61 61  }
62 62  
63 63  .gallery_attachmentframe {
64 - grid-area: 2 / 1 / 3 / 3;
65 + padding: ${boxPadding}px;
65 65   height: ${imgSize}px;
66 66   overflow: hidden;
67 67   position: relative;
... ... @@ -100,16 +100,39 @@
100 100  }
101 101  
102 102  /* Actions */
103 -.gallery_actions p {
104 - grid-area: 1 / 2 / 2 / 3;
105 - display: flex;
106 - justify-content: flex-end;
107 - gap: .2rem;
104 +.gallery_actions {
105 + width: auto;
106 + position: absolute;
107 + bottom: 0px;
108 + right: ${boxPadding}px;
108 108  }
109 109  .gallery_actions .tool {
111 + background: none no-repeat 50% transparent;
110 110   cursor: pointer;
111 111   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;
112 112  }
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 +}
113 113  /*--------------------------------------------------*/
114 114  /* Upload form */
115 115  .gallery_upload {
... ... @@ -120,6 +120,12 @@
120 120   background-color: $theme.backgroundSecondaryColor;
121 121  }
122 122  
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 +}
123 123  .gallery_upload .gallery_attachmentframe {
124 124   height: auto;
125 125  }
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -97,7 +97,7 @@
97 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}))
... ... @@ -130,7 +130,7 @@
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)
133 +#macro (attachmentPicker_displayButton)
134 134   #if ($targetPermView)
135 135   #set ($queryString = {
136 136   'docname': $doc.fullName,
... ... @@ -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()##
161 + #attachmentPicker_displayAttachment($propValue $displayImage false true) #attachmentPicker_displayButton()##
162 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}}