Changes for page Create Application

Last modified by Ludovic Dubost on 2024/07/22 15:51

From version 3.1
edited by Ludovic Dubost
on 2014/11/18 12:31
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-6.3]
To version 7.1
edited by Ludovic Dubost
on 2019/05/20 19:03
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/11.3]

Summary

Details

Page properties
Syntax
... ... @@ -1,1 +1,1 @@
1 -XWiki 2.0
1 +XWiki 2.1
Content
... ... @@ -1,102 +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 - #set($appName = $request.appName)
37 - #getAppDescriptor($appName)
38 - #if($appDescriptor)
39 - ## Edit an existing application. Use the configured class name.
40 - #set($classStringRef = $appDescriptor.getObject($appDescriptorClassName).getProperty('class').value)
41 - ## The class string reference is relative to the document holding the application descriptor.
42 - #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)
43 43   #else
44 44   ## Create a new application. Use the default class name.
45 - #set($className = "#toXMLName($appName)")
46 - #set($classRef = $services.model.createDocumentReference($doc.wiki, "${className}Code", "${className}Class"))
64 + #set ($appCodeRef = $services.model.createSpaceReference('Code', $appReference))
65 + #set ($appClassRef = $services.model.createDocumentReference("$!{appReference.name}Class", $appCodeRef))
47 47   #end
48 - #set($queryString = 'wizard=true')
49 - #if(!$xwiki.exists($classRef))
50 - #set($classTitle = "$appName Class")
51 - #set($appHomeRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome'))
52 - #set($classParent = $services.model.serialize($appHomeRef))
53 - #set($queryString = "$queryString&editor=inline&template=AppWithinMinutes.ClassTemplate&parent=$escapetool.url($classParent)&title=$escapetool.url($classTitle)&AppWithinMinutes.MetadataClass_0_dataSpaceName=$escapetool.url($appName)")
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 + }))
54 54   #end
55 - $response.sendRedirect($xwiki.getURL($classRef, 'edit', $queryString))
76 + $response.sendRedirect($xwiki.getURL($appClassRef, 'edit', $escapetool.url($queryString)))
56 56  #end
57 57  
58 -#macro(validateAppName $appName)
59 - #getAppDescriptor("$!appName")
60 - #if($appDescriptor)
61 - ## Edit an existing application.
62 - #set($appHomeRef = $appDescriptor.documentReference)
63 - #set($classStringRef = $appDescriptor.getObject($appDescriptorClassName).getProperty('class').value)
64 - ## The class string reference is relative to the document holding the application descriptor.
65 - #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>
66 66   #else
67 - ## Create a new application.
68 - #set($className = "#toXMLName($appName)")
69 - #if($className == '')
70 - (% 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))
71 71   #end
72 - #set($appHomeRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome'))
73 - #set($appClassRef = $services.model.createDocumentReference($doc.wiki, "$!{className}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
74 74   #end
75 - #set($appHomeURL = $stringtool.removeEnd($xwiki.getDocument($appHomeRef).getExternalURL(), 'WebHome'))
76 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewHomePageUrlLabel')
77 - : {{{$!appHomeURL}}}
78 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewDataSpaceLabel')
79 - : {{{$appHomeRef.wikiReference.name}}} » {{{$appHomeRef.lastSpaceReference.name}}}
80 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewCodeSpaceLabel')
81 - : {{{$appClassRef.wikiReference.name}}} » {{{$appClassRef.lastSpaceReference.name}}}
82 - ; $services.localization.render('platform.appwithinminutes.appNamePreviewClassReferenceLabel')
83 - : {{{$appClassRef.wikiReference.name}}} » {{{$appClassRef.lastSpaceReference.name}}} » {{{$appClassRef.name}}}
84 - #if($appDescriptor || $xwiki.exists($appHomeRef) || $xwiki.exists($appClassRef))
107 +#end
85 85  
86 - {{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)
87 87   #end
88 88  #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
89 89  {{/velocity}}
90 90  
91 91  {{velocity}}
92 -#if("$!request.appName" != '')
93 - #if($xcontext.action == 'get')
94 - #validateAppName($request.appName)
137 +{{html clean="false"}}
138 +#if ("$!request.appName" != '')
139 + #if ($xcontext.action == 'get')
140 + #validateAppName
95 95   #else
96 96   ## CSRF protection is not needed because this step only redirects to the next one passing data in the query string.
97 - #processStep()
143 + #processStep
98 98   #end
99 -#else
100 - #showStep()
145 +#elseif ($request.wizard == 'true')
146 + #showStep
147 + #set ($displayDocExtra = false)
101 101  #end
149 +{{/html}}
102 102  {{/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 -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);
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