Änderungen von Dokument View File Macro

Zuletzt geändert von xwikiadmin am 2025/12/11 07:44

Von Version 6.1
bearbeitet von xwikiadmin
am 2024/06/24 15:04
Änderungskommentar: Install extension [com.xwiki.pro:xwiki-pro-macros-ui/1.19.4]
Auf Version 10.1
bearbeitet von xwikiadmin
am 2025/12/11 07:44
Änderungskommentar: Install extension [com.xwiki.pro:xwiki-pro-macros-ui/1.28.5]

Zusammenfassung

Details

Seiteneigenschaften
Inhalt
... ... @@ -6,10 +6,11 @@
6 6  
7 7  |=Parameter|=Description|=Required|=Default
8 8  |display|Kind of display. "button" for a button, "thumbnail" for a thumbnail, "full" to render the document in place|no|thumbnail (button in inline mode)
9 -|name|The attachment reference to display|if att-filename is not given|
9 +|name|The attachment reference to display|if att--filename is not given|
10 +|page|The page from where you want the attachments to be displayed. Modifying this parameter will reset the selected file value|no|
10 10  |width|The width of the view in % or px (e.g. 100%, 100px)|no|100% for the full view or 100px for the thumbnail
11 11  |height|The height of the view in % or px (e.g. 100%, 100px)|no|1000px for the full view or 100px for the thumbnail
12 -|att-filename|Alias of name|If name is not given|
13 +|att--filename|Alias of name|If name is not given|
13 13  
14 14  = Example Usage =
15 15  
XWiki.JavaScriptExtension[0]
Code
... ... @@ -1,33 +1,185 @@
1 -window.addEventListener("DOMContentLoaded", function () {
2 - "use strict";
3 - document.addEventListener("click", async function (e) {
4 - if (("" + document.getElementById("xwikicontent")?.contentEditable) == "true") {
5 - return;
6 - }
7 - const viewFile = e.target?.closest(".viewFileThumbnail");
8 - if (viewFile && viewFile.dataset.preview === 'true') {
9 - const popup = new XWiki.widgets.ModalPopup();
10 - popup.createDialog();
11 - popup.setContent("<span class='fa fa-spinner'></span>");
12 - popup.dialogBox.classList.add("viewFileModal");
13 - popup.dialogBox.style.top = "2.5vh";
14 - popup.dialogBox.style.width = "95vw";
15 - popup.dialogBox.style.height = "95vh";
16 - const a = e.target.closest('a');
17 - const downloadLink = document.createElement("a");
18 - downloadLink.download = true;
19 - downloadLink.textContent = a.textContent;
20 - downloadLink.className = "fa fa-download button button-primary viewFileModal-downloadLink";
21 - downloadLink.href = a.href;
22 - popup.dialogBox.insertBefore(downloadLink, popup.dialogBox.firstChild)
23 - popup.showDialog();
24 - e.preventDefault();
25 - const response = await fetch(XWiki.contextPath + "/wiki/" + XWiki.currentWiki + "/get/Confluence/Macros/ViewFileService?action=render&attachment=" + encodeURIComponent(viewFile.dataset.ref));
26 - popup.setContent(await response.text());
27 - const gallery = popup.dialogBox.querySelector(".gallery");
28 - if (gallery) {
29 - new XWiki.Gallery(gallery);
30 - }
31 - }
1 +require.config({
2 + paths: {
3 + 'xwiki-suggestAttachments': "$xwiki.getSkinFile('uicomponents/suggest/suggestAttachments.js', true)" +
4 + "?v=$escapetool.url($xwiki.version)"
5 + }
6 +});
7 +
8 +// As there is no platform implementation to allow the user to dynamically select the page from where the attachments
9 +// are shown, a custom implementation was made to dynamically update the displyed attachments in corelation to the
10 +// selected page parameter. This can be removed after the implementation of https://jira.xwiki.org/browse/XWIKI-22850.
11 +require(['jquery', 'xwiki-meta', 'xwiki-suggestAttachments'], function($, xm) {
12 + require(['collabora-utils'], function(collabora) {
13 + initUI(collabora);
14 + }, function (err) {
15 + console.warn('collabora-utils not found, continuing without it.');
16 + initUI(null);
32 32   });
18 +
19 + function initUI(collabora) {
20 + const acceptedExtensions = '.ppt,.pptx,.odp,.doc,.docx,.odt,.xls,.xlsx,.ods,.pdf';
21 + const styleObserver = new MutationObserver(function(mutations) {
22 + for (const mutation of mutations) {
23 + if (mutation.target.style.display === 'none') {
24 + styleObserver.disconnect();
25 + pageObserver.observe(document.body, { childList: true, subtree: true });
26 + return;
27 + }
28 + }
29 + });
30 +
31 + const initializeAttachments = function(selectElement) {
32 + let scope = "document:";
33 + if (selectElement.val() != null) {
34 + scope += selectElement.val();
35 + }
36 + var inputElement = $('input[name="name"]');
37 + if (inputElement.length) {
38 + let selectize = inputElement.siblings('.selectize-control');
39 + if (selectize.length) {
40 + selectize.remove();
41 + inputElement.removeAttr("class tabindex style").val('');
42 + const clone = inputElement.clone().appendTo(inputElement.parent());
43 + inputElement.remove();
44 + inputElement = clone;
45 + }
46 + const allowUpload = selectElement.val() == xm.document || !selectElement.val();
47 + inputElement.suggestAttachments({
48 + maxItems: 1,
49 + accept: acceptedExtensions,
50 + searchScope: scope,
51 + uploadAllowed: allowUpload
52 + });
53 + }
54 + };
55 +
56 + const checkModalAttachment = function(mutationsList, observer) {
57 + const selectElement = $('select[name="page"]');
58 + if (selectElement.length) {
59 + const modal = selectElement.closest(".macro-editor-modal")[0];
60 + if (modal && modal.style.display !== 'none') {
61 + observer.disconnect();
62 + styleObserver.observe(modal, { attributes: true, attributeFilter: ['style'] });
63 + $(selectElement).change(function() {
64 + initializeAttachments($(this));
65 + });
66 + initializeAttachments(selectElement);
67 + }
68 + }
69 + };
70 +
71 + const pageObserver = new MutationObserver(checkModalAttachment);
72 + pageObserver.observe(document.body, { childList: true, subtree: true });
73 + checkModalAttachment([], pageObserver);
74 +
75 + const getFileExtension = function(fileName) {
76 + return fileName.slice(fileName.lastIndexOf('.') + 1).toLowerCase();
77 + };
78 +
79 + const decorateWithCollaboraButton = function(viewFile, fileRef, spanContainer) {
80 + const attachment = XWiki.Model.resolve(fileRef, XWiki.EntityType.ATTACHMENT);
81 + var fileName = attachment.getName();
82 + var collaboraButton = $(viewFile).find('a.collaboraEdit');
83 + if (collaboraButton.length != 0) {
84 + const accessRights = collabora.getAccessRights(fileName);
85 + if (!accessRights) {
86 + return;
87 + }
88 + collabora.populateCollaboraButton(collaboraButton, fileName, accessRights, XWiki.Model.serialize(attachment.parent));
89 + const clonedButton = collaboraButton.clone(true, true);
90 + clonedButton.addClass('btn btn-default');
91 + clonedButton.addClass('viewfile-header-button');
92 + clonedButton.attr('target', '_blank');
93 + $(spanContainer).find('.viewFileModal-downloadLink').after(clonedButton);
94 + }
95 + };
96 +
97 + // This function has been taken from OnlyOffice Connector Application, as it's being used to determine what
98 + // action the user can take on a file depending on the file extension.
99 + const determineOOAction = function(fileRef) {
100 + var ooCanDoByExt = { };
101 + const editableFormats = ['docx', 'xlsx', 'pptx'];
102 + const convertibleFormats = ['odt', 'ods', 'odp', 'xls', 'csv', 'doc', 'ppt', 'pps', 'ppsx', 'rtf', 'txt', 'mht',
103 + 'html', 'htm'];
104 + editableFormats.forEach(function(x) {
105 + ooCanDoByExt[x] = 'edit';
106 + });
107 + convertibleFormats.forEach(function(x) {
108 + ooCanDoByExt[x] = 'convert';
109 + });
110 + ['pdf', 'djvu', 'fb2', 'epub', 'xps'].forEach(function(x) {
111 + ooCanDoByExt[x] = 'view';
112 + });
113 + var fileType = getFileExtension(fileRef);
114 + return ooCanDoByExt[fileType];
115 + };
116 +
117 + const decorateWithXooButton = function(viewFile, fileRef, spanContainer) {
118 + if ($(viewFile).find('span.oo-installed-check').data('ooexists')) {
119 + var whatCanDo = determineOOAction(fileRef);
120 + if (!whatCanDo) {
121 + return;
122 + }
123 + if (!XWiki.hasEdit) {
124 + whatCanDo = 'view';
125 + }
126 + const attachment = XWiki.Model.resolve(fileRef, XWiki.EntityType.ATTACHMENT);
127 + var queryString = $.param({
128 + 'elem': 'oOActionButtons',
129 + 'document': XWiki.Model.serialize(attachment.parent),
130 + 'filename': attachment.getName(),
131 + 'whatCanDo': whatCanDo,
132 + 'asLink': true
133 + });
134 +
135 + $.post(new XWiki.Document('UI', 'XWikiOnlyOfficeCode').getURL('get', queryString), function(data) {
136 + const $button = $(data);
137 + $button.addClass('btn btn-default');
138 + $button.addClass('viewfile-header-button');
139 + $button.attr('target', '_blank');
140 + $(spanContainer).find('.viewFileModal-downloadLink').after($button);
141 + });
142 + }
143 + };
144 +
145 + $(document).on("click", async function (e) {
146 + if (("" + document.getElementById("xwikicontent")?.contentEditable) == "true") {
147 + return;
148 + }
149 + const viewFile = e.target?.closest(".viewFileThumbnail");
150 + if (viewFile && viewFile.dataset.preview === 'true') {
151 + const fileRef = viewFile.dataset.ref;
152 + const popup = new XWiki.widgets.ModalPopup();
153 + popup.createDialog();
154 + popup.setContent("<span class='fa fa-spinner'></span>");
155 + popup.dialogBox.classList.add("viewFileModal");
156 + popup.dialogBox.style.top = "2.5vh";
157 + popup.dialogBox.style.width = "95vw";
158 + popup.dialogBox.style.height = "95vh";
159 + const a = e.target.closest('a');
160 + const downloadLink = document.createElement('a');
161 + const spanContainer = document.createElement('span');
162 + spanContainer.className = 'viewfile-actions-header';
163 + downloadLink.download = true;
164 + downloadLink.textContent = ' ' + $(a).find('.viewFileName').text();
165 + downloadLink.className = 'fa fa-download button button-primary viewFileModal-downloadLink viewfile-header-button';
166 + downloadLink.href = a.href;
167 + spanContainer.appendChild(downloadLink);
168 + decorateWithXooButton(viewFile, fileRef, spanContainer);
169 + if (collabora != null) {
170 + decorateWithCollaboraButton(viewFile, fileRef, spanContainer);
171 + }
172 + $(popup.dialogBox).prepend(spanContainer);
173 + popup.showDialog();
174 + e.preventDefault();
175 + const response = await fetch(XWiki.contextPath + '/wiki/' + XWiki.currentWiki +
176 + '/get/Confluence/Macros/ViewFileService?action=render&attachment=' + encodeURIComponent(fileRef));
177 + popup.setContent(await response.text());
178 + const gallery = popup.dialogBox.querySelector(".gallery");
179 + if (gallery) {
180 + new XWiki.Gallery(gallery);
181 + }
182 + }
183 + });
184 + }
33 33  });
Inhalt parsen
... ... @@ -1,1 +1,1 @@
1 -Nein
1 +Ja
XWiki.StyleSheetExtension[0]
Code
... ... @@ -1,3 +1,5 @@
1 +#template('colorThemeInit.vm')
2 +
1 1  .viewFileModal iframe, .viewFileModal .xdialog-content {
2 2   height: calc(95vh - 5em);
3 3  }
... ... @@ -42,8 +42,15 @@
42 42  
43 43  .viewFileThumbnailCard, .viewFileFull {
44 44   position: relative;
47 + margin-bottom: 1rem !important;
45 45  }
46 46  
50 +.viewFileThumbnailCard {
51 + width: 10rem !important;
52 + height: fit-content !important;
53 + min-height: 10rem;
54 +}
55 +
47 47  span.viewFileThumbnailCard {
48 48   display: inline-block;
49 49  }
... ... @@ -54,7 +54,7 @@
54 54   flex-direction: column;
55 55   text-align: center;
56 56   width: 100%;
57 - height: 100%;
66 + min-height: inherit;
58 58  }
59 59  
60 60  .viewFileThumbnailCard a .attachmentMimeType {
... ... @@ -67,8 +67,51 @@
67 67   width: 100%;
68 68   border: 1px solid;
69 69   border-radius: 1rem;
79 + min-height: 5em;
70 70  }
71 71  
72 72  .viewFileModal-downloadLink {
73 73   margin-left: 2px;
74 74  }
85 +
86 +.viewFileName {
87 + overflow-wrap: break-word;
88 +}
89 +
90 +.image-container {
91 + position: relative;
92 +}
93 +
94 +.viewfile-thumbnail-image {
95 + display: block;
96 +}
97 +
98 +.overlay {
99 + position: absolute;
100 + inset: 0px;
101 + opacity: 0;
102 + transition: .7s ease;
103 + background-color: $theme.buttonPrimaryBackgroundColor;
104 +}
105 +
106 +.image-container:hover .overlay {
107 + opacity: 1;
108 +}
109 +
110 +.overlay-text {
111 + color: $theme.buttonPrimaryTextColor;
112 + font-size: 2rem;
113 + position: absolute;
114 + top: 50%;
115 + left: 50%;
116 + transform: translate(-50%, -50%);
117 + text-align: center;
118 +}
119 +
120 +.viewfile-header-button {
121 + margin: 1rem 0.7rem;
122 +}
123 +
124 +.viewfile-actions-header {
125 + margin: 1rem;
126 +}
Inhalt parsen
... ... @@ -1,1 +1,1 @@
1 -Nein
1 +Ja
XWiki.WikiMacroClass[0]
Cached
... ... @@ -1,1 +1,0 @@
1 -Nein
Asynchrones Rendern
... ... @@ -1,1 +1,0 @@
1 -Nein
Makro-Code
... ... @@ -1,155 +1,0 @@
1 -{{velocity output="false"}}
2 -#template('attachment_macros.vm')
3 -
4 -#set ($officeExtensions = [ 'ppt', 'pptx', 'odp', 'doc', 'docx', 'odt', 'xls', 'xlsx', 'ods' ])
5 -#set ($presentationExtensions = [ 'ppt', 'pptx', 'odp' ])
6 -#set ($hasPDFViewer = $xwiki.exists("XWiki.PDFViewerMacro"))
7 -
8 -#macro (renderThumbnailButton $attachmentRef $previewSupported $width $height $forceCard)
9 - #set ($style = "")
10 - #if ("$!width" != "")
11 - #set ($style = $style + " width: $width")
12 - #end
13 - #if ("$!height" != "")
14 - #set ($style = $style + " height: $height")
15 - #end
16 - #if ("$!style" != "")
17 - #set ($style = "style='$style.trim()'")
18 - #set ($thumbnailStyle = "Card")
19 - #elseif ($forceCard)
20 - #set ($style = "style='width: 100px; height: 100px;'")
21 - #set ($height = "100px")
22 - #set ($thumbnailStyle = "Card")
23 - #else
24 - #set ($thumbnailStyle = "Button")
25 - #end
26 - #if ($wikimacro.context.isInline() || $thumbnailStyle == "Button")
27 - #set ($elem = "span")
28 - #else
29 - #set ($elem = "div")
30 - #end
31 - #set ($attachment = $xwiki.getDocument($attachmentRef.getParent()).getAttachment($attachmentRef.getName()))
32 - #set ($thumbnail = "#displayAttachmentMimeType($attachment)")
33 - #if ($thumbnail.charAt(0) == '#')
34 - ## #displayAttachmentMimeType is not supported (before July 2022)
35 - #set ($thumbnail = '<div class="attachmentMimeType"><span><span class="fa fa-paperclip" aria-hidden="true"></span></span></div>')
36 - #end
37 - #if ($elem == "span")
38 - #set ($thumbnail = $thumbnail.replace('</div>', '</span>').replace('<div ', '<span '))
39 - #end
40 -
41 - {{html clean=false}}
42 - <$elem class="viewFileThumbnail viewFileThumbnail$thumbnailStyle" $style data-preview="$previewSupported" data-ref="$escapetool.xml($services.model.serialize($attachmentRef, 'default'))">
43 - <a href="$escapetool.xml($xwiki.getURL($attachmentRef))"
44 - download="download"
45 - #if ($thumbnailStyle == "Button") class="button button-primary" #end
46 - title="$escapetool.xml($services.localization.render('rendering.macro.viewFile.thumbnail.button.title'))"
47 - >
48 - $thumbnail
49 - <span class="viewFileName">$escapetool.xml($attachmentRef.getName())</span>
50 - </a>
51 - </$elem>
52 - {{/html}}
53 -
54 -#end
55 -
56 -#macro (renderFull $extension $attachmentRef $width $height)
57 - #set ($escapedAttachmentReference = $services.rendering.escape($attachmentRef, $xwiki.currentContentSyntaxId))
58 - #if ($officeExtensions.contains($extension))
59 -
60 - {{html clean=false}}
61 - <div class="viewFileFull#if (!$presentationExtensions.contains($extension)) box#end"
62 - style="width: $width; height: $height; overflow: auto">
63 - {{/html}}
64 -
65 - {{office reference="$escapedAttachmentReference" /}}
66 -
67 - {{html clean=false}}
68 - </div>
69 - {{/html}}
70 -
71 - #elseif ($extension == 'pdf' && $hasPDFViewer)
72 - #if ($height.endsWith("px"))
73 - #set ($height = $stringtool.removeEnd($height, "px"))
74 - #end
75 - #if ($width.endsWith("px"))
76 - #set ($width = $stringtool.removeEnd($width, "px"))
77 - #end
78 -
79 - {{pdfviewer file="$escapedAttachmentReference" height="$height" width="$width"/}}
80 -
81 - #else
82 - #renderThumbnailButton($attachmentRef false $width $height)
83 - #end
84 -#end
85 -
86 -#macro (executeMacro)
87 - #set($unescapedFilename = $xcontext.macro.params.get('att--filename'))
88 - #if(!$unescapedFilename)
89 - #set($unescapedFilename = $xcontext.macro.params.get('name'))
90 - #end
91 - #if(!$unescapedFilename)
92 -
93 - {{error}}
94 - $escapetool.xml($services.localization.render('rendering.macro.viewFile.namerequired'))"
95 - {{/error}}
96 - #end
97 - #continueExecutingMacro##
98 -#end
99 -
100 -#macro (continueExecutingMacro)
101 - #set ($attachmentRef = $services.model.resolveAttachment($unescapedFilename))
102 - #set ($discard = $xwiki.ssx.use('Confluence.Macros.ViewFile'))
103 - #set ($extension = $unescapedFilename.substring($unescapedFilename.lastIndexOf('.') + 1).toLowerCase())
104 - #set ($width = $xcontext.macro.params.get('width'))
105 - #set ($height = $xcontext.macro.params.get('height'))
106 - #set ($display = $xcontext.macro.params.get('display'))
107 - #if ("$!width" != "")
108 - #set ($width = $escapetool.xml($width))
109 - #if (!$width.endsWith("%") && !$width.endsWith("px"))
110 - #set($width = $width + "px")
111 - #end
112 - #end
113 - #if ("$!height" != "")
114 - #set ($height = $escapetool.xml($height))
115 - #if (!$height.endsWith("%") && !$height.endsWith("px"))
116 - #set($height = $height + "px")
117 - #end
118 - #end
119 - #if (($display == 'FULL' || $display == 'full') && ($wikimacro.context.isInline() || ($xcontext.action == "edit" || $request.outputSyntax == "annotatedhtml")))
120 - #set ($display = "thumbnail")
121 - #end
122 - #if ($display == 'FULL' || $display == 'full')
123 - #if ("$!width" == "")
124 - #set ($width = "100%")
125 - #end
126 - #if ("$!height" == "")
127 - #set ($height = "1000px")
128 - #end
129 - #renderFull($extension $attachmentRef $width $height)
130 - #else
131 - ## thumbnail or fallback
132 - #set ($hasPreview = ($extension == 'pdf' && $hasPDFViewer) || $officeExtensions.contains($extension))
133 - #if ($hasPreview)
134 - #set ($discard = $xwiki.jsx.use('Confluence.Macros.ViewFile'))
135 - #end
136 - #set ($forceCard = ($display == 'THUMBNAIL' || $display == 'thumbnail' || ("$!display" == "" && !$wikimacro.context.isInline())))
137 - #if ($presentationExtensions.contains($extension))
138 - #set ($discard = $xwiki.jsfx.use("uicomponents/widgets/gallery/gallery.js", {"forceSkinAction": true}))
139 - #set ($discard = $xwiki.ssfx.use("uicomponents/widgets/gallery/gallery.css"))
140 - #end
141 - #renderThumbnailButton($attachmentRef $hasPreview $width $height $forceCard)
142 - #end
143 -#end
144 -{{/velocity}}
145 -
146 -{{velocity}}
147 -## We need to check if there is a valid license because the macro is registered even if the user doesn't have view right
148 -## on the macro definition page. See XWIKI-14828: Rendering macros defined in wiki pages are available to users that
149 -## don't have view right on those pages.
150 -#if ($services.promacrolicensing.hasLicensureForEntity($xcontext.macro.doc.documentReference))##
151 - #executeMacro##
152 -#else
153 - {{missingLicenseMessage extensionName="proMacros.extension.name"/}}
154 -#end
155 -{{/velocity}}
Verfügbarkeit von Makroinhalten
... ... @@ -1,1 +1,0 @@
1 -No content
Makrobeschreibung
... ... @@ -1,1 +1,0 @@
1 -Show files using PDF Viewer Macro or Office Viewer
Makro id
... ... @@ -1,1 +1,0 @@
1 -view-file
Makroname
... ... @@ -1,1 +1,0 @@
1 -View Files
Unterstützt Inline-Modus
... ... @@ -1,1 +1,0 @@
1 -Ja
Makro-Sichtbarkeit
... ... @@ -1,1 +1,0 @@
1 -Current Wiki
XWiki.WikiMacroParameterClass[0]
Parameter-Beschreibung
... ... @@ -1,1 +1,0 @@
1 -Alias of name (here for compatibility reasons)
Parameter verpflichtend
... ... @@ -1,1 +1,0 @@
1 -Nein
Parameter-Name
... ... @@ -1,1 +1,0 @@
1 -att--filename
Parameter-Typ
... ... @@ -1,1 +1,0 @@
1 -org.xwiki.model.reference.AttachmentReference
XWiki.WikiMacroParameterClass[1]
Parameter-Beschreibung
... ... @@ -1,1 +1,0 @@
1 -The width of the view in % or px (e.g. 100%, 100px)
Parameter verpflichtend
... ... @@ -1,1 +1,0 @@
1 -Nein
Parameter-Name
... ... @@ -1,1 +1,0 @@
1 -width
XWiki.WikiMacroParameterClass[2]
Parameter-Beschreibung
... ... @@ -1,1 +1,0 @@
1 -The height of the view in % or px (e.g. 100%, 100px)
Parameter verpflichtend
... ... @@ -1,1 +1,0 @@
1 -Nein
Parameter-Name
... ... @@ -1,1 +1,0 @@
1 -height
XWiki.WikiMacroParameterClass[3]
Parameter-Beschreibung
... ... @@ -1,1 +1,0 @@
1 -Kind of display. "button" for a button, "thumbnail" for a thumbnail, "full" to render the document in place
Parameter verpflichtend
... ... @@ -1,1 +1,0 @@
1 -Nein
Parameter-Name
... ... @@ -1,1 +1,0 @@
1 -display
Parameter-Typ
... ... @@ -1,1 +1,0 @@
1 -com.xwiki.macros.internal.ViewFileDisplay
XWiki.WikiMacroParameterClass[4]
Parameter-Beschreibung
... ... @@ -1,1 +1,0 @@
1 -The attachment reference to display
Parameter verpflichtend
... ... @@ -1,1 +1,0 @@
1 -Nein
Parameter-Name
... ... @@ -1,1 +1,0 @@
1 -name
Parameter-Typ
... ... @@ -1,1 +1,0 @@
1 -org.xwiki.model.reference.AttachmentReference