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 6.1
edited by Ludovic Dubost
on 2017/01/07 20:21
on 2017/01/07 20:21
Change comment:
Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-8.4.3]
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. ThomasMortagne1 +xwiki:XWiki.ludovic - Content
-
... ... @@ -1,98 +1,136 @@ 1 1 {{include reference="AppWithinMinutes.WizardStep"/}} 2 2 3 +{{template name="locationPicker_macros.vm" /}} 4 + 3 3 {{velocity output="false"}} 4 4 #macro(showStep) 5 5 {{html wiki="true"}} 6 - #appWizardHeader( 1)8 + #appWizardHeader('name') 7 7 (% class="wizard-help" %) 8 8 ((( 9 9 **$services.localization.render('platform.appwithinminutes.wizardStepHelpTitle')** $services.localization.render('platform.appwithinminutes.wizardStepHelpDescription') 10 10 (% class="steps vertical" %) 11 - #foreach($ indexin[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")13 + #foreach($step in $awmSteps) 14 + * (% class="number" %)$mathtool.add($foreach.index, 1)(%%) (% class="name" %)$services.localization.render("appWithinMinutes.wizardStep.${step}.name")(%%) 15 + (% class="description" %)$services.localization.render("appWithinMinutes.wizardStep.${step}.description") 14 14 #end 15 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" /> 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> 20 20 #appWizardFooter(1) 21 21 </form> 22 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) 44 +#macro (processStep) 35 35 ## Check if the application already exists. 36 - #getAppDescriptor($request.appName) 37 - #if($appDescriptor) 46 + #getAppReference 47 + #getAppDescriptor($appReference) 48 + #if ($appDescriptor) 38 38 ## Edit an existing application. Use the configured class name. 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))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)) 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")) 55 + #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 56 + #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)") 58 + #set ($queryString = {'wizard': true}) 59 + #if (!$xwiki.exists($appClassRef)) 60 + #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 61 + #set ($discard = $queryString.putAll({ 62 + 'template': 'AppWithinMinutes.ClassTemplate', 63 + 'parent': $services.model.serialize($appHomeRef), 64 + 'title': "$appReference.name Class" 65 + })) 50 50 #end 51 - $response.sendRedirect($xwiki.getURL($ classRef, 'edit', $queryString))67 + $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)) 70 +#macro (validateAppName) 71 + #getAppReference 72 + #if (!$appReference) 73 + (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameEmptyError') 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') 75 + #getAppDescriptor($appReference) 76 + #if ($appDescriptor) 77 + ## Edit an existing application. 78 + #set ($appDescriptorObj = $appDescriptor.getObject($appDescriptorClassName)) 79 + #set ($appClassRef = $appDescriptorObj.getValue('class')) 80 + ## The class reference is relative to the document holding the application descriptor. 81 + #set ($appClassRef = $services.model.resolveDocument($appClassRef, 'explicit', $appDescriptor.documentReference)) 82 + #else 83 + ## Create a new application. 84 + #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference)) 85 + #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")) 87 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewHomePageUrlLabel') 88 + : {{{$!xwiki.getDocument($appReference).externalURL}}} 89 + ; $services.localization.render('platform.appwithinminutes.appNamePreviewCodeSpaceLabel') 90 + : {{html clean="false"}}#hierarchy($appClassRef.parent){{/html}} 91 + #set ($appHomeRef = $services.model.resolveDocument('', 'default', $appReference)) 92 + #if ($appDescriptor || $xwiki.exists($appHomeRef) || $xwiki.exists($appClassRef)) 93 + 94 + {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}} 95 + #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)) 97 +#end 81 81 82 - {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}} 99 +#macro (getAppReference) 100 + #if ($request.resolve == 'true') 101 + #set ($appReference = $services.model.resolveSpace($request.appName)) 102 + #elseif ("$!request.appName" != '') 103 + #set ($parentReference = $doc.documentReference.wikiReference) 104 + #if ("$!request.appParentReference" != '') 105 + #set ($parentReference = $services.model.resolveSpace($request.appParentReference)) 106 + #end 107 + #set ($appReference = $services.model.createSpaceReference($request.appName, $parentReference)) 108 + #else 109 + #set ($appReference = $NULL) 83 83 #end 84 84 #end 112 + 113 +#macro (getAppDescriptor $appReference) 114 + #set ($appDescriptorClassName = 'AppWithinMinutes.LiveTableClass') 115 + #set ($appDescriptorStatement = "from doc.object($appDescriptorClassName) as obj where doc.space = :space") 116 + #set ($localSpaceReference = $services.model.serialize($appReference, 'local')) 117 + #set ($appDescriptors = $services.query.xwql($appDescriptorStatement).bindValue('space', $localSpaceReference).execute()) 118 + #if ($appDescriptors.size() > 0) 119 + #set ($appDescriptor = $xwiki.getDocument($appDescriptors.get(0))) 120 + #end 121 +#end 85 85 {{/velocity}} 86 86 87 87 {{velocity}} 88 -#if("$!request.appName" != '') 89 - #if($xcontext.action == 'get') 90 - #validateAppName ($request.appName)125 +#if ("$!request.appName" != '') 126 + #if ($xcontext.action == 'get') 127 + #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 ()130 + #processStep 94 94 #end 95 95 #else 96 - #showStep ()133 + #showStep 97 97 #end 135 +#set ($displayDocExtra = false) 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