Changes for page LiveTable View Sheet
Last modified by Сергей Коршунов on 2025/05/01 21:19
From version 2.1
edited by Сергей Коршунов
on 2022/03/08 16:59
on 2022/03/08 16:59
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/14.1]
To version 4.1
edited by Сергей Коршунов
on 2023/01/17 14:14
on 2023/01/17 14:14
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/14.10.3]
Summary
-
Page properties (1 modified, 0 added, 0 removed)
-
Objects (1 modified, 0 added, 0 removed)
Details
- Page properties
-
- Content
-
... ... @@ -11,16 +11,8 @@ 11 11 ## Display the live table only if it was generated. 12 12 #if ($doc.content.length() > 0) 13 13 = $services.localization.render('platform.appwithinminutes.appLiveTableHeading') = 14 - ## We don't use the Include macro (with empty reference) because we want the content to be executed with the rights 15 - ## of the current document rather than the rights of the sheet. This is important because the user can modify the 16 - ## content of the application home page which means we could execute untrusted content with the rights of the sheet. 17 - ## Ideally we should use the Display macro with a parameter to disable the sheet, but we don't have this parameter. 18 - ## We don't clean the HTML content because getRenderedContent() should produce clean HTML, unless the user has 19 - ## disabled the HTML cleaning, in which case he will get what he asked for. Note that one good reason to disable 20 - ## HTML cleaning is to preserve the whitespaces in the attribute values. 21 - ## Escape {{ in the rendered content to be sure that the HTML macro is not closed unintentionally. 22 - {{html clean="false"}}$doc.getRenderedContent($doc.content, 23 - $doc.syntax.toIdString()).replace('{{', '&#123;&#123;'){{/html}} 14 + 15 + {{include reference="" author="target"/}} 24 24 #end 25 25 #end 26 26 ... ... @@ -122,23 +122,30 @@ 122 122 data-backdrop="static" data-keyboard="false"> 123 123 <div class="modal-dialog" role="document"> 124 124 <form class="modal-content xform"> 125 - <div class="modal-header"> 126 - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> 127 - <span aria-hidden="true">×</span> 128 - </button> 129 - <span class="modal-title" id="renameAppModal-label">Rename Application</span> 130 - </div> 131 - <div class="modal-body"> 132 - #renameAppModalBody 133 - </div> 134 - <div class="modal-footer"> 135 - <button type="button" class="btn btn-default" data-dismiss="modal"> 136 - $escapetool.xml($services.localization.render('cancel')) 137 - </button> 138 - <button type="submit" class="btn btn-primary" disabled="disabled"> 139 - $escapetool.xml($services.localization.render('core.rename.submit')) 140 - </button> 141 - </div> 117 + ## The fieldset allows us to disable and enable the entire form quickly and easy. 118 + <fieldset> 119 + <div class="modal-header"> 120 + <button type="button" class="close" data-dismiss="modal" 121 + title="$escapetool.xml($services.localization.render('appWithinMinutes.renameApp.close'))" 122 + aria-label="$escapetool.xml($services.localization.render('appWithinMinutes.renameApp.close'))"> 123 + <span aria-hidden="true">×</span> 124 + </button> 125 + <span class="modal-title" id="renameAppModal-label"> 126 + $escapetool.xml($services.localization.render('appWithinMinutes.renameApp.label')) 127 + </span> 128 + </div> 129 + <div class="modal-body"> 130 + #renameAppModalBody 131 + </div> 132 + <div class="modal-footer"> 133 + <button type="button" class="btn btn-default" data-dismiss="modal"> 134 + $escapetool.xml($services.localization.render('cancel')) 135 + </button> 136 + <button type="submit" class="btn btn-primary" disabled="disabled"> 137 + $escapetool.xml($services.localization.render('core.rename.submit')) 138 + </button> 139 + </div> 140 + </fieldset> 142 142 </form> 143 143 </div> 144 144 </div>
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -58,7 +58,7 @@ 58 58 /** 59 59 * Rename Application 60 60 */ 61 -require(['jquery', 'bootstrap'], function($) { 61 +require(['jquery', 'bootstrap', 'xwiki-form-validation-async'], function($) { 62 62 #set ($currentDocReference = $xwiki.getDocument($request.currentApp).getDocumentReference()) 63 63 // if we cannot find any extension related to this page app, it's not part of an extension. 64 64 var isNotAnExtension = $services.extension.xar.getInstalledExtensions($currentDocReference).isEmpty(); ... ... @@ -77,7 +77,6 @@ 77 77 // Form validation. 78 78 var appNameInput = $('#renameAppTitle'); 79 79 var appParentInput = $('#renameAppParentReference'); 80 - var submitButton = renameAppModal.find('.btn-primary[type="submit"]'); 81 81 82 82 var appNameEmptyError = renameAppModal.find('.appNameEmptyError'); 83 83 var pageExistsError = renameAppModal.find('.pageExistsError'); ... ... @@ -100,49 +100,44 @@ 100 100 101 101 var startValidation = function() { 102 102 if (appNameInput.val() === '') { 103 - en dValidation(appNameEmptyError);102 + return Promise.reject(appNameEmptyError); 104 104 } else { 105 105 var newAppHomePage = getNewAppHomePage(); 106 106 if (newAppHomePage.documentReference.equals(XWiki.currentDocument.documentReference)) { 107 - en dValidation(pageExistsError);106 + return Promise.reject(pageExistsError); 108 108 } else { 109 - $.ajax({ 110 - type: 'HEAD', 111 - url: newAppHomePage.getURL() 112 - }).then(endValidation.bind(null, pageExistsError), response => { 113 - if (response.status === 404) { 114 - $.ajax({ 115 - type: 'HEAD', 116 - url: newAppHomePage.getURL('edit') 117 - }).then( 118 - () => endValidation(), 119 - () => endValidation(locationForbiddenError) 120 - ); 121 - } else if (response.status === 403) { 122 - endValidation(locationForbiddenError); 123 - } else { 124 - endValidation(); 125 - } 108 + return new Promise((resolve, reject) => { 109 + $.ajax({ 110 + type: 'HEAD', 111 + url: newAppHomePage.getURL() 112 + }).then(reject.bind(null, pageExistsError), response => { 113 + if (response.status === 404) { 114 + $.ajax({ 115 + type: 'HEAD', 116 + url: newAppHomePage.getURL('edit') 117 + }).then( 118 + () => resolve(), 119 + () => reject(locationForbiddenError) 120 + ); 121 + } else if (response.status === 403) { 122 + reject(locationForbiddenError); 123 + } else { 124 + resolve(); 125 + } 126 + }); 126 126 }); 127 127 } 128 128 } 129 129 }; 130 130 131 - var endValidation = function(error) { 132 - if (error) { 133 - error.show(); 134 - } 135 - appNameInput.removeClass('loading'); 136 - submitButton.prop('disabled', !!error); 137 - }; 138 - 139 - var validationTimeout; 140 140 var scheduleValidation = function() { 141 - clearTimeout(validationTimeout);133 + // Hide all error messages before starting the asynchronous validation. 142 142 renameAppModal.find('.xErrorMsg').hide(); 143 - appNameInput.addClass('loading'); 144 - submitButton.prop('disabled', true); 145 - validationTimeout = setTimeout(startValidation, 500); 135 + appNameInput.addClass('loading').validateAsync(startValidation, 500, 'awm').catch((error) => { 136 + error.show(); 137 + }).finally(() => { 138 + appNameInput.removeClass('loading'); 139 + }); 146 146 }; 147 147 148 148 appNameInput.add(appParentInput).on('input', scheduleValidation); ... ... @@ -191,13 +191,13 @@ 191 191 192 192 var renameApp = function(data) { 193 193 // Disable the form to prevent it from being submitted twice. 194 - renameAppModal.find(' :input').prop('disabled', true);188 + renameAppModal.find('fieldset').prop('disabled', true); 195 195 var notification = new XWiki.widgets.Notification( 196 196 $jsontool.serialize($services.localization.render('appWithinMinutes.renameApp.inProgress')), 197 197 'inprogress' 198 198 ); 199 199 var renameAppURL = new XWiki.Document('RenameApplication', 'AppWithinMinutes').getURL('get'); 200 - $.post(renameAppURL, data).then(updateAppHomePage).then(function() { 194 + Promise.resolve($.post(renameAppURL, data)).then(updateAppHomePage).then(function() { 201 201 renameAppModal.modal('hide'); 202 202 notification.replace(new XWiki.widgets.Notification( 203 203 $jsontool.serialize($services.localization.render('appWithinMinutes.renameApp.done')), ... ... @@ -214,7 +214,7 @@ 214 214 )); 215 215 }).finally(function() { 216 216 // Re-enable the form. 217 - renameAppModal.find(' :input').prop('disabled', false);211 + renameAppModal.find('fieldset').prop('disabled', false); 218 218 }); 219 219 }; 220 220