Changes for page Attachments

Last modified by teamwire005 on 2025/05/06 07:37

From version 3.1
edited by teamwire004
on 2024/01/16 09:32
Change comment: Install extension [org.xwiki.platform:xwiki-platform-attachment-ui/14.10.13]
To version 2.1
edited by teamwire-admin
on 2024/01/16 09:29
Change comment: Migrated property [defaultCategories] from class [XWiki.WikiMacroClass]

Summary

Details

Page properties
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.teamwire004
1 +XWiki.teamwire-admin
Content
... ... @@ -45,7 +45,9 @@
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)
48 + #if ($xwiki.hasAccessLevel('edit',$xcontext.user,${targetAttachDocument.fullName}))
49 + #attachmentPicker_displayUploadForm($targetDocument, $targetAttachDocument, $options)
50 + #end
49 49   #attachmentPicker_displayAttachmentGalleryEmptyValue($targetDocument, $targetAttachDocument, $options, $currentValue)
50 50   #set ($sortedAttachments = $sorttool.sort($targetAttachDocument.getAttachmentList(), "${options.sortAttachmentsBy}") )
51 51   #foreach ($attachment in $sortedAttachments)
... ... @@ -67,46 +67,18 @@
67 67   * @param $currentValue the currently selected file, used for determining if the box should be highlighted as the current value
68 68   *#
69 69  #macro (attachmentPicker_displayAttachmentBox $attachment $targetDocument $targetAttachDocument, $options $currentValue)
70 - #set ($hasTemporaryAttachment = "$!services.temporaryAttachments" != '')
71 - #set ($canEdit = $xwiki.hasAccessLevel('edit', $xcontext.user, ${targetAttachDocument.fullName}))
72 - #set ($isTemporaryAttachment = false)
73 - #if(!$hasTemporaryAttachment)
74 - #set ($canDeleteAttachment = $canEdit)
72 + #if ($options.displayImage && $attachment.isImage())
73 + #set ($cssClass = 'gallery_image')
75 75   #else
76 - #set ($isTemporaryAttachment = $services.temporaryAttachments.temporaryAttachmentExists($attachment))
77 - ## TODO: Update once it is made possible to delete temporary attachments (see XWIKI-20225).
78 - #set ($canDeleteAttachment = !$isTemporaryAttachment && $canEdit)
75 + #set ($cssClass = '')
79 79   #end
80 - #set ($cssClasses = [])
81 - #if ($options.displayImage && $attachment.isImage())
82 - #set ($discard = $cssClasses.add('gallery_image'))
83 - #end
84 - #if ($isTemporaryAttachment)
85 - #set ($discard = $cssClasses.add('temporary_attachment'))
86 - #end
87 - #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "${stringtool.join($cssClasses, ' ')}"} $currentValue)
77 + #attachmentPicker_displayStartFrame({'value' : $attachment.filename, 'text' : $attachment.filename, 'cssClass' : "$!{cssClass}"} $currentValue)
88 88   #attachmentPicker_displayAttachmentDetails($attachment $options)
89 89   #set ($returnURL = $escapetool.url($doc.getURL('view', $request.queryString)))
90 90   #set ($deleteURL = $targetAttachDocument.getAttachmentURL($attachment.filename, 'delattachment', "xredirect=${returnURL}&form_token=$!{services.csrf.getToken()}") )
91 91   #set ($viewURL = $targetAttachDocument.getAttachmentURL($attachment.filename) )##{'name' : 'download', 'url' : $viewURL, 'rel' : '__blank'}
92 - #set ($selectURL = $targetDocument.getURL(${options.get('docAction')}, $escapetool.url({
93 - "${options.get('classname')}_${options.get('object')}_${options.get('property')}": ${attachment.filename},
94 - 'form_token': $!{services.csrf.getToken()}
95 - })))
96 - ## Delete action is only proposed for users with the edit right on the document.
97 - ## If the temporary attachment is available, the delete action is only allowed for non-temporary attachments.
98 - #set ($attachmentActions = [{'name' : 'select', 'url' : $selectURL}])
99 - #if($canDeleteAttachment)
100 - #set ($discard = $attachmentActions.add({'name' : 'delete', 'url' : $deleteURL}))
101 - #end
102 - #define($additionalContent)
103 - #if ($isTemporaryAttachment)
104 - #set ($titleMessage = $services.localization.render('attachment.attachmentSelector.attachmentBox.temporaryAttachmentTitle'))
105 - #set ($titleMessage = $services.rendering.escape($titleMessage, 'xwiki/2.1'))
106 - (% title="$titleMessage" %)$services.icon.render('clock')(%%)
107 - #end
108 - #end
109 - #attachmentPicker_displayEndFrame ($attachmentActions $additionalContent)
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}])
110 110  #end
111 111  
112 112  #**
... ... @@ -118,9 +118,7 @@
118 118   *#
119 119  #macro (attachmentPicker_displayStartFrame $boxOptions $currentValue)
120 120   (% class="gallery_attachmentbox $!{boxOptions.cssClass} #if ("$!{boxOptions.value}" == $currentValue) current#{end}" %)(((
121 - (% class="gallery_attachmenttitle" title="$services.rendering.escape($!{boxOptions.value}, 'xwiki/2.1')" %)(((
122 - $services.rendering.escape($boxOptions.text, 'xwiki/2.1')
123 - )))
95 + (% class="gallery_attachmenttitle" title="$!{boxOptions.value}" %)((($boxOptions.text)))
124 124   (% class="gallery_attachmentframe" %)(((
125 125  #end
126 126  
... ... @@ -136,13 +136,13 @@
136 136   ## Compute the attachment reference because there's no getter.
137 137   #set ($attachmentReference = $services.model.createAttachmentReference($attachment.document.documentReference,
138 138   $attachment.filename))
139 - #set ($attachmentStringReference = $services.rendering.escape($services.model.serialize($attachmentReference, 'default'), 'xwiki/2.1'))
111 + #set ($attachmentStringReference = $services.model.serialize($attachmentReference, 'default'))
140 140   #if ($attachment.isImage() && $options.displayImage)
141 141   ## We add the version to the query string in order to invalidate the cache when an image attachment is replaced.
142 142   #set ($queryString = $escapetool.url({'version': $attachment.version}))
143 143   [[[[image:$attachmentStringReference||width=180 queryString="$queryString"]]>>attach:$attachmentStringReference]]
144 144   #else
145 - * (% class="mime" %){{html wiki=false clean=false}}#mimetypeimg($attachment.getMimeType().toLowerCase() $attachment.getFilename().toLowerCase()){{/html}}(%%) (% class="filename" %)$services.rendering.escape($attachment.getFilename(), 'xwiki/2.1')(% %)
117 + * (% class="mime" %){{html wiki=false clean=false}}#mimetypeimg($attachment.getMimeType().toLowerCase() $attachment.getFilename().toLowerCase()){{/html}}(%%) (% class="filename" %)$attachment.getFilename()(% %)
146 146   * v$attachment.getVersion() (#dynamicsize($attachment.longSize))
147 147   * $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')}])
148 148   * (% class="buttonwrapper" %)[[${services.localization.render("${translationPrefix}.actions.download")}>>attach:$attachmentStringReference||title="$services.localization.render("${translationPrefix}.actions.download")" rel="__blank" class="button"]](%%)
... ... @@ -162,9 +162,8 @@
162 162   * <dt>rel</dt>
163 163   * <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>
164 164   * </dl>
165 - * @param $additionalContent optional additional content that does not follow the structure of the actions
166 166   *#
167 -#macro (attachmentPicker_displayEndFrame $actions $additionalContent)
138 +#macro (attachmentPicker_displayEndFrame $actions)
168 168   )))## attachmentframe
169 169   (% class="gallery_actions" %)(((
170 170   #foreach ($action in $actions)
... ... @@ -171,7 +171,6 @@
171 171   #set( $actionname = $services.localization.render("${translationPrefix}.actions.${action.name}") )
172 172   [[${actionname}>>path:${action.url}||class="tool ${action.name}" title="${actionname}" #if($action.rel) rel="${action.rel}"#end]]##
173 173   #end
174 - $!additionalContent
175 175   )))## actions
176 176   )))## attachmentbox
177 177  #end
... ... @@ -328,8 +328,6 @@
328 328   $!targetDocument.use($targetDocument.getObject($options.classname, $options.object))##
329 329   #attachmentPicker_displayAttachmentGallery($targetDocument, $targetAttachDocument, $options)
330 330  
331 - #set ($cancelLinkName = $services.rendering.escape($services.rendering.escape($services.localization.render("${translationPrefix}.cancel"), 'xwiki/2.1'), 'xwiki/2.1'))
332 - #set ($cancelLinkTarget = $services.rendering.escape($services.model.serialize($targetDocument), 'xwiki/2.1'))
333 333   (% class="gallery_buttons buttons" %)(((
334 334   (% class="buttonwrapper secondary" %)[[$services.localization.render("${translationPrefix}.cancel")>>$targetDocument||class="button secondary" id="attachment-picker-close"]]
335 335   )))
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,66 +1,4 @@
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 -
64 64   /** Handles the gallery buttons directly in the current page without reloading the window. */
65 65   XWiki.AttachmentPicker = Class.create({
66 66   /**
... ... @@ -122,23 +122,21 @@
122 122   new XWiki.widgets.Notification("$services.localization.render('xe.attachmentSelector.upload.error.badExtension')", 'error');
123 123   hasErrors = true;
124 124   }
125 - const beforeUploadEvent = Event.fire(document, 'xwiki:actions:beforeUpload', {
126 - file: fileInput.files[0]
127 - });
128 -
129 - if (beforeUploadEvent.defaultPrevented) {
130 - hasErrors = true;
131 - }
132 132   }.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
133 133   if (!hasErrors) {
134 134   if (this.directSave) {
135 135   uploadForm.submit();
136 136   } else {
137 - if ("$!services.temporaryAttachments" != '') {
138 - uploadTemporaryAttachment.call(this);
139 - } else {
140 - directUploadAttachment.call(this, uploadForm);
141 - }
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')});
142 142   }
143 143   }
144 144   }.bindAsEventListener(this));
... ... @@ -237,7 +237,10 @@
237 237   this.dialog.closeDialog();
238 238   }.bindAsEventListener(this),
239 239   onFailure : function(response) {
240 - var failureReason = response.statusText || 'Server not responding';
176 + var failureReason = response.statusText;
177 + if (response.statusText == '' /* No response */ || response.status == 12031 /* In IE */) {
178 + failureReason = 'Server not responding';
179 + }
241 241   if (targetElement._x_notif) {
242 242   targetElement._x_notif.replace(new XWiki.widgets.Notification("$services.localization.render('core.widgets.confirmationBox.notification.failed')" + failureReason, "error"));
243 243   } else {
... ... @@ -244,6 +244,9 @@
244 244   new XWiki.widgets.Notification(this.interactionParameters.failureMessageText + failureReason, "error");
245 245   }
246 246   },
186 + on1223 : function(response) {
187 + response.request.options.onSuccess(response);
188 + },
247 247   on0 : function(response) {
248 248   response.request.options.onFailure(response);
249 249   },
XWiki.StyleSheetExtension[0]
Code
... ... @@ -140,6 +140,9 @@
140 140   ## Make this box twice as large as the others
141 141   width: ${uploadBoxSize}px;
142 142  }
143 +* html .gallery_upload {
144 + width: ${mathtool.add($uploadBoxSize, 2)}px;
145 +}
143 143  .gallery_upload, .gallery_upload:hover {
144 144   background-color: $theme.backgroundSecondaryColor;
145 145  }
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -34,7 +34,7 @@
34 34  #set ($property = "$!{xcontext.macro.params.property}")
35 35  #set ($object = $mathtool.toInteger("$!{xcontext.macro.params.object}"))
36 36  #if ("$!{object}" != $!{xcontext.macro.params.object})
37 - #set ($object = ${targetdoc.getObject($classname).number})
37 + #set ($object = ${doc.getObject($classname).number})
38 38   #if ("$!{object}" == '')
39 39   #set ($object = 0)
40 40   #end
... ... @@ -46,18 +46,9 @@
46 46   #set ($displayImage = false)
47 47  #end
48 48  #if ($displayImage)
49 - #set ($alt = '')
50 - #set ($width = '')
51 - #set ($height = '')
52 - #if ($xcontext.macro.params.alternateText)
53 - #set ($alt = "$services.rendering.escape($!{xcontext.macro.params.alternateText}, 'xwiki/2.1')")
54 - #end
55 - #if ($xcontext.macro.params.width)
56 - #set ($width = "$services.rendering.escape($!{xcontext.macro.params.width}, 'xwiki/2.1')")
57 - #end
58 - #if ($xcontext.macro.params.height)
59 - #set ($height = "$services.rendering.escape($!{xcontext.macro.params.height}, 'xwiki/2.1')")
60 - #end
49 + #set ($alt = "$!{xcontext.macro.params.alternateText}")
50 + #set ($width = "$!{xcontext.macro.params.width}")
51 + #set ($height = "$!{xcontext.macro.params.height}")
61 61   #set ($imageParams = '')
62 62   #if ("${width}" != '')
63 63   #set($imageParams = "$!{imageParams} width=${width}")
... ... @@ -95,7 +95,7 @@
95 95   #set ($savemode = 'form')
96 96  #end
97 97  
98 -#set ($propValue = "$!{targetdoc.getObject($classname, $object).getProperty($property).value}")
89 +#set ($propValue = "$!{doc.getObject($classname, $object).getProperty($property).value}")
99 99  ##
100 100  
101 101  #macro (attachmentPicker_displayAttachment $name $displayImage $withLink $forceElement)
... ... @@ -122,9 +122,9 @@
122 122   #set ($attachmentResource = '')
123 123   #end
124 124   #if ($displayImage)
125 - (% 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)))##
116 + (% class="$!{cssClass}#if (!$attachment) hidden#end" %)(((#if ("$!{attachmentResource}" != '' || $forceElement)#if($withLink)[[#end[[image:${attachmentResource}$!{imageParams}]]#if($withLink)>>attach:${attachmentResource}||rel=lightbox]]#{end}#end)))##
126 126   #else
127 - (% 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(%%)##
118 + (% class="$!{cssClass}" %)#if ("$!{attachmentResource}" != '' || $forceElement)#if ($withLink)[[attach:${attachmentResource}||rel=__blank]]#{else}(% class="displayed" %)#if($targetPermView)$!{attachmentName}#{else}Access Denied#{end}(% %)#{end}#end(%%)##
128 128   #end
129 129  #end
130 130  
... ... @@ -132,7 +132,7 @@
132 132  ## 1. Edit the current page
133 133  ## 2. View the target attachment page. (can be the same page)
134 134  #macro (attachmentPicker_displayButton)
135 - #if ($targetPermView)
126 + #if ($hasEdit && $targetPermView)
136 136   #set ($queryString = {
137 137   'docname': $doc.fullName,
138 138   'classname': $classname,
... ... @@ -159,7 +159,7 @@
159 159  #elseif ($xcontext.action == 'inline' || $xcontext.action == 'edit')
160 160   (% class="attachment-picker" %)(((##
161 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}}##
153 + {{html}}<input type="hidden" name="${classname}_${object}_${property}" value="${propValue}"/>{{/html}}##
163 163   )))
164 164  #else
165 165   #attachmentPicker_displayAttachment($propValue $displayImage $link false)
Default categories
... ... @@ -1,1 +1,0 @@
1 -Development
Default category
... ... @@ -1,0 +1,1 @@
1 +Development