Changes for page Create Application

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

From version 6.1
edited by Ludovic Dubost
on 2017/01/07 20:21
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-8.4.3]
To version 4.1
edited by Ludovic Dubost
on 2015/09/01 11:46
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui-7.1]

Summary

Details

Page properties
Content
... ... @@ -1,136 +1,103 @@
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"}}
8 - #appWizardHeader('name')
6 + #appWizardHeader(1)
9 9   (% class="wizard-help" %)
10 10   (((
11 11   **$services.localization.render('platform.appwithinminutes.wizardStepHelpTitle')** $services.localization.render('platform.appwithinminutes.wizardStepHelpDescription')
12 12   (% class="steps vertical" %)
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")
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")
16 16   #end
17 17   )))
18 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>
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 + #set($appName = $request.appName)
37 + #getAppDescriptor($appName)
38 + #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))
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))
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))
45 + #set($className = "#toXMLName($appName)")
46 + #set($classRef = $services.model.createDocumentReference($doc.wiki, "${className}Code", "${className}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 - 'template': 'AppWithinMinutes.ClassTemplate',
63 - 'parent': $services.model.serialize($appHomeRef),
64 - 'title': "$appReference.name Class"
65 - }))
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)")
66 66   #end
67 - $response.sendRedirect($xwiki.getURL($appClassRef, 'edit', $escapetool.url($queryString)))
55 + $response.sendRedirect($xwiki.getURL($classRef, 'edit', $queryString))
68 68  #end
69 69  
70 -#macro (validateAppName)
71 - #getAppReference
72 - #if (!$appReference)
73 - (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameEmptyError')
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))
74 74   #else
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 + ## Create a new application.
68 + #set($className = "#toXMLName($appName)")
69 + #if($className == '')
70 + (% class="xErrorMsg" %)$services.localization.render('platform.appwithinminutes.appNameInvalidClassNameError')
86 86   #end
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
72 + #set($appHomeRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome'))
73 + #set($appClassRef = $services.model.createDocumentReference($doc.wiki, "$!{className}Code", "$!{className}Class"))
96 96   #end
97 -#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))
98 98  
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)
86 + {{warning}}$services.localization.render('platform.appwithinminutes.appNameIsUsedWarning'){{/warning}}
110 110   #end
111 111  #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
122 122  {{/velocity}}
123 123  
124 124  {{velocity}}
125 -#if ("$!request.appName" != '')
126 - #if ($xcontext.action == 'get')
127 - #validateAppName
92 +#if("$!request.appName" != '')
93 + #if($xcontext.action == 'get')
94 + #validateAppName($request.appName)
128 128   #else
129 129   ## CSRF protection is not needed because this step only redirects to the next one passing data in the query string.
130 - #processStep
97 + #processStep()
131 131   #end
132 132  #else
133 - #showStep
100 + #showStep()
134 134  #end
135 -#set ($displayDocExtra = false)
102 +#set($docextras=[])
136 136  {{/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.text(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