Änderungen von Dokument Attachments

Zuletzt geändert von xwikiadmin am 2025/05/21 09:22

Von Version 3.1
bearbeitet von xwikiadmin
am 2023/10/26 10:36
Änderungskommentar: Install extension [com.xwiki.pro:xwiki-pro-macros/1.12]
Auf Version 1.1
bearbeitet von xwikiadmin
am 2023/04/25 11:20
Änderungskommentar: Install extension [com.xwiki.pro:xwiki-pro-macros/1.7.1]

Zusammenfassung

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_attachments
23 +{{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 -CSS
1 +LESS
Name
... ... @@ -1,1 +1,0 @@
1 -Confluence Attachments Macro
XWiki.WikiMacroClass[0]
Makro-Code
... ... @@ -1,6 +1,48 @@
1 1  {{velocity output="false"}}
2 -#macro (getLiveDataSort $return)
3 - ##property
2 +#macro (filterAndSortAttachments $attachmentsFiltered $invalidSortBy $invalidSortOrder)
3 + $xwiki.ssx.use('Confluence.Macros.Attachments')
4 + $xwiki.jsx.use('Confluence.Macros.Attachments')
5 + #if ("$!{request.forceTestRights}" == "1")#template("xwikivars.vm")#end
6 + #template('attachment_macros.vm')
7 + ## Get attachments
8 + #if ("$!wikimacro.parameters.tags" != '')
9 + #set ($tags = $!wikimacro.parameters.tags.split(','))
10 + #set ($pageReferenceSet = $collectiontool.getSet())
11 + #foreach ($tag in $tags)
12 + #set ($references = $xwiki.tag.getDocumentsWithTag("$tag"))
13 + #set ($discard = $pageReferenceSet.addAll($references))
14 + #end
15 + #set ($attachments = [])
16 + #foreach ($pageReference in $pageReferenceSet)
17 + #set ($document = $xwiki.getDocument($pageReference))
18 + #set ($documentAttachments = $document.attachmentList)
19 + #set ($discard = $attachments.addAll($documentAttachments))
20 + #end
21 + #else
22 + #set ($attachments = $doc.attachmentList)
23 + #if ("$!wikimacro.parameters.page" != '')
24 + #set ($document = $xwiki.getDocument("$!wikimacro.parameters.page"))
25 + #set ($attachments = $document.attachmentList)
26 + #end
27 + #end
28 + ## Filter attachments
29 + #set ($confluencePatterns = "$!wikimacro.parameters.patterns")
30 + #if ($confluencePatterns == '')
31 + #set($attachmentsFiltered = $attachments)
32 + #else
33 + #set ($patterns = $!confluencePatterns.split(','))
34 + #set($attachmentsFiltered = [])
35 + #foreach ($attachment in $attachments)
36 + #foreach ($pattern in $patterns)
37 + #set ($matches = $attachment.filename.matches("(?i)$!pattern"))
38 + #if ($matches)
39 + #set ($discard = $attachmentsFiltered.add($attachment))
40 + #break
41 + #end
42 + #end
43 + #end
44 + #end
45 + ## Sort attachments
4 4   #set ($confluenceSortBy = "$!wikimacro.parameters.sortBy")
5 5   #set ($invalidSortBy = false)
6 6   #if ($confluenceSortBy == 'date')
... ... @@ -14,7 +14,6 @@
14 14   #else
15 15   #set ($invalidSortBy = true)
16 16   #end
17 - ## order
18 18   #set ($confluenceSortOrder = "$!wikimacro.parameters.sortOrder")
19 19   #set ($invalidSortOrder = false)
20 20   #set ($reverseSortOrderProperties = ['filesize', 'date'])
... ... @@ -31,178 +31,101 @@
31 31   #set ($sortOrder = 'desc')
32 32   #end
33 33   #else
34 - #set ($invalidSortOrder = true)
75 + #set ($invalidSortOrder = false)
35 35   #end
36 - ## return
37 - #if ($invalidSortBy || $invalidSortOrder)
38 - #setVariable("$return", {})
39 - #else
40 - #setVariable("$return", "$sortBy:$sortOrder")
41 - #end
77 + #set ($attachmentsFiltered = $collectiontool.sort($attachmentsFiltered, "$sortBy:$sortOrder"))
42 42  #end
43 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">&times;</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>
100 - #end
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'))
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
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'))
155 - #else
156 - #set ($discard = $sourceParams.put('resultPage', 'Confluence.Macros.AttachmentsJSON'))
157 - #end
158 - #getLiveDataSort($liveDataSort)
80 +#macro (executeMacro)
81 + #filterAndSortAttachments($attachmentsFiltered $invalidSortBy $invalidSortOrder)
159 159   #if ($invalidSortBy)
160 - {{warning}}
161 - Attachment macro: sortBy parameter must be one of 'date', 'size', or 'name'
162 - {{/warning}}
83 + {{error}}
84 + Attachment macro error: sortBy parameter must be one of 'date', 'size', or 'name'
85 + {{/error}}
86 + #break
163 163   #end
164 164   #if ($invalidSortOrder)
165 - {{warning}}
166 - Attachment macro: sortOrder parameter must be one of 'ascending' or 'descending'
167 - {{/warning}}
89 + {{error}}
90 + Attachment macro error: sortOrder parameter must be one of 'ascending' or 'descending'
91 + {{/error}}
92 + #break
168 168   #end
94 + ## Display attachments
95 + {{html clean="false"}}
96 + <div class="confluence-attachment-macro">
97 + #if ($attachmentsFiltered.size() > 0)
98 + #displayAttachments($attachmentsFiltered)
99 + #deleteAttachmentModal()
100 + #else
101 + <p class="noitems">
102 + $!escapetool.xml($services.localization.render('core.viewers.attachments.noAttachments'))
103 + </p>
104 + #end
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}}
106 + ## Allow upload
107 + #set ($upload = "$!wikimacro.parameters.upload")
108 + #if ($upload == 'true' && ($hasEdit || $hasAdmin) && $xcontext.action == 'view')
109 + <form
110 + id="AddAttachment"
111 + action="$doc.getURL("upload")"
112 + method="post"
113 + enctype="multipart/form-data"
114 + >
115 + <div>
116 + ## CSRF prevention
117 + <input
118 + type="hidden"
119 + name="form_token"
120 + value="$!{services.csrf.getToken()}"
121 + />
178 178  
179 - {{html clean="false"}}
180 - #uploadFileForm($liveDataId)
181 - #deleteConfluenceAttachmentModal()
182 - {{/html}}
183 -#end
123 + <fieldset id="attachform">
124 + <legend>
125 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.title'))
126 + </legend>
184 184  
128 + <div class="fileupload-field">
129 + <label
130 + class="hidden"
131 + for="xwikiuploadfile"
132 + >
133 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.file'))
134 + </label>
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
136 + <input
137 + id="xwikiuploadfile"
138 + class="uploadFileInput noitems"
139 + type="file"
140 + name="filepath"
141 + size="40"
142 + data-max-file-size="$!escapetool.xml($xwiki.getSpacePreference('upload_maxsize'))"
143 + />
144 + </div>
199 199  
200 - {{html clean="false" wiki="true"}}
201 - <div class='confluenceAttachmentsMacro'>
202 - #showConfluenceAttachments($document)
203 - </div>
204 - {{/html}}
146 + <div>
147 + <span class="buttonwrapper">
148 + <input
149 + class="button btn btn-primary"
150 + type="submit"
151 + value="$!escapetool.xml($services.localization.render('core.viewers.attachments.upload.submit'))"
152 + />
153 + </span>
205 205  
155 + <span class="buttonwrapper">
156 + <a
157 + class="cancel secondary button btn btn-primary"
158 + href="$doc.getURL()"
159 + >
160 + $!escapetool.xml($services.localization.render('core.viewers.attachments.upload.cancel'))
161 + </a>
162 + </span>
163 + </div>
164 + </fieldset>
165 + </div>
166 + </form>
167 + #end
168 + </div> ## .confluence-attachment-macro
169 + {{/html}}
206 206  #end
207 207  {{/velocity}}
208 208  
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