Änderungen von Dokument Calendar Macro
Zuletzt geändert von xwikiadmin am 2025/12/11 06:30
Von Version 5.1
bearbeitet von xwikiadmin
am 2025/01/07 11:32
am 2025/01/07 11:32
Änderungskommentar:
Install extension [com.xwiki.mocca-calendar:application-mocca-calendar-ui/2.15]
Auf Version 8.1
bearbeitet von xwikiadmin
am 2025/12/03 10:04
am 2025/12/03 10:04
Änderungskommentar:
Install extension [com.xwiki.mocca-calendar:application-mocca-calendar-ui/2.18.0]
Zusammenfassung
-
Objekte (3 geändert, 0 hinzugefügt, 0 gelöscht)
Details
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -16,8 +16,6 @@ 16 16 XWiki.MoccaCalendar = {}; 17 17 } 18 18 19 -#template('colorThemeInit.vm') 20 - 21 21 XWiki.MoccaCalendar.Helper = Class.create({ 22 22 initialize: function(calendar, dateFormat, jsonServiceUrl, createEventBaseUrl, updateEventUrl, newPageNameUrl, dateCheckUrl, deleteEventInstanceUrl, newPageParams, formToken) { 23 23 this.calendar = calendar; ... ... @@ -158,7 +158,6 @@ 158 158 }, 159 159 { 160 160 verticalPosition: "top", 161 - backgroundColor: "$theme.pageHeaderBackgroundColor", 162 162 title : this.interactionParameters.editMode ? "$escapetool.javascript($services.localization.render('MoccaCalendar.calendarevent.create'))" : "$escapetool.javascript($services.localization.render('MoccaCalendar.calendarevent.view'))", 163 163 removeOnClose : true, 164 164 onClose : function() { ... ... @@ -301,6 +301,24 @@ 301 301 } 302 302 this.content.title.value = purify.sanitize(this.content.title.value) 303 303 this.content.writeAttribute('action', saveUrl + '&xpage=plain&ajax=true'); 301 + let formData = new FormData(this.content); 302 + if (formData.get('MoccaCalendar.MoccaCalendarEventClass_0_allDay') == 1) { 303 + this.content.querySelectorAll('input.datetime').forEach(dateInput => { 304 + // Convert the date fields from the displayed format to the one accepted by the backend. 305 + const dateObj = moment(dateInput.value, moment().toMomentFormatString(dateInput.getAttribute('data-format'))); 306 + if (dateInput.id == "MoccaCalendar.MoccaCalendarEventClass_0_endDate") { 307 + // For the end date, set the hour to 23:59 instead of 00:00. 308 + dateObj.hours(23); 309 + dateObj.minutes(59); 310 + } 311 + const calendarEventObjectDateFormat = moment().toMomentFormatString(this.helper.dateFormat); 312 + // Add a hidden element to the DOM to avoid flickering. 313 + const tempElement = dateInput.clone(); 314 + tempElement.addClassName('hidden'); 315 + tempElement.value = dateObj.isValid() ? dateObj.format(calendarEventObjectDateFormat) : ""; 316 + dateInput.parentElement.insertBefore(tempElement, dateInput); 317 + }); 318 + } 304 304 this.content.request({ 305 305 onSuccess: function() { 306 306 this.saving = false; ... ... @@ -746,13 +746,14 @@ 746 746 747 747 }); 748 748 749 -define('mocca-calendar- import-notification', {750 - prefix: 'MoccaCalendar. import.notification.',764 +define('mocca-calendar-notification', { 765 + prefix: 'MoccaCalendar.notification.', 751 751 keys: [ 752 - 'inprogress', 753 - 'done', 754 - 'error', 755 - 'filetoolarge' 767 + 'import.inprogress', 768 + 'import.done', 769 + 'import.error', 770 + 'import.filetoolarge', 771 + 'addObject.error' 756 756 ] 757 757 }); 758 758 ... ... @@ -759,7 +759,7 @@ 759 759 /** 760 760 * Delete event and calendar import actions. 761 761 */ 762 -require(['jquery', 'xwiki-meta', 'xwiki-job-runner', 'xwiki-l10n!mocca-calendar- import-notification'],778 +require(['jquery', 'xwiki-meta', 'xwiki-job-runner', 'xwiki-l10n!mocca-calendar-notification'], 763 763 function($, xwikiMeta, JobRunner, l10n) { 764 764 /** 765 765 * Events triggered before deleteEvents modal is shown: save the button that triggers ... ... @@ -796,33 +796,64 @@ 796 796 new XWiki.MoccaCalendar.MoccaCalendarPopup(calendarPopup.interactionParameters, calendarPopup.helper); 797 797 }); 798 798 815 + $(document).on('click', '.add-calendar-object-container a', function(event) { 816 + event.preventDefault(); 817 + const addObjectButton = $('#add-calendar-object'); 818 + const target = addObjectButton.data('target'); 819 + // To be adapted to the standard XWiki rest endpoint for object creation after 820 + // XWIKI-20704: NullPointerException (NPE) when accessing objects with ComputedField properties from REST is fixed. 821 + var documentReference = XWiki.Model.resolve('MoccaCalendar.Code.MoccaCalendarObjectCreator', 822 + XWiki.EntityType.DOCUMENT); 823 + var targetUrl = new XWiki.Document(documentReference).getURL(); 824 + var params = { 825 + 'documentRef': target 826 + }; 827 + $.ajax({ 828 + url: targetUrl, 829 + type: 'POST', 830 + data: params, 831 + success: function (response) { 832 + window.location.reload(); 833 + }, 834 + error: function (xhr, status, error) { 835 + console.error('Failed to add the MoccaCalendarClass object', error); 836 + var notification = new XWiki.widgets.Notification(l10n.get('addObject.error'), 'error'); 837 + } 838 + }); 839 + }); 840 + 799 799 // Trigger the upload manually when the button is clicked. 800 - $(document).on('click', '#import-calendar-file-button', function(event) { 801 - var form = $('#import-calendar-file form').get(0); 802 - if (event) { 803 - event.preventDefault(); 804 - } 805 - startUploading(form); 842 + $(document).on('click', '.import-calendar-file-button', function(event) { 843 + event.preventDefault(); 844 + var calId = $(event.target).data('calid'); 845 + var form = $(`#import-calendar-file-${calId} form`).get(0); 846 + startUploading(form, calId); 806 806 }); 807 807 808 808 // Start uploading this file by creating a new XHR object with the file data. 809 - var startUploading = function (form) { 810 - var formData=new FormData(form);811 - var select=form.down('#import-calendar-parent');812 - varinput=form.down('#import-ical-file-input');813 - if(input.files[0].size<input.dataset.maxFileSize){850 + var startUploading = function (form, calId) { 851 + var input = form.down(`#import-ical-file-input-${calId}`); 852 + var inputFile = input.files[0]; 853 + if (inputFile && inputFile.size < input.dataset.maxFileSize) { 854 + var select = form.down(`#import-calendar-parent-${calId}`); 814 814 var params = {}; 815 815 params[select.name] = select.value; 816 - formData.action = form.action + "?" + $.param(params);857 + let action = form.action + "?" + $.param(params); 817 817 // Create XMLHttpRequest object and POST the data 818 - var request = this.request = new XMLHttpRequest(); 819 - request.open('POST', formData.action); 820 - request.send(formData); 821 - checkImportJob(select.value); 859 + var request = new XMLHttpRequest(); 860 + request.open('POST', action); 861 + request.onload = function () { 862 + if (request.status === 202 || request.status === 302) { 863 + checkImportJob(select.value); 864 + } else { 865 + new XWiki.widgets.Notification(l10n.get('import.error'),'error'); 866 + } 867 + }; 868 + request.send(inputFile); 822 822 } else { 823 - var notification = new XWiki.widgets.Notification(l10n.get('filetoolarge'), 'error'); 870 + var notification = new XWiki.widgets.Notification(l10n.get('import.filetoolarge'), 'error'); 824 824 } 825 - } 872 + }; 826 826 827 827 const checkImportJob = function(selectedCalendar) { 828 828 let documentReference = XWiki.Model.resolve('MoccaCalendar.Code.ImportJobResource', XWiki.EntityType.DOCUMENT); ... ... @@ -837,8 +837,8 @@ 837 837 {name: 'data', value: 'jobStatus'}, 838 838 {name: 'form_token', value: xwikiMeta.form_token} 839 839 ); 840 - var notification = new XWiki.widgets.Notification(l10n.get('inprogress'), 'inprogress'); 841 - $(' #import-calendar-file-button').prop('disabled', true);887 + var notification = new XWiki.widgets.Notification(l10n.get('import.inprogress'), 'inprogress'); 888 + $('.import-calendar-file-button').prop('disabled', true); 842 842 return Promise.resolve(new JobRunner({ 843 843 createStatusRequest: function(jobId) { 844 844 return { ... ... @@ -856,13 +856,13 @@ 856 856 throw new Error(response.error.message); 857 857 } else { 858 858 document.dispatchEvent(new Event('calendarImportCompleted')); 859 - notification.replace(new XWiki.widgets.Notification(l10n.get('done'),'done')); 906 + notification.replace(new XWiki.widgets.Notification(l10n.get('import.done'),'done')); 860 860 } 861 861 }).catch((reason) => { 862 - notification.replace(new XWiki.widgets.Notification(l10n.get('error'),'error')); 909 + notification.replace(new XWiki.widgets.Notification(l10n.get('import.error'),'error')); 863 863 return Promise.reject(reason); 864 864 }).finally(() => { 865 - $(' #import-calendar-file-button').prop('disabled', false);912 + $('.import-calendar-file-button').prop('disabled', false); 866 866 }); 867 867 }; 868 868 });
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -26,7 +26,12 @@ 26 26 margin-top: 0.6em; 27 27 } 28 28 .xdialog-box-moccacal-modal-popup { 29 + background-color: @modal-content-bg; 30 + border-color: @modal-content-border-color; 29 29 width: 600px; 32 + top: 3vh !important; 33 + bottom: 3vh !important; 34 + max-height: 94vh; 30 30 } 31 31 32 32 /* Make sure the date time picker is shown on top of the event modal. */ ... ... @@ -90,13 +90,45 @@ 90 90 } 91 91 92 92 .import-form select, 93 -.import-form #import-ical-file-input {98 +.import-form input { 94 94 width: 100%; 95 95 margin-bottom: 1.6em; 96 96 border-radius: 0.4em; 97 97 } 98 98 99 -.import-form #import-ical-file-input {104 +.import-form input { 100 100 padding: 0.6em 1em; 101 101 border: 1px solid #ccc; 102 102 } 108 + 109 +#recurrentDays dd { 110 + display: flex; 111 + gap: 0.3rem; 112 + margin-top: 1rem; 113 + justify-content: space-between; 114 +} 115 + 116 +#recurrentDays .xwiki-form-listclass { 117 + display: inline-flex; 118 + align-items: center; 119 + justify-content: center; 120 + padding: 0.8rem 1.1rem; 121 + background-color: @btn-default-bg; 122 + color: @btn-default-color; 123 + border-radius: 6px; 124 + cursor: pointer; 125 + user-select: none; 126 + transition: all 0.2s ease; 127 + position: relative; 128 +} 129 + 130 +#recurrentDays .xwiki-form-listclass input[type="checkbox"] { 131 + position: absolute; 132 + opacity: 0; 133 + pointer-events: none; 134 +} 135 + 136 +#recurrentDays .xwiki-form-listclass:has(input[type="checkbox"]:checked) { 137 + background-color: @btn-primary-bg; 138 + color: @btn-primary-color; 139 +} - Content Type
-
... ... @@ -1,1 +1,1 @@ 1 - CSS1 +LESS - Inhalt parsen
-
... ... @@ -1,0 +1,1 @@ 1 +Nein
- XWiki.WikiMacroClass[0]
-
- Makro-Code
-
... ... @@ -1,4 +1,11 @@ 1 1 {{velocity output="false"}} 2 +#set ($parameterMap = {}) 3 +#if ($themeDoc) 4 + ## If a theme doc is found, we add the theme to the ssx requests to make sure that the cache is properly updated. 5 + ## This code can be removed when the following platform issue is fixed: 6 + ## XWIKI-18668: The changes on the color theme are not taken into account for various ss*x resources 7 + #set ($discard = $parameterMap.put('colorTheme', $themeDocFullName)) 8 +#end 2 2 $xwiki.jsx.use("Calendar.FullCalendar", {'defer': false, 'minify': false}) 3 3 $xwiki.jsx.use("MoccaCalendar.Code.Macro", {'defer': false, 'v' : '2.7'}) 4 4 $xwiki.jsx.use("MoccaCalendar.Code.DatePickerExtension", {'defer': false}) ... ... @@ -5,8 +5,8 @@ 5 5 $xwiki.jsx.use("MoccaCalendar.MoccaCalendarEventSheet") 6 6 $xwiki.jsx.use("MoccaCalendar.Code.MoccaCalendarEventModificationClass") 7 7 #dateTimePicker_import() 8 -$xwiki.ssx.use("Calendar.FullCalendar") 9 -$xwiki.ssx.use("MoccaCalendar.Code.Macro") 15 +$xwiki.ssx.use("Calendar.FullCalendar", $parameterMap) 16 +$xwiki.ssx.use("MoccaCalendar.Code.Macro", $parameterMap) 10 10 #set($calcounter = $request.getAttribute('MoccaCalendar.Code.Macro:counter')) 11 11 #if(!$calcounter) #set($calcounter = 0) #else #set($calcounter = $calcounter + 1) #end 12 12 #set($discard = $request.setAttribute('MoccaCalendar.Code.Macro:counter', $calcounter)) ... ... @@ -153,7 +153,7 @@ 153 153 #end 154 154 155 155 #macro(importCalendarFileModal) 156 - <div class="modal fade" id="import-calendar-file" tabindex="-1" role="dialog"> 163 + <div class="modal fade" id="import-calendar-file-$calcounter" tabindex="-1" role="dialog"> 157 157 <div class="modal-dialog"> 158 158 <div class="modal-content"> 159 159 <div class="modal-header"> ... ... @@ -166,32 +166,46 @@ 166 166 #set ($escapedCalendarSpace = $escapetool.xml($doc.getSpace())) 167 167 #set ($escapedCalendarName = $escapetool.xml($doc.getDocumentReference().getName())) 168 168 #set ($actionURL = "$request.getContextPath()/rest/moccacalendar/import") 169 - <form class="xform" action="$actionURL" method="post"> 176 + #set ($xwikiCalendarDoc = $xwiki.getDocument($calendarDoc)) 177 + #set ($calendarObject = $xwikiCalendarDoc.getObject('MoccaCalendar.MoccaCalendarClass')) 178 + <form class="xform" action="${actionURL}" method="post"> 170 170 <div class="import-form"> 171 - <label for="import-calendar-parent"> 172 - $escapetool.xml($services.localization.render('MoccaCalendar.calendar'))</label> 173 - <select id="import-calendar-parent" name="parentCalendar"> 174 - #foreach ($item in $services.moccacalendar.getAllCalendars()) ## TODO: add filter here, see MOCCACAL-76 175 - #set ($itemdoc = $xwiki.getDocument($item)) 176 - #if ($!{itemdoc} && ${itemdoc.hasAccessLevel("edit")}) 177 - #set ($selected="") 178 - #if ($itemdoc.getId() == $doc.getId()) 179 - #set ($selected=" selected='selected'") 180 + #set ($calendarReferences = []) 181 + #if ($filter == 'wiki') 182 + #set ($calendarReferences = $services.moccacalendar.getAllCalendars()) 183 + #elseif ($filter == 'space') 184 + #set ($calendarReferences = $services.moccacalendar.getAllCalendarsInDocumentSpace($services.model.resolveDocument($calendarDoc))) 185 + #end 186 + #if ($calendarReferences.size() > 0) 187 + <label for="import-calendar-parent-${calcounter}"> 188 + $escapetool.xml($services.localization.render('MoccaCalendar.calendar'))</label> 189 + <select id="import-calendar-parent-${calcounter}" name="parentCalendar"> 190 + #foreach ($item in $calendarReferences) 191 + #set ($itemdoc = $xwiki.getDocument($item)) 192 + #if ($!{itemdoc} && ${itemdoc.hasAccessLevel("edit")}) 193 + #set ($selected="") 194 + #if ($itemdoc.getId() == $doc.getId()) 195 + #set ($selected=" selected='selected'") 196 + #end 197 + <option value="$escapetool.xml($services.model.serialize($itemdoc.getDocumentReference(),'default'))"$selected> 198 + $itemdoc.getDisplayTitle()</option> 180 180 #end 181 - <option value="$escapetool.html($itemdoc.getFullName())"$selected> 182 - $itemdoc.getDisplayTitle()</option> 183 183 #end 184 - #end 185 - </select> 186 - <label for="import-ical-file-input">$escapetool.xml($services.localization.render( 201 + </select> 202 + #else 203 + <select id="import-calendar-parent-${calcounter}" name="parentCalendar" hidden> 204 + <option value="$escapetool.xml($services.model.serialize($services.model.resolveDocument($calendarDoc),'default'))" selected></option> 205 + </select> 206 + #end 207 + <label for="import-ical-file-input-${calcounter}">$escapetool.xml($services.localization.render( 187 187 'MoccaCalendar.import.modal.file.label'))</label> 188 - <input type="file" id="import-ical-file-input" accept=".ics" name="importedfile" 209 + <input type="file" id="import-ical-file-input-${calcounter}" accept=".ics" name="importedfile" 189 189 data-max-file-size="$!escapetool.xml($xwiki.getSpacePreference('upload_maxsize'))"> 190 190 </div> 191 191 </form> 192 192 </div> 193 193 <div class="modal-footer"> 194 - <input type="button" class="btn btn-primary "id="import-calendar-file-button"215 + <input type="button" class="btn btn-primary import-calendar-file-button" data-calid="${calcounter}" 195 195 value="$escapetool.xml($services.localization.render('MoccaCalendar.import.modal.button.start'))"> 196 196 <input type="button" class="btn btn-default" 197 197 value="$escapetool.xml($services.localization.render('cancel'))" data-dismiss="modal"> ... ... @@ -200,6 +200,16 @@ 200 200 </div> 201 201 </div> 202 202 #end 224 +#macro (addCalendarObject $docRef) 225 + {{html clean=false wiki=true}} 226 + <input type="hidden" id="add-calendar-object" data-target="$docRef"> 227 + 228 + {{info cssClass="add-calendar-object-container"}} 229 + $escapetool.xml($services.localization.render('rendering.macro.moccacalendar.addObject.description')) 230 + [[**$escapetool.xml($services.localization.render('rendering.macro.moccacalendar.addObject.button'))**>>$docRef]] 231 + {{/info}} 232 + {{/html}} 233 +#end 203 203 {{/velocity}} 204 204 205 205 {{velocity}} ... ... @@ -262,12 +262,18 @@ 262 262 #if (!$services.licensing.licensor.hasLicensureForEntity($mainReference)) 263 263 {{missingLicenseMessage extensionName="moccacalendar.extension.name"/}} 264 264 #else 265 -#if($xcontext.action=='view'){{html clean="false" wiki="false"}} 296 +#if($xcontext.action=='view') 297 +#set ($xwikiCalendarDoc = $xwiki.getDocument($calendarDoc)) 298 +#set ($calendarObject = $xwikiCalendarDoc.getObject('MoccaCalendar.MoccaCalendarClass')) 299 +#if ($filter == 'page' && !$calendarObject) 300 + #addCalendarObject($calendarDoc) 301 +#end 302 +{{html clean="false" wiki="false"}} 266 266 #if($canCreateEvents) 267 267 ## create event link 268 268 <div class="calendar-buttons"> 269 269 <span class="buttonwrapper"> 270 -<button data-toggle="modal" data-target="#import-calendar-file" 307 +<button data-toggle="modal" data-target="#import-calendar-file-$calcounter" 271 271 title="$escapetool.xml($services.localization.render('MoccaCalendar.calendarevent.import.title'))"> 272 272 $escapetool.html($services.localization.render('MoccaCalendar.calendarevent.import'))</button> 273 273 <button class="btn btn-success" id="calendar${calcounter}-btn"><span class="glyphicon glyphicon-plus"></span> $escapetool.html($services.localization.render('MoccaCalendar.calendarevent.create'))</button> ... ... @@ -448,7 +448,7 @@ 448 448 }); 449 449 jQuery('#calendar${calcounter}-btn').click( function(e) { calendarHelper.showCreateEvent(); e.preventDefault(); }); 450 450 // helper to be used in callback above 451 -#set($newPageParams = "template=MoccaCalendar.MoccaCalendarEventTemplate&parentFROM=${escapetool.url($calendarDoc)}&form_token=${services.csrf.getToken()}&ocalcaction=create&disabled=$disableCreationEvent") 488 +#set($newPageParams = "template=MoccaCalendar.MoccaCalendarEventTemplate&parentFROM=${escapetool.url($calendarDoc)}&calendarParentFilter=${escapetool.url($filter)}&form_token=${services.csrf.getToken()}&ocalcaction=create&disabled=$disableCreationEvent") 452 452 #set($randomDocUrl = $xwiki.getURL("randomPage${util.generateRandomString(10)}",'edit',$newPageParams)) 453 453 #set($updateUrlParams="?xpage=plain&outputSyntax=plain&calendarDoc=${escapetool.url(${calendarDoc})}&") 454 454 var calendarHelper = new XWiki.MoccaCalendar.Helper(calendar, ... ... @@ -465,9 +465,9 @@ 465 465 }); 466 466 }); 467 467 </script> 505 +#importCalendarFileModal 468 468 #if($calcounter == 0) 469 469 #showDeleteEventsModal 470 - #importCalendarFileModal 471 471 #end 472 472 {{/html}} 473 473 #else ## of #if($xcontext.action=='view')