0 Votes

Changes for page Office Importer

Last modified by Ryan C on 2025/04/30 08:04

From version 2.1
Change comment: $escapetool.xml($targetDoc.comment)
To version 3.1
edited by Ryan C
on 2025/04/30 08:04
Change comment: Install extension [org.xwiki.platform:xwiki-platform-office-ui/17.3.0]

Summary

Details

Page properties
Title
... ... @@ -1,0 +1,1 @@
1 +$services.localization.render('xe.officeimporter.import.title')
Parent
... ... @@ -1,0 +1,1 @@
1 +XWiki.WebHome
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.XWikiGuest
1 +XWiki.AdminAngriff
Hidden
... ... @@ -1,1 +1,1 @@
1 -false
1 +true
Content
... ... @@ -1,0 +1,297 @@
1 +{{velocity output="false"}}
2 +#macro (officeImporterForm)
3 + #set ($targetReference = $services.model.resolveDocument($request.page))
4 + #set ($targetPageIsNested = $targetReference.name == $services.model.getEntityReference('DOCUMENT', 'default').name)
5 + #set ($discard = $xwiki.ssx.use('XWiki.OfficeImporter'))
6 + #set ($discard = $xwiki.jsx.use('XWiki.OfficeImporter'))
7 + {{html clean="false"}}
8 + <form id="officeImportForm" class="xform" method="post" enctype="multipart/form-data"
9 + action="$escapetool.xml($xwiki.getURL('XWiki.OfficeImporterResults'))"
10 + data-progress-message="$escapetool.xml($services.localization.render('office.import.inProgress'))"
11 + data-done-message="$escapetool.xml($services.localization.render('office.import.done'))"
12 + data-failed-message="$escapetool.xml($services.localization.render('office.import.failed'))">
13 + <fieldset>
14 + <dl class="row">
15 + ##
16 + ## Left part
17 + ##
18 + <div class="col-xs-12 col-md-6">
19 + #officeImporterForm_officeDocument()
20 + #officeImporterForm_targetPage()
21 + #if ($xwiki.exists($targetReference))
22 + #officeImporterForm_overwriteContent()
23 + #end
24 + </div>
25 + ##
26 + ## Right part
27 + ##
28 + <div class="col-xs-12 col-md-6">
29 + #officeImporterForm_filterStyles()
30 + #officeImporterForm_splitDocument()
31 + #officeImporterForm_headingLevelsToSplit()
32 + #officeImporterForm_childPagesNamingMethod()
33 + #officeImporterForm_terminalChildPages()
34 + </div>
35 + </dl>
36 + ##
37 + ## Hidden inputs
38 + ##
39 + <input type="hidden" name="form_token" value="$!escapetool.xml($services.csrf.token)" />
40 + ## Normalize the parent reference of the new document so that even in a subwiki it points to the current wiki.
41 + #set ($normalizedParentReference = $services.model.resolveDocument("$!request.parent", 'current'))
42 + <input type="hidden" name="parent" value="$escapetool.xml($normalizedParentReference)" />
43 + <input type="hidden" name="target" value="$escapetool.xml($services.model.serialize($targetReference,
44 + 'default'))" />
45 + ##
46 + ## Form action buttons
47 + ##
48 + <div class="buttons">
49 + <span class="buttonwrapper">
50 + <button id="submit">
51 + $escapetool.xml($services.localization.render('xe.officeimporter.import.import'))
52 + </button>
53 + </span>
54 + <span class="buttonwrapper">
55 + <a class="secondary button" href="$escapetool.xml($xwiki.getURL($targetReference))">
56 + $escapetool.xml($services.localization.render('cancel'))
57 + </a>
58 + </span>
59 + </div>
60 + </fieldset>
61 + </form>
62 + {{/html}}
63 +#end
64 +
65 +#macro (officeImporterForm_officeDocument)
66 + ## FIXME: The following list of file name extensions and media types are duplicated from the office resource reference
67 + ## picker (templates/html_displayer/officeresourcereference/edit.vm).
68 + #set ($officeFileNameExtensions = $stringtool.join([
69 + '.doc', '.docx',
70 + '.xls', '.xlsx',
71 + '.ppt', '.pptx',
72 + '.odt', '.ott', '.fodt',
73 + '.ods', '.ots', '.fods',
74 + '.odp', '.otp', '.fodp',
75 + '.sxw', '.sxc', '.sxi'
76 + ], ','))
77 + #set ($officeMediaTypes = $stringtool.join([
78 + 'application/msword', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint',
79 + 'application/vnd.oasis.opendocument.',
80 + 'application/vnd.openxmlformats-officedocument.',
81 + 'application/vnd.sun.xml.'
82 + ], ','))
83 + <dt>
84 + <label for="filePath">
85 + $escapetool.xml($services.localization.render('xe.officeimporter.import.document'))
86 + </label>
87 + <span class="xHint">
88 + $escapetool.xml($services.localization.render('office.import.document.hint'))
89 + </span>
90 + </dt>
91 + <dd class="buttonwrapper">
92 + <input type="file" id="filePath" name="filePath" value="" size="40" class="button secondary" required
93 + accept="$escapetool.xml("$officeFileNameExtensions,$officeMediaTypes")" />
94 + </dd>
95 +#end
96 +
97 +#macro (officeImporterForm_targetPage)
98 + <dt>
99 + <label>
100 + $escapetool.xml($services.localization.render('xe.officeimporter.import.target'))
101 + </label>
102 + <span class="xHint">
103 + $escapetool.xml($services.localization.render('office.import.target.hint'))
104 + </span>
105 + </dt>
106 + <dd>
107 + #template('hierarchy_macros.vm')
108 + #hierarchy($targetReference)
109 + </dd>
110 +#end
111 +
112 +#macro (officeImporterForm_overwriteContent)
113 + <dt>
114 + #define ($warningMessageContent)
115 + <label>
116 + <input name="overwriteContent" type="checkbox" value="true" checked />
117 + $escapetool.xml($services.localization.render('office.import.overwriteContent'))
118 + </label>
119 + <span class="xHint">
120 + $escapetool.xml($services.localization.render('office.import.overwriteContent.hint'))
121 + </span>
122 + #end
123 + #warning($warningMessageContent)
124 + </dt>
125 + <dd>
126 + #officeImporterForm_confirmationModal({
127 + 'cssClass': 'confirmation-overwriteContent',
128 + 'title': 'office.import.overwriteContent',
129 + 'message': 'office.import.overwriteContent.confirmationMessage',
130 + 'action': 'office.import.overwriteContent.confirmationAction'
131 + })
132 + </dd>
133 +#end
134 +
135 +#macro (officeImporterForm_confirmationModal $config)
136 + <div class="confirmation modal fade $!escapetool.xml($config.cssClass)" tabindex="-1" role="dialog">
137 + <div class="modal-dialog">
138 + <div class="modal-content">
139 + <div class="modal-header">
140 + <button type="button" class="close" data-dismiss="modal">&times;</button>
141 + <div class="modal-title">
142 + $escapetool.xml($services.localization.render($config.title))
143 + </div>
144 + </div>
145 + <div class="modal-body">
146 + $escapetool.xml($services.localization.render($config.message))
147 + </div>
148 + <div class="modal-footer">
149 + <input type="button" class="btn btn-danger" data-dismiss="modal"
150 + value="$escapetool.xml($services.localization.render($config.action))">
151 + <input type="button" class="btn btn-default" data-dismiss="modal"
152 + value="$escapetool.xml($services.localization.render('cancel'))">
153 + </div>
154 + </div>
155 + </div>
156 + </div>
157 +#end
158 +
159 +#macro (officeImporterForm_filterStyles)
160 + <dt>
161 + <label>
162 + <input name="filterStyles" type="checkbox" value="strict" checked />
163 + $escapetool.xml($services.localization.render('xe.officeimporter.import.filterstyles'))
164 + </label>
165 + <span class="xHint">
166 + $escapetool.xml($services.localization.render('xe.officeimporter.import.help.styles'))
167 + </span>
168 + </dt>
169 + <dd></dd>
170 +#end
171 +
172 +#macro (officeImporterForm_splitDocument)
173 + <dt>
174 + <label>
175 + <input name="splitDocument" type="checkbox" value="true" />
176 + $escapetool.xml($services.localization.render('xe.officeimporter.import.splitting.splitdocument'))
177 + </label>
178 + <span class="xHint">
179 + $escapetool.xml($services.localization.render('xe.officeimporter.import.help.splitting'))
180 + </span>
181 + </dt>
182 + <dd></dd>
183 +#end
184 +
185 +#macro (officeImporterForm_headingLevelsToSplit)
186 + <dt>
187 + <label for="headingLevelsToSplitInputId">
188 + $escapetool.xml($services.localization.render('xe.officeimporter.import.splitting.headinglevels'))
189 + </label>
190 + <span class="xHint">
191 + $escapetool.xml($services.localization.render('office.import.headingLevelsToSplit.hint'))
192 + </span>
193 + </dt>
194 + <dd>
195 + <select id="headingLevelsToSplitInputId" name="headingLevelsToSplit" multiple required size="6"
196 + class="splitDocument-setting">
197 + #foreach ($level in [1..6])
198 + <option value="$level"#if ($level == 1) selected#end>
199 + $escapetool.xml($services.localization.render('xe.officeimporter.import.splitting.heading')) $level
200 + </option>
201 + #end
202 + </select>
203 + </dd>
204 +#end
205 +
206 +#macro (officeImporterForm_childPagesNamingMethod)
207 + ## Hide the field when the target page is nested (not terminal) because the only logical strategy in this case is to
208 + ## use "headingNames". It creates pages as children of the target, which seems to be the correct way in the nested
209 + ## pages paradigm. The other choices have no sense:
210 + ## - "mainPageNameAndHeading" will create pages called "WebHome-Title1" instead of "targetPage/Title1".
211 + ## - "mainPageNameAndNumbering" will create pages called "WebHome-1" instead of "targetPage/1".
212 + ## In both cases, the "WebHome" part of the names is meaningless.
213 + <dt#if ($targetPageIsNested) hidden#end>
214 + <label for="childPagesNamingMethodInputId">
215 + $escapetool.xml($services.localization.render('xe.officeimporter.import.splitting.naming'))
216 + </label>
217 + <span class="xHint">
218 + $escapetool.xml($services.localization.render('office.import.childPagesNaming.hint'))
219 + </span>
220 + </dt>
221 + <dd>
222 + <select id="childPagesNamingMethodInputId" name="childPagesNamingMethod" class="splitDocument-setting"
223 + #if ($targetPageIsNested) hidden#end>
224 + <option value="headingNames"#if ($targetPageIsNested) selected#end>
225 + $escapetool.xml($services.localization.render('xe.officeimporter.import.splitting.naming.headingnames'))
226 + </option>
227 + <option value="mainPageNameAndHeading"#if (!$targetPageIsNested) selected#end>
228 + $escapetool.xml($services.localization.render(
229 + 'xe.officeimporter.import.splitting.naming.mainpagenameandheading'))
230 + </option>
231 + <option value="mainPageNameAndNumbering">
232 + $escapetool.xml($services.localization.render(
233 + 'xe.officeimporter.import.splitting.naming.mainpagenameandnumbering'))
234 + </option>
235 + </select>
236 + </dd>
237 +#end
238 +
239 +#macro (officeImporterForm_terminalChildPages)
240 + #set ($hidden = !($targetPageIsNested && ($isAdvancedUser || $isSuperAdmin)))
241 + <dt#if ($hidden) hidden#end>
242 + <label>
243 + <input type="checkbox" name="terminalChildPages" value="true"#if ($hidden) checked#end
244 + class="splitDocument-setting" />
245 + $escapetool.xml($services.localization.render('office.import.terminalChildPages'))
246 + </label>
247 + <span class="xHint">
248 + $escapetool.xml($services.localization.render('office.import.terminalChildPages.hint'))
249 + </span>
250 + </dt>
251 + <dd></dd>
252 +#end
253 +
254 +#macro (officeImporter_translationWithLink $key $linkTarget)
255 + #set ($targetSyntax = 'xwiki/2.1')
256 + #set ($translation = $services.localization.render($key, $targetSyntax, ['LINKSTART', 'LINKEND']))
257 + #set ($linkLabel = $stringtool.substringBetween($translation, 'LINKSTART', 'LINKEND'))
258 + #if ($linkLabel)
259 + #set ($escapedLinkLabel = $services.rendering.escape($linkLabel, $targetSyntax))
260 + #set ($escapedLinkTarget = $services.rendering.escape($linkTarget, $targetSyntax))
261 + $translation.replace("LINKSTART${linkLabel}LINKEND", "[[$escapedLinkLabel>>$escapedLinkTarget]]")
262 + #else
263 + $services.localization.render($key, $targetSyntax, ['', ''])
264 + #end
265 +#end
266 +{{/velocity}}
267 +
268 +{{velocity}}
269 +#if ("$!request.page" == '')
270 + {{error}}
271 + ## This page does not propose to select the target page anymore. The create action should be used instead.
272 + ## Note: The link points to the main page because the user might not have create right on the current "XWiki" space,
273 + ## which is reserved anyway for technical pages.
274 + #set ($createURL = $xwiki.getURL($services.wiki.currentWikiDescriptor.mainPageReference, 'create', 'type=office'))
275 + #officeImporter_translationWithLink('office.form.error.noDocument' "path:$createURL")
276 + {{/error}}
277 +#else
278 + ## Hide UI elements that are not needed for office import.
279 + #set ($displayContentMenu = false)
280 + #set ($displayContentFooter = false)
281 + #set ($displayDocExtra = false)
282 + #if ($isguest)
283 + {{error}}$services.localization.render('xe.officeimporter.notallowed', 'xwiki/2.1'){{/error}}
284 + #elseif (!$services.officemanager.isConnected())
285 + #if ($hasAdmin)
286 + {{error}}
287 + #set ($documentationURL = 'http://extensions.xwiki.org/xwiki/bin/Extension/Office%20Importer%20Application')
288 + #officeImporter_translationWithLink('xe.officeimporter.error.adminuser' $documentationURL)
289 + {{/error}}
290 + #else
291 + {{error}}$services.localization.render('xe.officeimporter.error.normaluser', 'xwiki/2.1'){{/error}}
292 + #end
293 + #else
294 + #officeImporterForm()
295 + #end
296 +#end
297 +{{/velocity}}
XWiki.JavaScriptExtension[0]
Caching policy
... ... @@ -1,0 +1,1 @@
1 +long
Code
... ... @@ -1,0 +1,80 @@
1 +require(['jquery', 'bootstrap'], function($) {
2 + /**
3 + * Enable/disable the split document settings based on the value of the split document checkbox.
4 + */
5 + const maybeDisableSplitDocumentSettings = function() {
6 + const splitDocumentDisabled = !$('input[name=splitDocument]').prop('checked');
7 + $('.splitDocument-setting').prop('disabled', splitDocumentDisabled);
8 + };
9 +
10 + // Initalize the default state.
11 + maybeDisableSplitDocumentSettings();
12 +
13 + // Enable/disable the split document settings when the checkbox's value changes.
14 + $('input[name=splitDocument]').on('change', maybeDisableSplitDocumentSettings);
15 +
16 + /**
17 + * Handle form submit.
18 + */
19 + $('#officeImportForm').on('submit', function(event) {
20 + event.preventDefault();
21 +
22 + const overwriteContentCheckbox = $('input[name=overwriteContent]');
23 + if (!overwriteContentCheckbox.prop('checked') || overwriteContentCheckbox.data('confirmed')) {
24 + importOfficeDocument($(event.target));
25 + } else {
26 + // Ask for confirmation to overwrite the content of the target page.
27 + $('.modal.confirmation-overwriteContent').modal();
28 + }
29 + });
30 +
31 + $('.modal.confirmation-overwriteContent .btn-danger').on('click', function(event) {
32 + // Remember the confirmation.
33 + $('input[name=overwriteContent]').data('confirmed', true);
34 + // Re-submit the form.
35 + $('#officeImportForm #submit').click();
36 + });
37 +
38 + const importOfficeDocument = function(form) {
39 + // Collect the form data before disabling the form.
40 + const formData = new FormData(form[0]);
41 + // Disable the form while the office document is being imported (to prevent the form from being re-submitted).
42 + form.children('fieldset').prop('disabled', true);
43 + // Let the user know that the import is in progress.
44 + $('body').css('cursor', 'wait');
45 + const notification = new XWiki.widgets.Notification(form.data('progressMessage'), 'inprogress');
46 + // Send the office import request.
47 + fetch(new XWiki.Document('OfficeImporterResults', 'XWiki').getURL('get'), {
48 + method: 'POST',
49 + body: formData
50 + }).then(
51 + response => response.text()
52 + ).then(html => {
53 + if (html.indexOf('infomessage') > 0) {
54 + // Office import successful.
55 + notification.replace(new XWiki.widgets.Notification(form.data('doneMessage'), 'done'));
56 + // Redirect to the target page.
57 + const targetPageReference = XWiki.Model.resolve(formData.get('target'), XWiki.EntityType.DOCUMENT,
58 + XWiki.currentDocument.documentReference);
59 + window.location.href = new XWiki.Document(targetPageReference).getURL();
60 + } else {
61 + // Extract the error message from the returned HTML.
62 + const errorMessage = $('<div></div>').html(html).text();
63 + return Promise.reject(errorMessage);
64 + }
65 + }).catch(error => {
66 + let failedMessage = form.data('failedMessage');
67 + if (error) {
68 + failedMessage += `: ${error}`;
69 + }
70 + notification.replace(new XWiki.widgets.Notification(failedMessage, 'error'));
71 + }).finally(() => {
72 + // Re-enable the office import.
73 + form.children('fieldset').prop('disabled', false);
74 + $('body').css('cursor', '');
75 + });
76 + };
77 +
78 + // Everything is ready.
79 + $('#officeImportForm #submit').attr('data-ready', true);
80 +});
Use this extension
... ... @@ -1,0 +1,1 @@
1 +onDemand
Name
... ... @@ -1,0 +1,1 @@
1 +Code
Parse content
... ... @@ -1,0 +1,1 @@
1 +No
XWiki.StyleSheetExtension[0]
Caching policy
... ... @@ -1,0 +1,1 @@
1 +long
Code
... ... @@ -1,0 +1,9 @@
1 +.xdocLastModification,
2 +#hierarchy.breadcrumb {
3 + display: none;
4 +}
5 +
6 +/* Needed to avoid an overflow of the input with a long filename in Firefox zoomed above 100 percent.*/
7 +#officeImportForm #filePath {
8 + max-width: 100%;
9 +}
Use this extension
... ... @@ -1,0 +1,1 @@
1 +onDemand
Parse content
... ... @@ -1,0 +1,1 @@
1 +No
Content Type
... ... @@ -1,0 +1,1 @@
1 +LESS

XWiki AI Chat