Changes for page Create Application
Last modified by Ludovic Dubost on 2024/07/22 15:51
From 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]
To version 7.1
edited by Ludovic Dubost
on 2019/05/20 19:03
on 2019/05/20 19:03
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/11.3]
Summary
-
Page properties (3 modified, 0 added, 0 removed)
-
Objects (2 modified, 0 added, 0 removed)
Details
- Page properties
-
- Author
-
... ... @@ -1,1 +1,1 @@ 1 -xwiki:XWiki. ThomasMortagne1 +xwiki:XWiki.ludovic - Syntax
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki 2. 01 +XWiki 2.1 - Content
-
... ... @@ -1,98 +1,150 @@ 1 -{{include reference="AppWithinMinutes. WizardStep"/}}1 +{{include reference="AppWithinMinutes.VelocityMacros"/}} 2 2 3 +{{velocity}} 4 +#if ($request.wizard == 'true') 5 + {{include reference="AppWithinMinutes.WizardStep"/}} 6 +#end 7 +{{/velocity}} 8 + 9 +{{template name="locationPicker_macros.vm" /}} 10 + 3 3 {{velocity output="false"}} 4 -#macro(showStep) 5 - {{html wiki="true"}} 6 - #appWizardHeader(1) 7 - (% class="wizard-help" %) 8 - ((( 9 - **$services.localization.render('platform.appwithinminutes.wizardStepHelpTitle')** $services.localization.render('platform.appwithinminutes.wizardStepHelpDescription') 10 - (% class="steps vertical" %) 11 - #foreach($index in [1, 2, 3]) 12 - * (% class="number" %)$index(%%) (% class="name" %)$services.localization.render("platform.appwithinminutes.wizardStep${index}Name")(%%) 13 - (% class="description" %)$services.localization.render("platform.appwithinminutes.wizardStep${index}Description") 14 - #end 15 - ))) 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" /> 12 +#macro (showStep) 13 + #appWizardHeader('name') 14 + <div class="wizard-help"> 15 + <p> 16 + <strong>$services.localization.render('platform.appwithinminutes.wizardStepHelpTitle')</strong> 17 + $services.localization.render('platform.appwithinminutes.wizardStepHelpDescription') 18 + </p> 19 + <ul class="steps vertical"> 20 + #foreach($step in $awmSteps) 21 + <li> 22 + <span class="number">$mathtool.add($foreach.index, 1)</span> 23 + <span class="name">$services.localization.render("appWithinMinutes.wizardStep.${step}.name")</span> 24 + <span class="description">$services.localization.render("appWithinMinutes.wizardStep.${step}.description")</span> 25 + </li> 26 + #end 27 + </ul> 28 + </div> 29 + <form action="$doc.getURL()" method="post" class="xform wizard-body"> 30 + #locationPicker({ 31 + 'id': 'app', 32 + 'title': { 33 + 'label': 'platform.appwithinminutes.appNameLabel', 34 + 'hint': 'platform.appwithinminutes.appNameHint', 35 + 'name': 'appName' 36 + }, 37 + 'preview': { 38 + 'label': 'appWithinMinutes.createApp.location.label', 39 + 'hint': 'appWithinMinutes.createApp.location.hint' 40 + }, 41 + 'parent': { 42 + 'label': 'appWithinMinutes.createApp.parent.label', 43 + 'hint': 'appWithinMinutes.createApp.parent.hint', 44 + 'name': 'appParentReference', 45 + 'reference': $doc.documentReference.wikiReference, 46 + 'placeholder': 'appWithinMinutes.createApp.parent.placeholder' 47 + } 48 + }) 49 + <div class="appName-preview"></div> 20 20 #appWizardFooter(1) 21 21 </form> 22 - {{/html}} 23 23 #end 24 24 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) 54 +#macro (processStep) 35 35 ## Check if the application already exists. 36 - #getApp Descriptor($request.appName)37 - # if($appDescriptor)38 - # Editanexisting application. Use the configured class name.39 - # set($classStringRef= $appDescriptor.getObject($appDescriptorClassName).getProperty('class').value)40 - # # Theclassstring referenceis relative to the document holding the application descriptor.41 - #set($ classRef = $services.model.resolveDocument($classStringRef, 'explicit', $appDescriptor.documentReference))56 + #getAppReference 57 + #getAppDescriptor($appReference) 58 + #if ($appDescriptor) 59 + ## Edit an existing application. 60 + #getAppClassReference($appDescriptor) 61 + #set ($appClassRef = $classReference) 42 42 #else 43 43 ## Create a new application. Use the default class name. 44 - #set($classRef = $services.model.createDocumentReference($doc.wiki, "${request.appName}Code", "#toXMLName($request.appName)Class")) 64 + #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 65 + #set ($appClassRef = $services.model.createDocumentReference("$!{appReference.name}Class", $appCodeRef)) 45 45 #end 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 + #set ($queryString = {'wizard': true}) 68 + #if (!$xwiki.exists($appClassRef)) 69 + #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 70 + #set ($discard = $queryString.putAll({ 71 + 'template': 'AppWithinMinutes.ClassTemplate', 72 + 'parent': $services.model.serialize($appHomeRef), 73 + 'title': "$appReference.name Class" 74 + })) 50 50 #end 51 - $response.sendRedirect($xwiki.getURL($ classRef, 'edit', $queryString))76 + $response.sendRedirect($xwiki.getURL($appClassRef, 'edit', $escapetool.url($queryString))) 52 52 #end 53 53 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)) 79 +#macro (validateAppName) 80 + #getAppReference 81 + #if (!$appReference) 82 + <span class="xErrorMsg">$services.localization.render('platform.appwithinminutes.appNameEmptyError')</span> 62 62 #else 63 - ## Create a new application. 64 - #set($className = "#toXMLName($appName)") 65 - #if($className == '') 66 - (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameInvalidClassNameError') 84 + #getAppDescriptor($appReference) 85 + #if ($appDescriptor) 86 + ## Edit an existing application. 87 + #getAppClassReference($appDescriptor) 88 + #set ($appClassRef = $classReference) 89 + #else 90 + ## Create a new application. 91 + #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 92 + #set ($appClassRef = $services.model.createDocumentReference("$!{appReference.name}Class", $appCodeRef)) 67 67 #end 68 - #set($appHomeRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome')) 69 - #set($appClassRef = $services.model.createDocumentReference($doc.wiki, "$!{appName}Code", "$!{className}Class")) 94 + <dl> 95 + <dt>$services.localization.render('platform.appwithinminutes.appNamePreviewHomePageUrlLabel')</dt> 96 + <dd><pre>$!escapetool.xml($xwiki.getDocument($appReference).externalURL)</pre></dd> 97 + <dt>$services.localization.render('platform.appwithinminutes.appNamePreviewCodeSpaceLabel')</dt> 98 + <dd>#hierarchy($appClassRef.parent)</dd> 99 + </dl> 100 + #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 101 + #if ($appDescriptor || $xwiki.exists($appHomeRef) || $xwiki.exists($appClassRef)) 102 + <div class="box warningmessage"> 103 + $services.localization.render('platform.appwithinminutes.appNameIsUsedWarning') 104 + </div> 105 + #end 70 70 #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 +#end 81 81 82 - {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}} 109 +#macro (getAppReference) 110 + #if ($request.resolve == 'true') 111 + #set ($appReference = $services.model.resolveSpace($request.appName)) 112 + #elseif ("$!request.appName" != '') 113 + #set ($parentReference = $doc.documentReference.wikiReference) 114 + #if ("$!request.appParentReference" != '') 115 + #set ($parentReference = $services.model.resolveSpace($request.appParentReference)) 116 + #end 117 + #set ($appReference = $services.model.createSpaceReference($request.appName, $parentReference)) 118 + #else 119 + #set ($appReference = $NULL) 83 83 #end 84 84 #end 122 + 123 +#macro (getAppDescriptor $appReference) 124 + #set ($appDescriptorClassName = 'AppWithinMinutes.LiveTableClass') 125 + #set ($appDescriptorStatement = "from doc.object($appDescriptorClassName) as obj where doc.space = :space") 126 + #set ($localSpaceReference = $services.model.serialize($appReference, 'local')) 127 + #set ($appDescriptors = $services.query.xwql($appDescriptorStatement).bindValue('space', $localSpaceReference).execute()) 128 + #if ($appDescriptors.size() > 0) 129 + #set ($appDescriptor = $xwiki.getDocument($appDescriptors.get(0))) 130 + #else 131 + #set ($appDescriptor = $NULL) 132 + #end 133 +#end 85 85 {{/velocity}} 86 86 87 87 {{velocity}} 88 -#if("$!request.appName" != '') 89 - #if($xcontext.action == 'get') 90 - #validateAppName($request.appName) 137 +{{html clean="false"}} 138 +#if ("$!request.appName" != '') 139 + #if ($xcontext.action == 'get') 140 + #validateAppName 91 91 #else 92 92 ## CSRF protection is not needed because this step only redirects to the next one passing data in the query string. 93 - #processStep ()143 + #processStep 94 94 #end 95 -#else 96 - #showStep() 145 +#elseif ($request.wizard == 'true') 146 + #showStep 147 + #set ($displayDocExtra = false) 97 97 #end 149 +{{/html}} 98 98 {{/velocity}}
- XWiki.JavaScriptExtension[0]
-
- Code
-
... ... @@ -1,89 +1,53 @@ 1 -var XWiki = (function (XWiki) { 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); 2 2 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); 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()); 13 13 } 14 -}); 15 15 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) { 12 + var toggleValidationError = function(message) { 57 57 if (message) { 58 - this.input.addClassName('xErrorField').focus();59 - this.errorMessage.update(message.escapeHTML()).show();14 + appNameInput.addClass('xErrorField').focus(); 15 + errorMessage.text(message).show(); 60 60 } else { 61 - this.input.removeClassName('xErrorField');62 - this.errorMessage.hide();17 + appNameInput.removeClass('xErrorField'); 18 + errorMessage.hide(); 63 63 } 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 - }); 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>'); 70 70 } else { 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 - }); 33 + preview.addClass('loading'); 34 + $.get(XWiki.currentDocument.getURL('get'), submitButton.closest('form').serialize(), updatePreview); 77 77 } 78 - } 79 -}); 36 + }; 80 80 81 - functioninit() {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);38 + var previewTimeout; 39 + var schedulePreviewUpdate = function() { 40 + clearTimeout(previewTimeout); 41 + submitButton.prop('disabled', true); 42 + setTimeout(fetchPreviewUpdate, 500); 43 + }; 87 87 88 -return XWiki; 89 -}(XWiki || {})); 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 +});
- XWiki.StyleSheetExtension[0]
-
- Code
-
... ... @@ -24,10 +24,6 @@ 24 24 margin-bottom: 1em; 25 25 } 26 26 27 -.appName-preview dl tt { 28 - color: $theme.textColor; 29 -} 30 - 31 31 .appName-preview dt { 32 32 font-weight: normal; 33 33 margin-top: 1em; ... ... @@ -36,3 +36,8 @@ 36 36 .appName-preview dt:after { 37 37 content: ":" 38 38 } 35 + 36 +.appName-preview .breadcrumb { 37 + background-color: transparent; 38 + padding: 0; 39 +} - Content Type
-
... ... @@ -1,0 +1,1 @@ 1 +CSS