# Wiki source code of Attachments

Last modified by Richard Johnson on 2021/05/08 19:20
Export
Office Formats
Export as PDF
Other Formats
Export as HTML

Show last authors

author | version | line-number | content
--- | --- | --- | ---
|  | 1 | {{velocity output="false"}}
|  | 2 | #set ($translationPrefix = 'xe.attachmentSelector')
|  | 3 |
|  | 4 | #if ($request.xaction == 'postUpload')
|  | 5 | #set ($targetDocument = $xwiki.getDocument($request.get('docname')))
|  | 6 | #set ($targetAttachDocument = $xwiki.getDocument($request.get('targetdocname')))
|  | 7 |
|  | 8 | #set ($fieldname = $request.get('fieldname'))
|  | 9 | #set ($comment = $services.localization.render("${translationPrefix}.postUpload.comment", [$fieldname]))
|  | 10 | #set ($docAction = $request.get('docAction'))
|  | 11 | #set ($attachmentList = $targetAttachDocument.getAttachmentList())
|  | 12 | #if ($attachmentList && $attachmentList.size() > 0)
|  | 13 | #set ($sortedAttachments = $collectiontool.sort($attachmentList, 'date:desc'))
|  | 14 | #set ($lastAttachment = $sortedAttachments.get(0))
|  | 15 | #end
|  | 16 | $response.sendRedirect($targetDocument.getURL($docAction, $escapetool.url({
|  | 17 | $fieldname: $lastAttachment.filename,
|  | 18 | 'comment': $comment,
|  | 19 | 'form_token': $request.form_token
|  | 20 | })))
|  | 21 | #stop
|  | 22 | #end
|  | 23 | {{/velocity}}
|  | 24 |
|  | 25 | {{velocity output="false"}}
|  | 26 | ##
|  | 27 | ## Macros
|  | 28 | ##
|  | 29 | #set ($attachmentPickerDocName = 'XWiki.AttachmentSelector')
|  | 30 |
|  | 31 | $xwiki.ssx.use($attachmentPickerDocName)
|  | 32 | $xwiki.jsx.use($attachmentPickerDocName)
|  | 33 |
|  | 34 | #**
|  | 35 | * Displays the attachment gallery as a list of attachment boxes, starting with special boxes for uploading a new attachment and for setting a default value.
|  | 36 | *
|  | 37 | * @param $targetDocument the document to recieve the field value being modified
|  | 38 | * @param $targetAttachDocument the document to list/save attachments to
|  | 39 | * @param $options generic picker options
|  | 40 | *#
|  | 41 | #macro (attachmentPicker_displayAttachmentGallery $targetDocument, $targetAttachDocument, $options)
|  | 42 | #set ($currentValue = $targetDocument.getValue($options.property))
|  | 43 | #if ("$!{targetAttachDocument.getAttachment($currentValue)}" == '')
|  | 44 | #set ($currentValue = "$!{options.defaultValue}")
|  | 45 | #end
|  | 46 | (% class="gallery" %)(((
|  | 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)
|  | 50 | #end
|  | 51 | #attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
|  | 52 | #set ($sortedAttachments = $collectiontool.sort($targetAttachDocument.getAttachmentList(), "${options.sortAttachmentsBy}") )
|  | 53 | #foreach ($attachment in $sortedAttachments)
|  | 54 | #set ($extension = $attachment.getFilename())
|  | 55 | #set ($extension = $extension.substring($mathtool.add($extension.lastIndexOf('.'), 1)).toLowerCase())
|  | 56 | #if ($options.filter.size() == 0 || $options.filter.contains($extension))
|  | 57 | #attachmentPicker_displayAttachmentBox($attachment $targetDocument $targetAttachDocument, $options $currentValue)
|  | 58 | #end
|  | 59 | #end
|  | 60 | )))
|  | 61 | #end
|  | 62 |
|  | 63 | #**
|  | 64 | * Displays an attachment box.
|  | 65 | *
|  | 66 | * @param $attachment the target attachment to display
|  | 67 | * @param $targetDocument the document being modified
|  | 68 | * @param $options generic picker options
|  | 69 | * @param $currentValue the currently selected file, used for determining if the box should be highlighted as the current value
|  | 70 | *#
|  | 71 | #macro (attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
|  | 72 | #if ($options.displayImage && $attachment.isImage())
|  | 73 | #set ($cssClass = 'gallery_image')
|  | 74 | #else
|  | 75 | #set ($cssClass = '')
|  | 76 | #end
|  | 77 | #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "$!{cssClass}"} $currentValue)
|  | 78 | #attachmentPicker_displayAttachmentDetails($attachment $options)
|  | 79 | #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
|  | 80 | #set ($deleteURL = $targetAttachDocument.getAttachmentURL($attachment.filename, 'delattachment', "xredirect=${returnURL}&form_token=$!{services.csrf.getToken()}") )
|  | 81 | #set ($viewURL = $targetAttachDocument.getAttachmentURL($attachment.filename) )##{'name' : 'download', 'url' : $viewURL, 'rel' : '__blank'}
|  | 82 | #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, "${options.get('classname')}_${options.get('object')}_${options.get('property')}=${attachment.filename}&form_token=$!{services.csrf.getToken()}"))
|  | 83 | #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}, {'name' : 'delete', 'url' : $deleteURL}])
|  | 84 | #end
|  | 85 |
|  | 86 | #**
|  | 87 | * Writes the wiki code used at the start of an attachment box. Outputs the attachment title bar, and opens the inner frame div.
|  | 88 | *
|  | 89 | * @param $boxOptions a map of parameters/options for the current attachment, holding, for example, the attachment name (boxOptions.value),
|  | 90 | * the title to display (boxOptions.text), optional extra CSS classnames to put on the box (boxOptions.cssClass)
|  | 91 | * @param $currentValue the currently selected file, used for determining if this attachment should be highlighted as the current value
|  | 92 | *#
|  | 93 | #macro (attachmentPicker_displayStartFrame $boxOptions $currentValue)
|  | 94 | (% class="gallery_attachmentbox $!{boxOptions.cssClass} #if ("$!{boxOptions.value}" == $currentValue) current#{end}" %)(((
|  | 95 | (% class="gallery_attachmenttitle" title="$!{boxOptions.value}" %)((($boxOptions.text)))
|  | 96 | (% class="gallery_attachmentframe" %)(((
|  | 97 | #end
|  | 98 |
|  | 99 | #**
|  | 100 | * Displays details about an attachment inside the attachment box. If the attachment is an image and the "displayImage" option is on,
|  | 101 | * then the image is displayed. Otherwise, some basic information is displayed: the version, the size, the date and the author.
|  | 102 | *
|  | 103 | * @param $attachment the target attachment to display
|  | 104 | * @param $options generic picker options
|  | 105 | *#
|  | 106 | #macro (attachmentPicker_displayAttachmentDetails $attachment $options)
|  | 107 | #if ($attachment)
|  | 108 | ## Compute the attachment reference because there's no getter.
|  | 109 | #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
|  | 110 | $attachment.filename))
|  | 111 | #set ($attachmentStringReference = $services.model.serialize($attachmentReference, 'default'))
|  | 112 | #if ($attachment.isImage() && $options.displayImage)
|  | 113 | ## We add the version to the query string in order to invalidate the cache when an image attachment is replaced.
|  | 114 | #set ($queryString = $escapetool.url({'version': $attachment.version}))
|  | 115 | [[[[image:${attachmentStringReference}||width=180 queryString="$queryString"]]>>attach:$attachmentStringReference]]
|  | 116 | #else
|  | 117 | * (% class="mime" %){{html wiki=false clean=false}}#mimetypeimg($attachment.getMimeType().toLowerCase() $attachment.getFilename().toLowerCase()){{/html}}(%%) (% class="filename" %)$attachment.getFilename()(% %)
|  | 118 | * v$attachment.getVersion() (#dynamicsize($attachment.longSize))
|  | 119 | * $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')}])
|  | 120 | * (% class="buttonwrapper" %)[[${services.localization.render("${translationPrefix}.actions.download")}>>attach:${attachmentStringReference}||title="$services.localization.render("${translationPrefix}.actions.download")" rel="__blank" class="button"]](%%)
|  | 121 | #end
|  | 122 | #end
|  | 123 | #end
|  | 124 |
|  | 125 | #**
|  | 126 | * Writes the wiki code used at the end of an attachment box. Closes the inner frame div, and outputs the attachment actions.
|  | 127 | *
|  | 128 | * @param $actions a list of maps defining action buttons, where each entry contains a subset of the following:
|  | 129 | * <dl>
|  | 130 | * <dt>name</dt>
|  | 131 | * <dd>identifies the action; the name is used as a CSS classname, and in the translation key for the display text, as "xe.attachmentSelector.actions.<name>"</dd>
|  | 132 | * <dt>url</dt>
|  | 133 | * <dd>the destination of the button</dd>
|  | 134 | * <dt>rel</dt>
|  | 135 | * <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>
|  | 136 | * </dl>
|  | 137 | *#
|  | 138 | #macro (attachmentPicker_displayEndFrame $actions)
|  | 139 | )))## attachmentframe
|  | 140 | (% class="gallery_actions" %)(((
|  | 141 | #foreach ($action in $actions)
|  | 142 | #set( $actionname = $services.localization.render("${translationPrefix}.actions.${action.name}") )
|  | 143 | [[${actionname}>>path:${action.url}||class="tool ${action.name}" title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
|  | 144 | #end
|  | 145 | )))## actions
|  | 146 | )))## attachmentbox
|  | 147 | #end
|  | 148 |
|  | 149 | #**
|  | 150 | * Displays the upload box used for adding and selecting a new attachment.
|  | 151 | *
|  | 152 | * @param $targetDocument the document with the property being modified
|  | 153 | * @param $targetAttachDocument the document to upload the attachment to
|  | 154 | * @param $options generic picker options
|  | 155 | *#
|  | 156 | #macro (attachmentPicker_displayUploadForm $targetDocument, $targetAttachDocument, $options)
|  | 157 | #attachmentPicker_displayStartFrame({
|  | 158 | 'value' : $services.localization.render("${translationPrefix}.upload.title"),
|  | 159 | 'text' : $services.localization.render("${translationPrefix}.upload.title"),
|  | 160 | 'cssClass' : 'gallery_upload'
|  | 161 | } $NULL)
|  | 162 | {{html clean="false"}}
|  | 163 | <form action="$targetAttachDocument.getURL('upload')" enctype="multipart/form-data" method="post" id="uploadAttachment" class="uploadAttachment xform">
|  | 164 | <div class="gallery_upload_input">
|  | 165 | #if (${options.rawfilter} != '')
|  | 166 | <span class="xHint">$escapetool.xml($services.localization.render("${translationPrefix}.upload.hint", [${options.rawfilter}]))</span>
|  | 167 | #end
|  | 168 | <input type="file" name="filepath" id="attachfile" class="noitems" title="$!{escapetool.xml($options.rawfilter)}"/>
|  | 169 | <input type="hidden" name="xredirect" value="$xwiki.getDocument($attachmentPickerDocName).getURL('get', "xaction=postUpload&amp;docAction=$!{escapetool.url($options.get('docAction'))}&amp;targetdocname=$!{escapetool.url($targetAttachDocument.fullName)}&amp;docname=$!{escapetool.url($targetDocument.fullName)}&amp;fieldname=$!{escapetool.url($options.get('classname'))}_$!{escapetool.url($options.get('object'))}_$!{escapetool.url($options.get('property'))}&amp;form_token=$!{services.csrf.getToken()}")" />
|  | 170 | <input type="hidden" name="docname" value="$!{escapetool.xml($targetDocument.fullName)}" />
|  | 171 | <input type="hidden" name="classname" value="$!{escapetool.xml($options.get('classname'))}" />
|  | 172 | <input type="hidden" name="object" value="$!{escapetool.xml($options.get('object'))}" />
|  | 173 | <input type="hidden" name="property" value="$!{escapetool.xml($options.get('property'))}" />
|  | 174 | <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" />
|  | 175 | </div>
|  | 176 | #if ("$!currentValue" != '' && $currentValue != $options.defaultValue)
|  | 177 | <div>
|  | 178 | <label>
|  | 179 | <input type="checkbox" name="filename" value="$!escapetool.xml($currentValue)"
|  | 180 | />$services.localization.render('attachmentSelector.replace',
|  | 181 | ["<strong>$!escapetool.xml($currentValue)</strong>"])
|  | 182 | </label>
|  | 183 | <span class="xHint">$escapetool.xml($services.localization.render('attachmentSelector.replace.hint'))</span>
|  | 184 | </div>
|  | 185 | #end
|  | 186 | #if ($xwiki.hasEditComment() && $options.versionSummary)
|  | 187 | <div>
|  | 188 | #if ($xwiki.isEditCommentFieldHidden())
|  | 189 | <input type="hidden" name="comment" value="$!escapetool.xml($request.comment)" />
|  | 190 | #else
|  | 191 | <label for="commentinput">$services.localization.render('core.comment')</label>
|  | 192 | <input type="text" name="comment" id="commentinput" value="$!escapetool.xml($request.comment)"
|  | 193 | title="$services.localization.render('core.comment.tooltip')" />
|  | 194 | #end
|  | 195 | </div>
|  | 196 | #end
|  | 197 | <div class="buttons">
|  | 198 | <span class="buttonwrapper">
|  | 199 | <input type="submit" name="action_upload" class="button " value='$services.localization.render("${translationPrefix}.upload.submit")' title='$services.localization.render("${translationPrefix}.upload.submit")'/>
|  | 200 | </span>
|  | 201 | </div>
|  | 202 | </form>
|  | 203 | {{/html}}
|  | 204 | #attachmentPicker_displayEndFrame ([])
|  | 205 | #end
|  | 206 |
|  | 207 | #**
|  | 208 | * Displays the "empty value" box, used for unsetting the field value.
|  | 209 | *
|  | 210 | * @param $targetDocument the document being modified
|  | 211 | * @param $targetAttachDocument the document that the attachments will the loaded from/saved to
|  | 212 | * @param $options generic picker options
|  | 213 | * @param $currentValue the currently selected file, used for determining if the empty box should be highlighted as the current value
|  | 214 | *#
|  | 215 | #macro (attachmentPicker_displayAttachmentGalleryEmptyValue $targetDocument, $targetAttachDocument, $options, $currentValue)
|  | 216 | #if ("$!{options.get('defaultValue')}" != '')
|  | 217 | #set ($reference = ${options.get('defaultValue')})
|  | 218 | #set ($docNameLimit = $reference.indexOf('@'))
|  | 219 | #if ($docNameLimit > 0)
|  | 220 | #set ($docName = $reference.substring(0, $docNameLimit))
|  | 221 | #else
|  | 222 | #set ($docName = $targetAttachDocument.fullName)
|  | 223 | #end
|  | 224 | #set ($attachmentName = $reference.substring($mathtool.add($docNameLimit, 1)))
|  | 225 | #set ($defaultAttachment = $xwiki.getDocument($docName).getAttachment($attachmentName))
|  | 226 | #if ($defaultAttachment.isImage())
|  | 227 | #set($dcssClass = 'gallery_image')
|  | 228 | #end
|  | 229 | #end
|  | 230 | #attachmentPicker_displayStartFrame({'cssClass' : "gallery_emptyChoice $!{dcssClass}", 'text' : $services.localization.render("${translationPrefix}.default"), 'value' : "${options.defaultValue}"} $currentValue)
|  | 231 | #attachmentPicker_displayAttachmentDetails($defaultAttachment $options)
|  | 232 | #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
|  | 233 | #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, "${options.get('classname')}_${options.get('object')}_${options.get('property')}=&form_token=$!{services.csrf.getToken()}"))
|  | 234 | #attachmentPicker_displayEndFrame ([{'name' : 'select', 'url' : $selectURL}])
|  | 235 | #end
|  | 236 | {{/velocity}}
|  | 237 |
|  | 238 | {{velocity}}
|  | 239 | #if ($request.docname)
|  | 240 | #set ($targetDocument = $xwiki.getDocument($request.docname))
|  | 241 | #if ($request.targetdocname)
|  | 242 | ## Use the target document if it exists.
|  | 243 | #set ($targetAttachDocument = $xwiki.getDocument($request.targetdocname))
|  | 244 | #else
|  | 245 | ## Otherwise, just use the current document as the target to save/load attachments
|  | 246 | #set ($targetAttachDocument = $targetDocument)
|  | 247 | #end
|  | 248 | #if ("$!{request.savemode}" == 'direct')
|  | 249 | #set($docAction = 'save')
|  | 250 | #else
|  | 251 | #set($docAction = $targetAttachDocument.getDefaultEditMode())
|  | 252 | #end
|  | 253 | #set ($filter = [])
|  | 254 | #set ($rawfilter = '')
|  | 255 | #if ("$!{request.filter}" != '')
|  | 256 | #foreach ($value in $request.filter.trim().split('\s*+[,|; ]\s*+'))
|  | 257 | #if ("$!value" != '')
|  | 258 | #set ($discard = $filter.add($value.toLowerCase()))
|  | 259 | #set ($rawfilter = "${rawfilter}, ${value}")
|  | 260 | #end
|  | 261 | #end
|  | 262 | #if ($rawfilter != '')
|  | 263 | #set ($rawfilter = $rawfilter.substring(2))
|  | 264 | #end
|  | 265 | #end
|  | 266 | #if ("$!{request.displayImage}" == 'true')
|  | 267 | #set ($displayImage = true)
|  | 268 | #else
|  | 269 | #set ($displayImage = false)
|  | 270 | #end
|  | 271 | ### Determine attachment sorting
|  | 272 | #set($sortAttachmentsBy = "$!{request.sortAttachmentsBy}")
|  | 273 | #set ($validAttachmentProperties = ['filename', 'date', 'filesize', 'author', 'version', 'mimeType'])
|  | 274 | #if($sortAttachmentsBy == '' || $validAttachmentProperties.indexOf($sortAttachmentsBy) == -1)
|  | 275 | ### Default to sorting by filename, sort not requested.
|  | 276 | #set($sortAttachmentsBy = "filename")
|  | 277 | #end
|  | 278 | ### Set attachment sorting direction
|  | 279 | #if($sortAttachmentsBy == 'date')
|  | 280 | ### Sort the date descending
|  | 281 | #set($sortAttachmentsBy = "date:desc")
|  | 282 | #else
|  | 283 | ### Sort everything else ascending
|  | 284 | #set($sortAttachmentsBy = "${sortAttachmentsBy}:asc")
|  | 285 | #end
|  | 286 | #set ($options = {
|  | 287 | 'classname' : ${request.get('classname')},
|  | 288 | 'object' : $!{numbertool.toNumber($request.object).intValue()},
|  | 289 | 'property' : ${request.property},
|  | 290 | 'displayImage' : ${displayImage},
|  | 291 | 'docAction' : ${docAction},
|  | 292 | 'defaultValue' : "$!{request.defaultValue}",
|  | 293 | 'rawfilter': "$!{rawfilter}",
|  | 294 | 'filter': ${filter},
|  | 295 | 'sortAttachmentsBy': ${sortAttachmentsBy},
|  | 296 | 'versionSummary': $request.versionSummary.equals('true')
|  | 297 | })
|  | 298 | $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
|  | 299 | #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
|  | 300 |
|  | 301 | (% class="gallery_buttons buttons" %)(((
|  | 302 | (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")>>${targetDocument}||class="button secondary" id="attachment-picker-close"]]
|  | 303 | )))
|  | 304 | #end
|  | 305 | {{/velocity}}

# Applications

# Tips

Press the x+x+x+a key combo to toggle the Advanced mode and x+x+x+h to toggle the display of hidden pages.

# Need help?

If you need help with XWiki you can contact:

- Community Support
- Professional Support

XWiki Debian 13.10.2