Changes for page Create Application
Last modified by Ludovic Dubost on 2024/07/22 15:51
From version 5.1
edited by Ludovic Dubost
on 2015/11/28 14:58
on 2015/11/28 14:58
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-7.3]
To version 2.1
edited by Thomas Mortagne
on 2014/09/29 12:41
on 2014/09/29 12:41
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-6.2]
Summary
-
Page properties (2 modified, 0 added, 0 removed)
-
Objects (2 modified, 0 added, 0 removed)
Details
- Page properties
-
- Author
-
... ... @@ -1,1 +1,1 @@ 1 -xwiki:XWiki. ludovic1 +xwiki:XWiki.ThomasMortagne - Content
-
... ... @@ -1,7 +1,5 @@ 1 1 {{include reference="AppWithinMinutes.WizardStep"/}} 2 2 3 -{{template name="locationPicker_macros.vm" /}} 4 - 5 5 {{velocity output="false"}} 6 6 #macro(showStep) 7 7 {{html wiki="true"}} ... ... @@ -15,131 +15,86 @@ 15 15 (% class="description" %)$services.localization.render("platform.appwithinminutes.wizardStep${index}Description") 16 16 #end 17 17 ))) 18 - <form action="$doc.getURL()" method="post" class="xform wizard-body"> 19 - #locationPicker({ 20 - 'id': 'app', 21 - 'title': { 22 - 'label': 'platform.appwithinminutes.appNameLabel', 23 - 'hint': 'platform.appwithinminutes.appNameHint', 24 - 'name': 'appName' 25 - }, 26 - 'preview': { 27 - 'label': 'appWithinMinutes.createApp.location.label', 28 - 'hint': 'appWithinMinutes.createApp.location.hint' 29 - }, 30 - 'parent': { 31 - 'label': 'appWithinMinutes.createApp.parent.label', 32 - 'hint': 'appWithinMinutes.createApp.parent.hint', 33 - 'name': 'appParentReference', 34 - 'reference': $doc.documentReference.wikiReference, 35 - 'placeholder': 'appWithinMinutes.createApp.parent.placeholder' 36 - } 37 - }) 38 - <div class="appName-preview"></div> 16 + <form action="" method="post" class="xform wizard-body"> 17 + ; <label for="appName">$services.localization.render('platform.appwithinminutes.appNameLabel')</label> 18 + (% class="xHint" %)$services.localization.render('platform.appwithinminutes.appNameHint') 19 + : <input type="text" id="appName" name="appName" /> 39 39 #appWizardFooter(1) 40 40 </form> 41 41 {{/html}} 42 42 #end 43 43 44 -#macro (processStep) 25 +#macro(getAppDescriptor $appName) 26 + #set($appDescriptorClassName = 'AppWithinMinutes.LiveTableClass') 27 + #set($appDescriptorStatement = "from doc.object($appDescriptorClassName) as obj where doc.space = :space") 28 + #set($appDescriptors = $services.query.xwql($appDescriptorStatement).bindValue('space', $appName).execute()) 29 + #if($appDescriptors.size() > 0) 30 + #set($appDescriptor = $xwiki.getDocument($appDescriptors.get(0))) 31 + #end 32 +#end 33 + 34 +#macro(processStep) 45 45 ## Check if the application already exists. 46 - #getAppReference 47 - #getAppDescriptor($appReference) 48 - #if ($appDescriptor) 36 + #getAppDescriptor($request.appName) 37 + #if($appDescriptor) 49 49 ## Edit an existing application. Use the configured class name. 50 - #set appClassRef = $appDescriptor.getObject($appDescriptorClassName).getValue('class'))51 - ## The class reference is relative to the document holding the application descriptor. 52 - #set appClassRef = $services.model.resolveDocument($appClassRef, 'explicit', $appDescriptor.documentReference))39 + #set($classStringRef = $appDescriptor.getObject($appDescriptorClassName).getProperty('class').value) 40 + ## The class string reference is relative to the document holding the application descriptor. 41 + #set($classRef = $services.model.resolveDocument($classStringRef, 'explicit', $appDescriptor.documentReference)) 53 53 #else 54 54 ## Create a new application. Use the default class name. 55 - #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 56 - #set ($appClassRef = $services.model.createDocumentReference("$!{appReference.name}Class", $appCodeRef)) 44 + #set($classRef = $services.model.createDocumentReference($doc.wiki, "${request.appName}Code", "#toXMLName($request.appName)Class")) 57 57 #end 58 - #set ($queryString = {'wizard': true}) 59 - #if (!$xwiki.exists($appClassRef)) 60 - #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 61 - #set ($discard = $queryString.putAll({ 62 - 'editor': 'inline', 63 - 'template': 'AppWithinMinutes.ClassTemplate', 64 - 'parent': $services.model.serialize($appHomeRef), 65 - 'title': "$appReference.name Class" 66 - })) 46 + #set($queryString = 'wizard=true') 47 + #if(!$xwiki.exists($classRef)) 48 + #set($classTitle = "$request.appName Class") 49 + #set($queryString = "$queryString&editor=inline&template=AppWithinMinutes.ClassTemplate&parent=${request.appName}.WebHome&title=$escapetool.url($classTitle)") 67 67 #end 68 - $response.sendRedirect($xwiki.getURL($ appClassRef, 'edit', $escapetool.url($queryString)))51 + $response.sendRedirect($xwiki.getURL($classRef, 'edit', $queryString)) 69 69 #end 70 70 71 -#macro (validateAppName) 72 - #getAppReference 73 - #if (!$appReference) 74 - (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameEmptyError') 54 +#macro(validateAppName $appName) 55 + #getAppDescriptor("$!appName") 56 + #if($appDescriptor) 57 + ## Edit an existing application. 58 + #set($appHomeRef = $appDescriptor.documentReference) 59 + #set($classStringRef = $appDescriptor.getObject($appDescriptorClassName).getProperty('class').value) 60 + ## The class string reference is relative to the document holding the application descriptor. 61 + #set($appClassRef = $services.model.resolveDocument($classStringRef, 'explicit', $appDescriptor.documentReference)) 75 75 #else 76 - #getAppDescriptor($appReference) 77 - #if ($appDescriptor) 78 - ## Edit an existing application. 79 - #set ($appDescriptorObj = $appDescriptor.getObject($appDescriptorClassName)) 80 - #set ($appClassRef = $appDescriptorObj.getValue('class')) 81 - ## The class reference is relative to the document holding the application descriptor. 82 - #set ($appClassRef = $services.model.resolveDocument($appClassRef, 'explicit', $appDescriptor.documentReference)) 83 - #set ($appDataRef = $appDescriptorObj.getValue('dataSpace')) 84 - ## The data space reference is relative to the document holding the application descriptor. 85 - #set ($appDataRef = $services.model.resolveSpace($appDataRef, 'explicit', $appDescriptor.documentReference)) 86 - #else 87 - ## Create a new application. 88 - #set ($appDataRef = $services.model.createSpaceReference('Data', $appReference)) 89 - #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 90 - #set ($appClassRef = $services.model.createDocumentReference("$!{appReference.name}Class", $appCodeRef)) 63 + ## Create a new application. 64 + #set($className = "#toXMLName($appName)") 65 + #if($className == '') 66 + (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameInvalidClassNameError') 91 91 #end 92 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewHomePageUrlLabel') 93 - : {{{$!xwiki.getDocument($appReference).externalURL}}} 94 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewDataSpaceLabel') 95 - : {{html clean="false"}}#hierarchy($appDataRef){{/html}} 96 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewCodeSpaceLabel') 97 - : {{html clean="false"}}#hierarchy($appClassRef.parent){{/html}} 98 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewClassReferenceLabel') 99 - : {{html clean="false"}}#hierarchy($appClassRef){{/html}} 100 - #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 101 - #if ($appDescriptor || $xwiki.exists($appHomeRef) || $xwiki.exists($appClassRef)) 102 - 103 - {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}} 104 - #end 68 + #set($appHomeRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome')) 69 + #set($appClassRef = $services.model.createDocumentReference($doc.wiki, "$!{appName}Code", "$!{className}Class")) 105 105 #end 106 -#end 71 + #set($appHomeURL = $stringtool.removeEnd($xwiki.getDocument($appHomeRef).getExternalURL(), 'WebHome')) 72 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewHomePageUrlLabel') 73 + : {{{$!appHomeURL}}} 74 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewDataSpaceLabel') 75 + : {{{$doc.wiki}}} » {{{$appName}}} 76 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewCodeSpaceLabel') 77 + : {{{$doc.wiki}}} » {{{${appName}Code}}} 78 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewClassReferenceLabel') 79 + : {{{$appClassRef.wikiReference.name}}} » {{{$appClassRef.lastSpaceReference.name}}} » {{{$appClassRef.name}}} 80 + #if($appDescriptor || $xwiki.exists($appHomeRef) || $xwiki.exists($appClassRef)) 107 107 108 -#macro (getAppReference) 109 - #if ($request.resolve == 'true') 110 - #set ($appReference = $services.model.resolveSpace($request.appName)) 111 - #elseif ("$!request.appName" != '') 112 - #set ($parentReference = $doc.documentReference.wikiReference) 113 - #if ("$!request.appParentReference" != '') 114 - #set ($parentReference = $services.model.resolveSpace($request.appParentReference)) 115 - #end 116 - #set ($appReference = $services.model.createSpaceReference($request.appName, $parentReference)) 117 - #else 118 - #set ($appReference = $NULL) 82 + {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}} 119 119 #end 120 120 #end 121 - 122 -#macro (getAppDescriptor $appReference) 123 - #set ($appDescriptorClassName = 'AppWithinMinutes.LiveTableClass') 124 - #set ($appDescriptorStatement = "from doc.object($appDescriptorClassName) as obj where doc.space = :space") 125 - #set ($localSpaceReference = $services.model.serialize($appReference, 'local')) 126 - #set ($appDescriptors = $services.query.xwql($appDescriptorStatement).bindValue('space', $localSpaceReference).execute()) 127 - #if ($appDescriptors.size() > 0) 128 - #set ($appDescriptor = $xwiki.getDocument($appDescriptors.get(0))) 129 - #end 130 -#end 131 131 {{/velocity}} 132 132 133 133 {{velocity}} 134 -#if 135 - #if 136 - #validateAppName 88 +#if("$!request.appName" != '') 89 + #if($xcontext.action == 'get') 90 + #validateAppName($request.appName) 137 137 #else 138 138 ## CSRF protection is not needed because this step only redirects to the next one passing data in the query string. 139 - #processStep 93 + #processStep() 140 140 #end 141 141 #else 142 - #showStep 96 + #showStep() 143 143 #end 144 -#set ($docextras = []) 145 145 {{/velocity}}
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,53 +1,89 @@ 1 -require(['jquery'], function($) { 2 - var appNameInput = $('input[name="appName"]'); 3 - var appParentInput = $('input[name="appParentReference"]'); 4 - var preview = $('.appName-preview'); 5 - var submitButton = $('#wizard-next').prop('disabled', true); 1 +var XWiki = (function (XWiki) { 6 6 7 - var errorMessage = appNameInput.closest('dd').prev('dt').find('.xErrorMsg'); 8 - if (errorMessage.size() == 0) { 9 - errorMessage = $(document.createElement('span')).addClass('xErrorMsg').hide().appendTo(errorMessage.addBack()); 3 +XWiki.DeferredUpdater = Class.create({ 4 + initialize : function(updatable) { 5 + this.elapsedHandler = updatable.onUpdate.bind(updatable); 6 + this.updatable = updatable; 7 + }, 8 + deferUpdate : function() { 9 + if (this.timer) { 10 + clearTimeout(this.timer); 11 + } 12 + this.timer = setTimeout(this.elapsedHandler, 500); 10 10 } 14 +}); 11 11 12 - var toggleValidationError = function(message) { 16 +XWiki.AppNameValidator = Class.create({ 17 + initialize : function(input, submitButton) { 18 + this.input = input; 19 + this.deferredUpdater = new XWiki.DeferredUpdater(this); 20 + var updateScheduler = this._scheduleUpdate.bindAsEventListener(this); 21 + ['keypress', 'paste', 'cut'].each(function(eventType) { 22 + input.observe(eventType, updateScheduler); 23 + }.bind(this)); 24 + 25 + this.submitButton = submitButton; 26 + this.submitButton.observe('click', this._onSubmit.bindAsEventListener(this)); 27 + 28 + this.preview = new Element('div', {'class': 'appName-preview'}); 29 + this.input.insert({after: this.preview}); 30 + 31 + var previousDT = input.up('dd').previous(); 32 + this.errorMessage = previousDT.down('xErrorMsg'); 33 + if (!this.errorMessage) { 34 + this.errorMessage = new Element('span', {'class': 'xErrorMsg'}); 35 + previousDT.insert(this.errorMessage.hide()); 36 + } 37 + }, 38 + _onSubmit : function(event) { 39 + if (!this.input._validated) { 40 + event.stop(); 41 + this._scheduleUpdate(); 42 + } 43 + }, 44 + _scheduleUpdate : function(event) { 45 + if(!this.input._validated || [9, 13, 35, 36, 37, 38, 39, 40].indexOf(event.keyCode) < 0) { 46 + this.input._validated = false; 47 + this.deferredUpdater.deferUpdate(); 48 + } 49 + }, 50 + _onValidate : function(response) { 51 + this.preview.removeClassName('loading').update(response.responseText); 52 + var error = this.preview.down('.xErrorMsg'); 53 + this.input._validated = !error; 54 + this._showError(error ? error.remove().firstChild.nodeValue : ''); 55 + }, 56 + _showError : function(message) { 13 13 if (message) { 14 - appNameInput.addClass('xErrorField').focus();15 - errorMessage.te xt(message).show();58 + this.input.addClassName('xErrorField').focus(); 59 + this.errorMessage.update(message.escapeHTML()).show(); 16 16 } else { 17 - appNameInput.removeClass('xErrorField');18 - errorMessage.hide(); 61 + this.input.removeClassName('xErrorField'); 62 + this.errorMessage.hide(); 19 19 } 20 - }; 21 - 22 - var updatePreview = function(content) { 23 - preview.removeClass('loading').html(content); 24 - var error = preview.find('.xErrorMsg'); 25 - submitButton.prop('disabled', error.size() > 0); 26 - toggleValidationError(error.remove().text()); 27 - }; 28 - 29 - var fetchPreviewUpdate = function() { 30 - if (appNameInput.val() == '') { 31 - updatePreview('<span class="xErrorMsg">$escapetool.javascript($services.localization.render("platform.appwithinminutes.appNameEmptyError"))</span>'); 64 + }, 65 + onUpdate : function() { 66 + if (this.input.value == '') { 67 + this._onValidate({ 68 + responseText: '<span class="xErrorMsg">$escapetool.javascript($services.localization.render('platform.appwithinminutes.appNameEmptyError'))</span>' 69 + }); 32 32 } else { 33 - preview.addClass('loading'); 34 - $.get(XWiki.currentDocument.getURL('get'), submitButton.closest('form').serialize(), updatePreview); 71 + this.preview.addClassName('loading'); 72 + new Ajax.Request('$doc.getURL('get')', { 73 + method: 'get', 74 + parameters: {'appName': this.input.value}, 75 + onSuccess: this._onValidate.bind(this) 76 + }); 35 35 } 36 - }; 78 + } 79 +}); 37 37 38 - var previewTimeout;39 - var schedulePreviewUpdate =function(){40 - clearTimeout(previewTimeout);41 - submitButton.prop('disabled', true);42 - setTimeout(fetchPreviewUpdate, 500);43 - };81 +function init() { 82 + var appNameInput = $('appName'); 83 + appNameInput && new XWiki.AppNameValidator(appNameInput, $('wizard-next')); 84 + return !!appNameInput; 85 +} 86 +(XWiki.domIsLoaded && init()) || document.observe('xwiki:dom:loaded', init); 44 44 45 - appNameInput.add(appParentInput) 46 - .on('input', schedulePreviewUpdate) 47 - .keyup(function(event) { 48 - // Show the error message if the user presses Enter before typing anything. 49 - if (event.which == 13 && appNameInput.val() == '' && !appNameInput.hasClass('xErrorField')) { 50 - fetchPreviewUpdate(); 51 - } 52 - }); 53 -}); 88 +return XWiki; 89 +}(XWiki || {}));
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -24,6 +24,10 @@ 24 24 margin-bottom: 1em; 25 25 } 26 26 27 +.appName-preview dl tt { 28 + color: $theme.textColor; 29 +} 30 + 27 27 .appName-preview dt { 28 28 font-weight: normal; 29 29 margin-top: 1em; ... ... @@ -32,8 +32,3 @@ 32 32 .appName-preview dt:after { 33 33 content: ":" 34 34 } 35 - 36 -.appName-preview .breadcrumb { 37 - background-color: transparent; 38 - padding: 0; 39 -} - Content Type
-
... ... @@ -1,1 +1,0 @@ 1 -CSS