Änderungen von Dokument Attachments
Zuletzt geändert von xwikiadmin am 2026/03/05 08:08
Von Version 4.1
bearbeitet von xwikiadmin
am 2023/10/26 09:48
am 2023/10/26 09:48
Änderungskommentar:
Install extension [com.xwiki.pro:xwiki-pro-macros/1.12]
Auf Version 1.1
bearbeitet von xwikiadmin
am 2023/03/07 16:26
am 2023/03/07 16:26
Änderungskommentar:
Install extension [com.xwiki.pro:xwiki-pro-macros/1.7]
Zusammenfassung
-
Seiteneigenschaften (1 geändert, 0 hinzugefügt, 0 gelöscht)
-
Objekte (3 geändert, 0 hinzugefügt, 1 gelöscht)
Details
- Seiteneigenschaften
-
- Inhalt
-
... ... @@ -10,17 +10,17 @@ 10 10 = Parameters = 11 11 12 12 |=Parameter|=Description|=Required|=Default 13 -|**patterns**|Comma-separated list of regular expressions, used to filter attachments by name.|No| 13 +|**patterns**|Comma-separated list of regular expressions, used to filter attachments by name.|No| 14 14 |**sortBy**|Sort attachments by {{{ date }}}, {{{ size }}} or {{{ name }}}|No|{{{ date }}} 15 15 |**sortOrder**|Sort attachments in {{{ ascending }}} or {{{ descending }}} order|No|{{{ ascending }}} 16 16 |**upload**|Allow users to attach new files|No|{{{ true }}} 17 -|**page**|Pages containing the attachments to display. Current page if empty.|No| 17 +|**page**|Pages containing the attachments to display. Current page if empty.|No| 18 18 19 19 = Example Usage = 20 20 21 21 22 22 {{code}} 23 -{{ confluence_attachments23 +{{attachments 24 24 patterns=".*png" 25 25 sortBy="name" 26 26 /}}
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,95 +1,8 @@ 1 -define('xwiki-confluence-attachments-messages', { 2 - prefix: 'core.viewers.attachments.delete.', 3 - keys: [ 4 - 'inProgress', 5 - 'done', 6 - 'error' 7 - ] 8 -}); 9 - 10 -require(['jquery', 'xwiki-l10n!xwiki-confluence-attachments-messages'], function($, l10n) { 11 - var enhanceUploadInputs = function(liveDataElems) { 12 - $.each(liveDataElems.find('input[type=file]'), function() { 13 - // Since the attachments liveData is refreshed on file upload, there is no need for a response container. 14 - new XWiki.FileUploader(this, { 15 - 'progressAutohide': true, 16 - 'responseContainer' : document.createElement('div'), 17 - 'maxFilesize' : parseInt(this.readAttribute('data-max-file-size')) 18 - }); 19 - }) 20 - }; 21 - 22 - $(function() { 23 - enhanceUploadInputs($('.confluenceAttachmentsMacro')); 24 - }) 25 - 26 - $(document).on('xwiki:dom:updated', function(e, data) { 27 - let liveDataElems = $(data.elements).find('.confluenceAttachmentsMacro'); 28 - enhanceUploadInputs(liveDataElems); 29 - }); 30 - 31 - $(document).on('xwiki:html5upload:done', function(e) { 32 - if ($(e.target).prop('id').startsWith('confluenceAttachments')) { 33 - // Select the livedata above the upload form. 34 - const uploadForm = $(e.target).closest('form'); 35 - // The 'xwiki-livedata' CSS class is present only before XWiki version 14.4. 36 - let associatedLivedata = uploadForm.prevAll('.liveData, .xwiki-livedata').first(); 37 - // We do not have access to a liveData object before XWiki 14.4. 38 - if (associatedLivedata.data('liveData') === undefined) { 39 - location.reload(); 40 - } else { 41 - associatedLivedata.data('liveData').updateEntries(); 42 - } 1 +require(['jquery', 'xwiki-events-bridge'], function ($) { 2 + $('#xwikiuploadfile').on('xwiki:html5upload:message', function (event, data) { 3 + if (data.content === 'UPLOAD_FINISHED' && data.type === 'done') { 4 + location.reload(); 43 43 } 44 44 }); 45 - 46 - // 47 - // The delete action methods are similar to the ones from the attachments tab, but couldn't be reused. The problem is 48 - // that when the tab is not opened we cannot just load the attachments.js file, since it expects some elements to be 49 - // already loaded and it produces errors. 50 - // 51 - 52 - /** 53 - * Open the delete confirmation modal on liveData attachment delete button. 54 - */ 55 - $(document).on('click', '.confluenceAttachmentsMacro .attachmentActions .actiondelete', function(e) { 56 - e.preventDefault(); 57 - // The 'xwiki-livedata' CSS class is present only before XWiki version 14.4. 58 - let liveData = $(e.currentTarget).closest('.liveData, .xwiki-livedata'); 59 - var modal = liveData.nextAll('.deleteConfluenceAttachment'); 60 - modal.data('relatedTarget', e.currentTarget); 61 - modal.modal('show'); 62 - }); 63 - 64 - /** 65 - * On delete confirmation, delete attachment and refresh liveData. 66 - */ 67 - $(document).on('click', '.confluenceAttachmentsMacro .deleteConfluenceAttachment input.btn-danger', function(e) { 68 - e.preventDefault(); 69 - var modal = $(e.currentTarget).closest('.deleteConfluenceAttachment'); 70 - var button = $(modal.data('relatedTarget')); 71 - // The 'xwiki-livedata' CSS class is present only before XWiki version 14.4. 72 - let liveData = button.closest('.liveData, .xwiki-livedata'); 73 - var notification; 74 - 75 - $.ajax({ 76 - url : button.prop('href'), 77 - beforeSend : function() { 78 - notification = new XWiki.widgets.Notification(l10n['inProgress'], 'inprogress'); 79 - }, 80 - success : function() { 81 - // We do not have access to a liveData object before XWiki 14.4. 82 - if (liveData.data('liveData') !== undefined) { 83 - liveData.data('liveData').updateEntries(); 84 - notification.replace(new XWiki.widgets.Notification(l10n['done'], 'done')); 85 - } else { 86 - location.reload(); 87 - } 88 - }, 89 - error: function() { 90 - notification.replace(new XWiki.widgets.Notification(l10n['failed'], 'error')); 91 - } 92 - }); 93 - }); 94 94 }); 95 95 - Name
-
... ... @@ -1,1 +1,0 @@ 1 -Confluence Attachments Macro
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -1,15 +1,15 @@ 1 -.confluenceAttachmentsMacro legend { 2 - font-size: 1em; 1 +.confluence-attachment-macro { 2 + .upload-response { 3 + display: none; 4 + } 5 + 6 + #AddAttachment { 7 + margin-top: 15px; 8 + 9 + #attachform { 10 + .buttonwrapper { 11 + display: none; 12 + } 13 + } 14 + } 3 3 } 4 - /* These should be deleted after upgrading to a XWiki parent >= 14.6. */ 5 -.attachmentMimeType { 6 - color: $theme.textSecondaryColor; 7 - font-size: 32px; 8 - height: 32px; 9 - line-height: 32px; 10 - text-align: center; 11 -} 12 -.attachmentMimeType img { 13 - max-height: 32px; 14 - max-width: 48px; 15 -} - Content Type
-
... ... @@ -1,1 +1,1 @@ 1 - CSS1 +LESS - Name
-
... ... @@ -1,1 +1,0 @@ 1 -Confluence Attachments Macro
- XWiki.WikiMacroClass[0]
-
- Makro-Code
-
... ... @@ -1,223 +1,169 @@ 1 1 {{velocity output="false"}} 2 -#macro (getLiveDataSort $return) 3 - ##property 4 - #set ($confluenceSortBy = "$!wikimacro.parameters.sortBy") 5 - #set ($invalidSortBy = false) 6 - #if ($confluenceSortBy == 'date') 7 - #set ($sortBy = 'date') 8 - #elseif ($confluenceSortBy == 'size') 9 - #set ($sortBy = 'filesize') 10 - #elseif ($confluenceSortBy == 'name') 11 - #set ($sortBy = 'filename') 12 - #elseif ($confluenceSortBy == 'creation date') 13 - #set ($sortBy = 'date') 14 - #else 15 - #set ($invalidSortBy = true) 2 +$xwiki.ssx.use('Confluence.Macros.Attachments') 3 +$xwiki.jsx.use('Confluence.Macros.Attachments') 4 +#if ("$!{request.forceTestRights}" == "1")#template("xwikivars.vm")#end 5 +#template('attachment_macros.vm') 6 +## Get attachments 7 +#if ("$!wikimacro.parameters.tags" != '') 8 + #set ($tags = $!wikimacro.parameters.tags.split(',')) 9 + #set ($pageReferenceSet = $collectiontool.getSet()) 10 + #foreach ($tag in $tags) 11 + #set ($references = $xwiki.tag.getDocumentsWithTag("$tag")) 12 + #set ($discard = $pageReferenceSet.addAll($references)) 16 16 #end 17 - ## order 18 - #set ($confluenceSortOrder = "$!wikimacro.parameters.sortOrder") 19 - #set ($invalidSortOrder = false) 20 - #set ($reverseSortOrderProperties = ['filesize', 'date']) 21 - #if ($confluenceSortOrder == 'ascending') 22 - #if ($reverseSortOrderProperties.contains($sortBy)) 23 - #set ($sortOrder = 'desc') 24 - #else 25 - #set ($sortOrder = 'asc') 26 - #end 27 - #elseif ($confluenceSortOrder == 'descending') 28 - #if ($reverseSortOrderProperties.contains($sortBy)) 29 - #set ($sortOrder = 'asc') 30 - #else 31 - #set ($sortOrder = 'desc') 32 - #end 33 - #else 34 - #set ($invalidSortOrder = true) 14 + #set ($attachments = []) 15 + #foreach ($pageReference in $pageReferenceSet) 16 + #set ($document = $xwiki.getDocument($pageReference)) 17 + #set ($documentAttachments = $document.attachmentList) 18 + #set ($discard = $attachments.addAll($documentAttachments)) 35 35 #end 36 - ## return37 - # if($invalidSortBy||$invalidSortOrder)38 - #setVariable("$return",{})39 - #e lse40 - #set Variable("$return","$sortBy:$sortOrder")20 +#else 21 + #set ($attachments = $doc.attachmentList) 22 + #if ("$!wikimacro.parameters.page" != '') 23 + #set ($document = $xwiki.getDocument("$!wikimacro.parameters.page")) 24 + #set ($attachments = $document.attachmentList) 41 41 #end 42 42 #end 43 - 44 -#macro (deleteConfluenceAttachmentModal) 45 - ## Copied from the attachments tab code. The original macro cannot be used, since it will interfere with some js 46 - ## specific to attachments tab. Precisely, if the attachments tab is already opened, everything is working correctly. 47 - ## If it is not opened, we need to load the attachments.js code anyway, to use it's listeners, but there are parts 48 - ## that rightfully assume that some elements are present on the page and errors will occur. 49 - <div class="modal fade deleteConfluenceAttachment" tabindex="-1" role="dialog"> 50 - <div class="modal-dialog"> 51 - <div class="modal-content"> 52 - <div class="modal-header"> 53 - <button type="button" class="close" data-dismiss="modal">×</button> 54 - <div class="modal-title">$services.localization.render('core.viewers.attachments.delete')</div> 55 - </div> 56 - <div class="modal-body"> 57 - <div>$services.localization.render('core.viewers.attachments.delete.confirm')</div> 58 - </div> 59 - <div class="modal-footer"> 60 - <input type="button" class="btn btn-danger" data-dismiss="modal" 61 - value="$escapetool.xml($services.localization.render('core.viewers.attachments.delete'))"> 62 - <input type="button" class="btn btn-default" data-dismiss="modal" 63 - value="$escapetool.xml($services.localization.render('cancel'))"> 64 - </div> 65 - </div> 66 - </div> 67 - </div> 68 -#end 69 - 70 -#set ($confluenceAttachmentMacroIndex = -1) 71 -## Code taken and adapted 72 -#macro (showConfluenceAttachments $document) 73 - #template('display_macros.vm') 74 - #set ($confluenceAttachmentMacroIndex = $confluenceAttachmentMacroIndex + 1) 75 - #set ($confluenceAttachmentMacroId = "confluenceAttachments$confluenceAttachmentMacroIndex") 76 - ## 77 - #showConfluenceAttachmentsLiveData($document $confluenceAttachmentMacroId) 78 -#end 79 - 80 -#macro (uploadFileForm $liveDataId) 81 - #set ($upload = "$!wikimacro.parameters.upload") 82 - #if ($upload == 'true' && ($hasEdit || $hasAdmin) && $xcontext.action == 'view') 83 - <form action="$attachmentsDoc.getURL("upload")" enctype="multipart/form-data" method="post"> 84 - <div> 85 - ## CSRF prevention 86 - <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" /> 87 - <fieldset> 88 - <legend>$services.localization.render('promacros.attachments.upload.title')</legend> 89 - <div> 90 - #set ($inputID = "${liveDataId}-uploadFile") 91 - <label class="sr-only" for="${inputID}"> 92 - $services.localization.render('core.viewers.attachments.upload.file') 93 - </label> 94 - <input id="${inputID}" type="file" name="filepath" size="40" class="noitems" 95 - data-max-file-size="$!escapetool.xml($xwiki.getSpacePreference('upload_maxsize'))"/> 96 - </div> 97 - </fieldset> 98 - </div> 99 - </form> 27 +## Filter attachments 28 +#set ($confluencePatterns = "$!wikimacro.parameters.patterns") 29 +#if ($confluencePatterns == '') 30 + #set($attachmentsFiltered = $attachments) 31 +#else 32 + #set ($patterns = $!confluencePatterns.split(',')) 33 + #set($attachmentsFiltered = []) 34 + #foreach ($attachment in $attachments) 35 + #foreach ($pattern in $patterns) 36 + #set ($matches = $attachment.filename.matches("(?i)$!pattern")) 37 + #if ($matches) 38 + #set ($discard = $attachmentsFiltered.add($attachment)) 39 + #break 40 + #end 41 + #end 100 100 #end 101 101 #end 102 - 103 -#macro (supportsAttachJSON $supportsAttachJSON) 104 - ## The attachments.json code uses macros from attachment_macro.vm, so the existence of the attachments livedata macro 105 - ## is an indicator that the template exists and is adapted for livedata. 106 - #template('attachment_macros.vm') 107 - #set ($macroResult = "#showAttachmentsLiveData($doc 'id')") 108 - #set ($supportsAttachJSON = $macroResult.startsWith('{{liveData')) 44 +## Sort attachments 45 +#set ($confluenceSortBy = "$!wikimacro.parameters.sortBy") 46 +#set ($invalidSortBy = false) 47 +#if ($confluenceSortBy == 'date') 48 + #set ($sortBy = 'date') 49 +#elseif ($confluenceSortBy == 'size') 50 + #set ($sortBy = 'filesize') 51 +#elseif ($confluenceSortBy == 'name') 52 + #set ($sortBy = 'filename') 53 +#elseif ($confluenceSortBy == 'creation date') 54 + #set ($sortBy = 'date') 55 +#else 56 + #set ($invalidSortBy = true) 109 109 #end 110 - 111 -## Display a liveData with attachments from the specified document. 112 -#macro (showConfluenceAttachmentsLiveData $attachmentsDoc $liveDataId) 113 - #set ($liveDataConfig = { 114 - 'meta': { 115 - 'propertyDescriptors': [ 116 - { 'id': 'mimeType', 'displayer': 'html'}, 117 - { 'id': 'filename', 'displayer': 'html' }, 118 - { 'id': 'filesize', 'displayer': 'html' }, 119 - { 'id': 'date', 'filter': 'date'}, 120 - { 'id': 'author', 'displayer': 'html' }, 121 - { 'id': 'actions', 'displayer': 'html' } 122 - ], 123 - 'entryDescriptor': { 124 - 'idProperty': 'id' 125 - } 126 - } 127 - }) 128 - 129 - #if ("$!wikimacro.parameters.patterns" != '') 130 - #set ($liveDataConfig.query = {}) 131 - #set ($liveDataConfig.query.filters = [ 132 - { 133 - "property": "filename", 134 - "matchAll": true, 135 - "constraints": [] 136 - } 137 - ]) 138 - #set ($filters = $stringtool.split($wikimacro.parameters.patterns, ',')) 139 - #foreach ($filter in $filters) 140 - #set ($discard = $liveDataConfig.query.filters[0].constraints.add( 141 - { "operator": "contains", "value": "$!filter.trim()" } 142 - )) 143 - #end 58 +#set ($confluenceSortOrder = "$!wikimacro.parameters.sortOrder") 59 +#set ($invalidSortOrder = false) 60 +#set ($reverseSortOrderProperties = ['filesize', 'date']) 61 +#if ($confluenceSortOrder == 'ascending') 62 + #if ($reverseSortOrderProperties.contains($sortBy)) 63 + #set ($sortOrder = 'desc') 64 + #else 65 + #set ($sortOrder = 'asc') 144 144 #end 145 - #set ($sourceParams = { 146 - 'translationPrefix': 'core.viewers.attachments.livetable.', 147 - 'className': 'XWiki.AllAttachments', 148 - "\$doc": "$attachmentsDoc" 149 - }) 150 - ## Since the correct attachmentsjson.vm was added in XWiki 14.8, we use a copy of its code for backwards compatibility. 151 - #supportsAttachJSON($supportsAttachJSON) 152 - #if ($supportsAttachJSON) 153 - #set ($discard = $sourceParams.put('template', 'xpart.vm')) 154 - #set ($discard = $sourceParams.put('vm', 'attachmentsjson.vm')) 67 +#elseif ($confluenceSortOrder == 'descending') 68 + #if ($reverseSortOrderProperties.contains($sortBy)) 69 + #set ($sortOrder = 'asc') 155 155 #else 156 - #set ($ discard = $sourceParams.put('resultPage','Confluence.Macros.AttachmentsJSON'))71 + #set ($sortOrder = 'desc') 157 157 #end 158 - #getLiveDataSort($liveDataSort) 159 - #if ($invalidSortBy) 160 - {{warning}} 161 - Attachment macro: sortBy parameter must be one of 'date', 'size', or 'name' 162 - {{/warning}} 163 - #end 164 - #if ($invalidSortOrder) 165 - {{warning}} 166 - Attachment macro: sortOrder parameter must be one of 'ascending' or 'descending' 167 - {{/warning}} 168 - #end 73 +#else 74 + #set ($invalidSortOrder = false) 75 +#end 76 +#set ($attachmentsFiltered = $collectiontool.sort($attachmentsFiltered, "$sortBy:$sortOrder")) 77 +{{/velocity}} 169 169 170 - {{liveData 171 - id="$liveDataId" 172 - properties="mimeType,filename,filesize,date,author,actions" 173 - source='liveTable' 174 - sourceParameters="$escapetool.url($sourceParams)" 175 - sort="$liveDataSort" 176 - limit=5 177 - }}$jsontool.serialize($liveDataConfig){{/liveData}} 178 - 179 - {{html clean="false"}} 180 - #uploadFileForm($liveDataId) 181 - #deleteConfluenceAttachmentModal() 182 - {{/html}} 79 +{{velocity}} 80 +#if ($invalidSortBy) 81 + {{error}} 82 + Attachment macro error: sortBy parameter must be one of 'date', 'size', or 'name' 83 + {{/error}} 84 + #break 183 183 #end 86 +#if ($invalidSortOrder) 87 + {{error}} 88 + Attachment macro error: sortOrder parameter must be one of 'ascending' or 'descending' 89 + {{/error}} 90 + #break 91 +#end 92 +## Display attachments 93 +{{html clean="false"}} 94 + <div class="confluence-attachment-macro"> 95 + #if ($attachmentsFiltered.size() > 0) 96 + #displayAttachments($attachmentsFiltered) 97 + #deleteAttachmentModal() 98 + #else 99 + <p class="noitems"> 100 + $!escapetool.xml($services.localization.render('core.viewers.attachments.noAttachments')) 101 + </p> 102 + #end 184 184 104 + ## Allow upload 105 + #set ($upload = "$!wikimacro.parameters.upload") 106 + #if ($upload == 'true' && ($hasEdit || $hasAdmin) && $xcontext.action == 'view') 107 + <form 108 + id="AddAttachment" 109 + action="$doc.getURL("upload")" 110 + method="post" 111 + enctype="multipart/form-data" 112 + > 113 + <div> 114 + ## CSRF prevention 115 + <input 116 + type="hidden" 117 + name="form_token" 118 + value="$!{services.csrf.getToken()}" 119 + /> 185 185 186 -#macro (executeMacro) 187 - #set ($discard = $xwiki.ssfx.use('js/xwiki/viewers/attachments.css', true)) 188 - #set ($discard = $xwiki.ssfx.use('uicomponents/widgets/upload.css', true)) 189 - #set ($discard = $xwiki.jsfx.use('uicomponents/widgets/upload.js', { 190 - 'forceSkinAction': true, 191 - 'language': $xcontext.locale 192 - })) 193 - #set ($discard = $xwiki.jsx.use("Confluence.Macros.Attachments")) 194 - #set ($discard = $xwiki.ssx.use("Confluence.Macros.Attachments")) 195 - #set ($document = $doc) 196 - #if ("$!wikimacro.parameters.page" != '') 197 - #set ($document = $xwiki.getDocument("$!wikimacro.parameters.page")) 198 - #end 121 + <fieldset id="attachform"> 122 + <legend> 123 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.title')) 124 + </legend> 199 199 200 - {{html clean="false" wiki="true"}} 201 - <div class='confluenceAttachmentsMacro'> 202 - #showConfluenceAttachments($document) 203 - </div> 204 - {{/html}} 126 + <div class="fileupload-field"> 127 + <label 128 + class="hidden" 129 + for="xwikiuploadfile" 130 + > 131 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.file')) 132 + </label> 205 205 206 -#end 207 -{{/velocity}} 134 + <input 135 + id="xwikiuploadfile" 136 + class="uploadFileInput noitems" 137 + type="file" 138 + name="filepath" 139 + size="40" 140 + data-max-file-size="$!escapetool.xml($xwiki.getSpacePreference('upload_maxsize'))" 141 + /> 142 + </div> 208 208 209 -{{include reference="Licenses.Code.VelocityMacros"/}} 144 + <div> 145 + <span class="buttonwrapper"> 146 + <input 147 + class="button btn btn-primary" 148 + type="submit" 149 + value="$!escapetool.xml($services.localization.render('core.viewers.attachments.upload.submit'))" 150 + /> 151 + </span> 210 210 211 -{{velocity}} 212 -## We need to check if there is a valid license because the macro is registered even if the user doesn't have view right 213 -## on the macro definition page. See XWIKI-14828: Rendering macros defined in wiki pages are available to users that 214 -## don't have view right on those pages. 215 -#if ($services.licensing.licensor.hasLicensureForEntity($xcontext.macro.doc.documentReference)) 216 - #executeMacro 217 -#else 218 - {{error}} 219 - #getMissingLicenseMessage('proMacros.extension.name') 220 - {{/error}} 221 -#end 153 + <span class="buttonwrapper"> 154 + <a 155 + class="cancel secondary button btn btn-primary" 156 + href="$doc.getURL()" 157 + > 158 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.cancel')) 159 + </a> 160 + </span> 161 + </div> 162 + </fieldset> 163 + </div> 164 + </form> 165 + #end 166 + </div> ## .confluence-attachment-macro 167 +{{/html}} 222 222 {{/velocity}} 223 223 - Standardkategorie
-
... ... @@ -1,0 +1,1 @@ 1 +confluence
- XWiki.WikiMacroParameterClass[9]
-
- Parameter-Vorgabe
-
... ... @@ -1,1 +1,0 @@ 1 -true - Parameter-Beschreibung
-
... ... @@ -1,1 +1,0 @@ 1 -Display an option for uploading files to the selected page. - Parameter verpflichtend
-
... ... @@ -1,1 +1,0 @@ 1 -Nein - Parameter-Name
-
... ... @@ -1,1 +1,0 @@ 1 -upload - Parameter-Typ
-
... ... @@ -1,1 +1,0 @@ 1 -java.lang.Boolean