Changes for page Main

Last modified by Administrator on 2023/03/27 10:53

From version 1.1
edited by Administrator
on 2018/07/24 00:25
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/9.11.7]
To version 3.1
edited by Administrator
on 2020/01/07 18:45
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/11.10.2]

Summary

Details

Page properties
Title
... ... @@ -1,1 +1,1 @@
1 -#if(!$doc.name.endsWith('Sheet'))$services.localization.render('appWithinMinutes.classEditor.title', [$stringtool.removeEnd($doc.title, 'Class').trim()])#{else}$doc.name#end
1 +#if ("$!appTitle" != '')$appTitle#else$doc.pageReference.name#end
Syntax
... ... @@ -1,1 +1,1 @@
1 -XWiki 2.0
1 +XWiki 2.1
Content
... ... @@ -1,3 +1,5 @@
1 +{{include reference="AppWithinMinutes.VelocityMacros" /}}
2 +
1 1  {{groovy}}
2 2  import com.xpn.xwiki.XWikiContext;
3 3  import com.xpn.xwiki.api.Context;
... ... @@ -52,95 +52,100 @@
52 52  #**
53 53   * Displays the field palette.
54 54   *#
55 -#macro(displayFieldPalette)
56 - (% id="palette" %)
57 - (((
58 - **$services.localization.render('platform.appwithinminutes.classEditorPaletteTitle')**
59 -
60 - (% class="xHint" %)
61 - $services.localization.render('platform.appwithinminutes.classEditorPaletteHint')
62 -
57 +#macro (displayFieldPalette)
58 + <div id="palette">
59 + <p><strong>$services.localization.render('platform.appwithinminutes.classEditorPaletteTitle')</strong></p>
60 + <p class="xHint">$services.localization.render('platform.appwithinminutes.classEditorPaletteHint')</p>
63 63   ## List all form field types, grouped by category.
64 - #set($formFieldDocs = [])
65 - #set($formFieldClassName = 'AppWithinMinutes.FormFieldClass')
66 - #set($categoryListStatement = 'from doc.object(AppWithinMinutes.FormFieldCategoryClass) as category order by category.priority')
67 - #foreach($category in $services.query.xwql($categoryListStatement).execute())
68 - #set($categoryDoc = $xwiki.getDocument($category))
69 - * (% class="category" %)$categoryDoc.plainTitle
70 - #set($formFieldsForCategoryStatement = "from doc.object($formFieldClassName) as field where field.category = :category order by field.priority")
71 - #set($formFieldsForCategoryQuery = $services.query.xwql($formFieldsForCategoryStatement).bindValue('category', $category))
72 - #foreach($formField in $formFieldsForCategoryQuery.execute())
73 - #set($formFieldDoc = $xwiki.getDocument($formField))
74 - #set($discard = $formFieldDocs.add($formFieldDoc))
75 - #set($formFieldIcon = $formFieldDoc.getObject($formFieldClassName).getProperty('icon').value)
76 - #if($formFieldIcon.contains('/'))
77 - #set($formFieldIconURL = $xwiki.getSkinFile($formFieldIcon))
78 - #else
79 - #set($formFieldIconURL = $formFieldDoc.getAttachmentURL($formFieldIcon))
62 + #set ($formFieldDocs = [])
63 + #set ($formFieldClassName = 'AppWithinMinutes.FormFieldClass')
64 + #set ($categoryListStatement = 'from doc.object(AppWithinMinutes.FormFieldCategoryClass) as category order by category.priority')
65 + <ul>
66 + #foreach ($category in $services.query.xwql($categoryListStatement).execute())
67 + #set ($categoryDoc = $xwiki.getDocument($category))
68 + <li>
69 + <div class="category">$categoryDoc.plainTitle</div>
70 + #set ($formFieldsForCategoryStatement = "from doc.object($formFieldClassName) as field where field.category = :category order by field.priority")
71 + #set ($formFieldsForCategoryQuery = $services.query.xwql($formFieldsForCategoryStatement).bindValue('category', $category))
72 + <ul>
73 + #foreach ($formField in $formFieldsForCategoryQuery.execute())
74 + #set ($formFieldDoc = $xwiki.getDocument($formField))
75 + #set ($discard = $formFieldDocs.add($formFieldDoc))
76 + #set ($formFieldIcon = $formFieldDoc.getObject($formFieldClassName).getProperty('icon').value)
77 + #set ($formFieldIconRendered = $services.icon.renderHTML($formFieldIcon))
78 + #if ("$!formFieldIconRendered" == "")
79 + #if ($formFieldIcon.contains('/'))
80 + #set ($formFieldIconURL = $xwiki.getSkinFile($formFieldIcon))
81 + #else
82 + #set ($formFieldIconURL = $formFieldDoc.getAttachmentURL($formFieldIcon))
83 + #end
84 + #set ($formFieldIconRendered = "<img src='$formFieldIconURL' alt='$escapetool.xml($formFieldDoc.plainTitle)' class='icon' />")
80 80   #end
81 - ** (% class="field" %){{html}}
82 - <img src="$formFieldIconURL" alt="$escapetool.xml($formFieldDoc.plainTitle)" class="icon" />
83 - $escapetool.xml($formFieldDoc.plainTitle)
84 - ## FIXME: We should use the 'get' action instead to prevent the stats module from recording this AJAX request.
85 - ## The 'edit' action is a temporary solution until the sheet module is modified to allow a sheet to be enforced through
86 - ## the query string even if it doesn't match the action (e.g. the 'get' action).
87 - ## The sheet parameter is required when editing a new class because the request will be made to a document that doesn't exist.
88 - ## FIXME2: In the future don't force the text editor type and instead use the default editor. This means
89 - ## that if the WYSIWYG editor is used, we'll need to convert the HTML into the target syntax so that the
90 - ## Template in #updateAndSaveTemplate is saved with target syntax and not HTML.
91 - ## See https://jira.xwiki.org/browse/XWIKI-13789
92 - <input type="hidden" value="$doc.getURL('edit', "xpage=plain&sheet=AppWithinMinutes.ClassEditSheet&field=$escapetool.url($formFieldDoc.fullName)&xeditmode=text")" class="data"/>
93 - {{/html}}
86 + <li class="field">
87 + $formFieldIconRendered
88 + $escapetool.xml($formFieldDoc.plainTitle)
89 + ## FIXME: We should use the 'get' action instead to prevent the stats module from recording this AJAX request.
90 + ## The 'edit' action is a temporary solution until the sheet module is modified to allow a sheet to be enforced through
91 + ## the query string even if it doesn't match the action (e.g. the 'get' action).
92 + ## The sheet parameter is required when editing a new class because the request will be made to a document that doesn't exist.
93 + ## FIXME2: In the future don't force the text editor type and instead use the default editor. This means
94 + ## that if the WYSIWYG editor is used, we'll need to convert the HTML into the target syntax so that the
95 + ## Template in #updateAndSaveTemplate is saved with target syntax and not HTML.
96 + ## See https://jira.xwiki.org/browse/XWIKI-13789
97 + #set ($fieldURL = $doc.getURL('edit', $escapetool.url({
98 + 'xpage': 'plain',
99 + 'sheet': 'AppWithinMinutes.ClassEditSheet',
100 + 'field': $formFieldDoc.fullName,
101 + 'xeditmode': 'text'
102 + })))
103 + <input type="hidden" value="$fieldURL" class="data"/>
104 + </li>
94 94   #end
106 + </ul>
107 + </li>
95 95   #end
96 - )))
109 + </ul>
110 + </div>
97 97  #end
98 98  
99 99  #**
100 100   * Displays the field canvas.
101 101   *#
102 -#macro(displayFieldCanvas)
103 - #set($propertyType2FormField = {})
104 - #foreach($formFieldDoc in $formFieldDocs)
116 +#macro (displayFieldCanvas)
117 + #set ($propertyType2FormField = {})
118 + #foreach ($formFieldDoc in $formFieldDocs)
105 105   ## Use the type of the field template.
106 - #set($type = $formFieldDoc.getxWikiClass().properties.get(0).classType)
107 - #set($discard = $propertyType2FormField.put($type, $formFieldDoc))
120 + #set ($type = $formFieldDoc.getxWikiClass().properties.get(0).classType)
121 + #set ($discard = $propertyType2FormField.put($type, $formFieldDoc))
108 108   #end
109 - (% id="canvas" %)
110 - (((
111 - (% class="hint" %)
112 - $services.localization.render('platform.appwithinminutes.classEditorCanvasHint')
113 -
114 - #set($unknownFields = [])
115 - #set($empty = true)
116 - #foreach ($field in $doc.getxWikiClass().properties)
117 - #set($formFieldDoc = $propertyType2FormField.get($field.classType))
118 - #if($formFieldDoc)
119 - #set($empty = false)
120 - * (((#displayField($field $formFieldDoc))))
121 - #else
122 - #set($discard = $unknownFields.add($field))
123 + <div id="canvas">
124 + <p class="hint">
125 + $services.localization.render('platform.appwithinminutes.classEditorCanvasHint')
126 + </p>
127 + <ul>
128 + #set ($unknownFields = [])
129 + #foreach ($field in $doc.getxWikiClass().properties)
130 + #set ($formFieldDoc = $propertyType2FormField.get($field.classType))
131 + #if ($formFieldDoc)
132 + <li>#displayField($field $formFieldDoc)</li>
133 + #else
134 + #set($discard = $unknownFields.add($field))
135 + #end
123 123   #end
124 - #end
125 - #if(!$empty)
126 - ## Leave an empty line to separate the blocks.
127 -
128 - #end
129 - ##
130 - (% class="hidden" %)
131 - {{html}}
137 + </ul>
138 + <div class="hidden">
132 132   ## Output the field meta data even if the field is not supported to preserve it when the class is saved.
133 - #foreach($field in $unknownFields)
140 + #foreach ($field in $unknownFields)
134 134   #displayFieldMetaData($field)
135 135   #end
136 - {{/html}}
137 - )))
143 + </div>
144 + </div>
138 138  #end
139 139  
140 140  #**
141 141   * Display the options to create/update the class template, the class sheet and the class translation bundle.
142 142   *#
143 -#macro(displayClassOptions)
150 +#macro (displayClassOptions)
144 144   #set ($className = $stringtool.removeEnd($doc.fullName, 'Class'))
145 145   #set ($templateReference = $services.model.resolveDocument("${className}Template"))
146 146   #set ($translationsReference = $services.model.resolveDocument("${className}Translations"))
... ... @@ -151,7 +151,6 @@
151 151   #elseif ($classSheets.size() == 1)
152 152   #set ($sheetReference = $classSheets.get(0))
153 153   #end
154 - {{html}}
155 155   ## Hide the options if neither the sheet nor the template nor the translation bundle exists. They don't have to be
156 156   ## updated, they have to be created.
157 157   <dl id="options" #if (!$xwiki.exists($sheetReference) && !$xwiki.exists($templateReference)
... ... @@ -200,7 +200,6 @@
200 200   </span>
201 201   </dd>
202 202   </dl>
203 - {{/html}}
204 204  #end
205 205  
206 206  #macro (pageLink $reference)
... ... @@ -212,58 +212,56 @@
212 212   #set ($action = 'create')
213 213   #set ($discard = $params.put('parent', $doc.fullName))
214 214   #end
215 - <span class="$class">##
216 - <a href="$escapetool.xml($xwiki.getURL($reference, $action, $escapetool.url($params)))">##
217 - $escapetool.xml($reference.name)##
218 - </a>##
219 - </span>##
220 + <span class="$class"><a href="$escapetool.xml($xwiki.getURL($reference, $action, $escapetool.url($params)))"
221 + >$escapetool.xml($reference.name)</a></span>##
220 220  #end
221 221  
222 222  #**
223 223   * Display a form field.
224 224   *#
225 -#macro(displayField $field $formFieldDoc)
226 - #if($formFieldDoc.getObject('XWiki.StyleSheetExtension'))
227 - #set($discard = $xwiki.ssx.use($formFieldDoc.fullName))
227 +#macro (displayField $field $formFieldDoc)
228 + #if ($formFieldDoc.getObject('XWiki.StyleSheetExtension'))
229 + #set ($discard = $xwiki.ssx.use($formFieldDoc.fullName))
228 228   #end
229 - #if($formFieldDoc.getObject('XWiki.JavaScriptExtension'))
230 - #set($discard = $xwiki.jsx.use($formFieldDoc.fullName))
231 + #if ($formFieldDoc.getObject('XWiki.JavaScriptExtension'))
232 + #set ($discard = $xwiki.jsx.use($formFieldDoc.fullName))
231 231   #end
232 - (% class="hidden" %)
233 - {{html}}
234 + <div class="hidden">
234 234   #displayFieldMetaData($field)
235 235   ## We need this information to avoid querying and loading all FormField documents twice.
236 236   ## NOTE: We use a different ID format to avoid collisions with the field meta properties.
237 - <input type="hidden" id="template-$field.name" name="template-$field.name" value="$escapetool.xml($formFieldDoc.fullName)" />
238 - {{/html}}
239 -
240 - #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
241 - #set($templateRef = $services.model.resolveDocument("${className}Template"))
242 - #set($templateDoc = $xwiki.getDocument($templateRef))
238 + <input type="hidden" id="template-$field.name" name="template-$field.name"
239 + value="$escapetool.xml($formFieldDoc.fullName)"
240 + data-propertyName="$escapetool.xml($formFieldDoc.getxWikiClass().propertyNames[0])" />
241 + </div>
242 + #set ($className = $stringtool.removeEnd($doc.fullName, 'Class'))
243 + #set ($templateRef = $services.model.resolveDocument("${className}Template"))
244 + #set ($templateDoc = $xwiki.getDocument($templateRef))
243 243   ## Simulate the editing of the class instance from the template document.
244 244   ## Note that we can't simply call display on the template document because $field could be a new field that hasn't
245 245   ## been added to the class yet (so the object from the template doesn't have this field yet).
246 - (% class="field-viewer" %)
247 - #displayFieldProperty($field "${doc.fullName}_0_" $templateDoc.getObject($doc.fullName, true))
248 -
249 - #set($propertyNames = ['name', 'prettyName', 'number', 'required', 'hint'])
250 - #set($formFieldObj = $formFieldDoc.getObject('AppWithinMinutes.FormFieldClass'))
251 - #set($customPropertyNames = $formFieldObj.getProperty('properties').value.split('\s+'))
252 - #set($discard = $customPropertyNames.removeAll($propertyNames))
253 - #set($discard = $propertyNames.addAll($customPropertyNames.subList(0, $customPropertyNames.size())))
254 - (% class="field-config" %)
255 - #foreach($propertyName in $propertyNames)
256 - #set($propertyDefinition = $field.xWikiClass.get($propertyName))
257 - #if($propertyDefinition)
258 - #displayFieldProperty($propertyDefinition "field-${field.name}_" $field)
248 + <dl class="field-viewer">
249 + #displayFieldProperty($field "${doc.fullName}_0_" $templateDoc.getObject($doc.fullName, true))
250 + </dl>
251 + #set ($propertyNames = ['name', 'prettyName', 'number', 'required', 'hint'])
252 + #set ($formFieldObj = $formFieldDoc.getObject('AppWithinMinutes.FormFieldClass'))
253 + #set ($customPropertyNames = $formFieldObj.getProperty('properties').value.split('\s+'))
254 + #set ($discard = $customPropertyNames.removeAll($propertyNames))
255 + #set ($discard = $propertyNames.addAll($customPropertyNames.subList(0, $customPropertyNames.size())))
256 + <dl class="field-config">
257 + #foreach ($propertyName in $propertyNames)
258 + #set ($propertyDefinition = $field.xWikiClass.get($propertyName))
259 + #if ($propertyDefinition)
260 + #displayFieldProperty($propertyDefinition "field-${field.name}_" $field)
261 + #end
259 259   #end
260 - #end
263 + </dl>
261 261  #end
262 262  
263 263  #**
264 264   * Display the field meta data. This is needed to preserve the field when its type is not supported by the editor.
265 265   *#
266 -#macro(displayFieldMetaData $field)
269 +#macro (displayFieldMetaData $field)
267 267   <input type="hidden" id="type-$field.name" name="type-$field.name" value="$field.classType" />
268 268  #end
269 269  
... ... @@ -270,13 +270,18 @@
270 270  #**
271 271   * Displays a configuration property of a class field. This macro can also be used to display a property of an object.
272 272   *#
273 -#macro(displayFieldProperty $property $prefix $field)
274 - #set($displayFormType = $property.getProperty('displayFormType'))
275 - #if($property.classType == 'Boolean' && (!$displayFormType || $displayFormType.value == 'checkbox'))
276 - ; {{html clean="false"}}<label for="$!{prefix}$property.name">#displayPropertyEditInput($property, $prefix, $field)$escapetool.xml($property.prettyName)</label>{{/html}}
276 +#macro (displayFieldProperty $property $prefix $field)
277 + #set ($displayFormType = $property.getProperty('displayFormType'))
278 + #if ($property.classType == 'Boolean' && (!$displayFormType || $displayFormType.value == 'checkbox'))
279 + <dt>
280 + <label for="$!{prefix}$property.name">
281 + #displayPropertyEditInput($property, $prefix, $field)$escapetool.xml($property.prettyName)
282 + </label>
283 + </dt>
284 + <dd></dd>
277 277   #else
278 - ; {{html}}<label for="${prefix}$property.name">$escapetool.xml($property.prettyName)</label>{{/html}}
279 - : {{html clean="false"}}#displayPropertyEditInput($property, $prefix, $field){{/html}}
286 + <dt><label for="${prefix}$property.name">$escapetool.xml($property.prettyName)</label></dt>
287 + <dd>#displayPropertyEditInput($property, $prefix, $field)</dd>
280 280   #end
281 281  #end
282 282  
... ... @@ -283,12 +283,18 @@
283 283  #**
284 284   * Displays the input used to edit the specified property of the given object. The given object can be either an
285 285   * instance of an XWiki class or a class field. In the first case the property represents an object field and in the
286 - * second case the property represents a field meta property.
294 + * second case the property represents a field meta property. We currently don't use custom display for metaproperty,
295 + * so in that case we fallback on displayEdit.
287 287   *#
288 -#macro(displayPropertyEditInput $property $prefix $object)
289 - #set($wrappedProperty = $property.propertyClass)
290 - #if($wrappedProperty.isCustomDisplayed($xcontext.context))
291 - $xcontext.get('propertyCustomDisplayer').display($property, $prefix, $object)
297 +#macro (displayPropertyEditInput $property $prefix $object)
298 + #set ($wrappedProperty = $property.propertyClass)
299 + #if ($wrappedProperty.isCustomDisplayed($xcontext.context))
300 + #set ($customDisplayer = $!xcontext.get('propertyCustomDisplayer').display($property, $prefix, $object))
301 + #if ((! $customDisplayer) && ("$!customDisplayer" == ""))
302 + $doc.displayEdit($property, $prefix, $object)
303 + #else
304 + $customDisplayer
305 + #end
292 292   #else
293 293   $doc.displayEdit($property, $prefix, $object)
294 294   #end
... ... @@ -297,22 +297,23 @@
297 297  #**
298 298   * Called when a new form field is added via AJAX.
299 299   *#
300 -#macro(displayNewField)
314 +#macro (displayNewField)
301 301   ## Output the SkinExtension hooks to allow field displayers to pull JavaScript/CSS resources.
316 + ## Output also the LinkExtension hook because $xwiki.linkx.use() is used to load CSS files from WebJars.
302 302   ## The class editor moves this resource includes in the HTML page head.
303 - {{html}}
318 + <!-- com.xpn.xwiki.plugin.skinx.LinkExtensionPlugin -->
304 304   #skinExtensionHooks
305 - {{/html}}
306 -
307 - #set($formFieldDoc = $xwiki.getDocument($request.field))
308 - #set($formFieldDocClassFields = $formFieldDoc.getxWikiClass().getXWikiClass().properties)
309 - #if($formFieldDocClassFields.size() > 0)
320 + #set ($formFieldDoc = $xwiki.getDocument($request.field))
321 + #set ($formFieldDocClassFields = $formFieldDoc.getxWikiClass().getXWikiClass().properties)
322 + #if ($formFieldDocClassFields.size() > 0)
310 310   ## Clone the field template.
311 - #set($field = $formFieldDocClassFields.get(0).clone())
312 - #if("$!field.prettyName" == '')
313 - #set($discard = $field.setPrettyName($formFieldDoc.title))
324 + #set ($field = $formFieldDocClassFields.get(0).clone())
325 + #if ("$!field.prettyName" == '')
326 + #set ($discard = $field.setPrettyName($formFieldDoc.title))
314 314   #end
315 - #set($discard = $doc.getxWikiClass().getXWikiClass().addField($field.name, $field))
328 + #set ($xclass = $doc.getxWikiClass().getXWikiClass())
329 + #set ($discard = $xclass.addField($field.name, $field))
330 + #set ($discard = $field.setObject($xclass))
316 316   #displayField($doc.getxWikiClass().get($field.name) $formFieldDoc)
317 317   #else
318 318   Unsupported form field.
... ... @@ -322,88 +322,91 @@
322 322  #**
323 323   * Preview a class field (requires Programming Right).
324 324   *#
325 -#macro(previewField)
340 +#macro (previewField)
326 326   ## Find the request parameter that specifies the field template.
327 - #foreach($paramName in $request.getParameterMap().keySet())
328 - #if($paramName.startsWith('template-'))
329 - #set($fieldName = $paramName.substring(9))
330 - #set($fieldTemplateDoc = $xwiki.getDocument($request.getParameter($paramName)))
342 + #foreach ($paramName in $request.getParameterMap().keySet())
343 + #if ($paramName.startsWith('template-'))
344 + #set ($fieldName = $paramName.substring(9))
345 + #set ($fieldTemplateDoc = $xwiki.getDocument($request.getParameter($paramName)))
331 331   #break
332 332   #end
333 333   #end
334 334   ##
335 335   ## Clone the field template.
336 - #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
351 + #set ($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
337 337   ##
338 338   ## Update the field meta properties based on the submitted data.
339 - #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName"))
340 - #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field))
354 + #set ($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName"))
355 + #set ($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field))
341 341   ##
342 342   ## Don't rename the field (ignore the submitted name).
343 - #set($discard = $field.setName($fieldName))
358 + #set ($discard = $field.setName($fieldName))
344 344   ##
345 345   ## We have to add the field to the class before setting its value.
346 346   ## (otherwise the field value from the request is ignored).
347 - #set($xclass = $doc.getxWikiClass().getXWikiClass())
348 - #set($discard = $xclass.addField($fieldName, $field))
362 + #set ($xclass = $doc.getxWikiClass().getXWikiClass())
363 + #set ($discard = $xclass.addField($fieldName, $field))
364 + #set ($discard = $field.setObject($xclass))
349 349   ##
350 350   ## Create an object that has this field and set its value from request.
351 - #set($object = $fieldTemplateDoc.getObject($doc.fullName, true))
367 + #set ($object = $fieldTemplateDoc.getObject($doc.fullName, true))
352 352   ##
353 353   ## Filter empty values from the request, otherwise the update method could try to select an invalid value.
354 - #set($values = [])
355 - #foreach($value in $request.getParameterValues("${doc.fullName}_0_$fieldName"))
356 - #if($value != '')
357 - #set($discard = $values.add($value))
370 + #set ($values = [])
371 + #foreach ($value in $request.getParameterValues("${doc.fullName}_0_$fieldName"))
372 + #if ($value != '')
373 + #set ($discard = $values.add($value))
358 358   #end
359 359   #end
360 - #if($values.size() > 0)
361 - #set($stringArray = $request.getParameterValues("template-$fieldName"))
362 - #set($discard = $xclass.fromMap({$fieldName: $values.toArray($stringArray)}, $object.getXWikiObject()))
376 + #if ($values.size() > 0)
377 + #set ($stringArray = $request.getParameterValues("template-$fieldName"))
378 + #set ($discard = $xclass.fromMap({$fieldName: $values.toArray($stringArray)}, $object.getXWikiObject()))
363 363   #end
364 364   ##
365 - ## Display the field (with the rights of the current user).
366 - #set($field = $doc.getxWikiClass().get($fieldName))
367 - ## Note that we don't modify the cached document because the previous line has cloned it.
368 - #set ($discard = $doc.document.setAuthorReference($xcontext.userReference))
369 - {{html clean="false"}}#displayPropertyEditInput($field, "${doc.fullName}_0_", $object){{/html}}
381 + ## Display the field.
382 + #set ($field = $doc.getxWikiClass().get($fieldName))
383 + #displayPropertyEditInput($field, "${doc.fullName}_0_", $object)
370 370  #end
371 371  
372 372  #**
373 373   * Display the edit class form.
374 374   *#
375 -#macro(displayEditForm)
376 - $xwiki.jsfx.use('js/scriptaculous/dragdrop.js')##
377 - $xwiki.jsx.use('AppWithinMinutes.ClassEditSheet')##
378 - $xwiki.ssx.use('AppWithinMinutes.ClassEditSheet')##
379 - $xwiki.ssx.use('AppWithinMinutes.ClassSheetGenerator')##
380 - #if("$!request.wizard" == 'true')
389 +#macro (displayEditForm)
390 + #set ($discard = $xwiki.jsfx.use('js/scriptaculous/dragdrop.js'))
391 + #set ($discard = $xwiki.jsx.use('AppWithinMinutes.ClassEditSheet'))
392 + #set ($discard = $xwiki.ssx.use('AppWithinMinutes.ClassEditSheet'))
393 + #set ($discard = $xwiki.ssx.use('AppWithinMinutes.ClassSheetGenerator'))
394 + #if ("$!request.wizard" == 'true')
381 381   #appWizardHeader('structure')
382 -
383 383   #end
384 384   #displayFieldPalette()
385 385   #displayFieldCanvas()
386 386   #displayClassOptions()
387 387   #if("$!request.wizard" == 'true')
388 -
389 389   #appWizardFooter('structure')
390 390   #end
391 - (% class="clearfloats" %)((()))
403 + <div class="clearfloats"></div>
392 392  #end
393 393  
394 394  #**
395 395   * Displays either the edit class form or a new form field. The later is used when adding a new form field via AJAX.
396 396   *#
397 -#macro(doEdit)
398 - #if("$!request.field" != '')
409 +#macro (doEdit)
410 + #if ("$!request.field" != '')
399 399   #displayNewField()
400 - #elseif("$!request.preview" == 'true')
412 + #elseif ("$!request.preview" == 'true')
401 401   #previewField()
402 402   #else
403 403   ## Make sure that only the sheet content is rendered when the class is saved using AJAX.
404 - (% class="hidden" %)
405 - {{html}}<input type="hidden" name="xpage" value="plain" />{{/html}}
406 -
416 + <div class="hidden">
417 + <input type="hidden" name="xpage" value="plain" />
418 + #if ($request.wizard == 'true')
419 + ## Preserve the wizard mode.
420 + <input type="hidden" name="wizard" value="true" />
421 + #end
422 + ## Compute the application title to be used as the wizard step title.
423 + #getAppTitle
424 + </div>
407 407   #displayEditForm()
408 408   #end
409 409  #end
... ... @@ -419,10 +419,7 @@
419 419   #try()
420 420   #set ($discard = $copyAsJob.join())
421 421   #set ($copyAsJobStatus = $services.job.getJobStatus($copyAsJob.request.id))
422 - #set ($errorLogs = $copyAsJobStatus.log.getLogs('ERROR'))
423 - #if ($errorLogs.size() > 0)
424 - #set ($errorMessage = $errorLogs.get(0).toString())
425 - #end
440 + #set ($errorMessage = $copyAsJobStatus.logTail.getFirstLogEvents('ERROR').toString())
426 426   #end
427 427   #end
428 428  #end
... ... @@ -561,7 +561,7 @@
561 561   #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
562 562   #set($templateRef = $services.model.resolveDocument("${className}Template"))
563 563   #set($templateDoc = $xwiki.getDocument($templateRef))
564 - #set($discard = $templateDoc.setParent($doc.name))
579 + #set($discard = $templateDoc.setParent($doc.documentReference.name))
565 565   #if ($request.templateTitle)
566 566   #set($discard = $templateDoc.setTitle($request.templateTitle))
567 567   #end
... ... @@ -599,7 +599,7 @@
599 599   #if($sheetReference)
600 600   #set($sheetDoc = $xwiki.getDocument($sheetReference))
601 601   #set($sheetGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassSheetGenerator'))
602 - #set($discard = $sheetDoc.setParent($doc.name))
617 + #set($discard = $sheetDoc.setParent($doc.documentReference.name))
603 603   #set($discard = $sheetDoc.setContent($doc.getRenderedContent($sheetGeneratorDoc.content,
604 604   $sheetGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
605 605   #set($discard = $sheetDoc.setHidden(true))
... ... @@ -623,7 +623,7 @@
623 623   #set ($scope = 'WIKI')
624 624   #end
625 625   #set($discard = $translationsObj.set('scope', $scope))
626 - #set($discard = $translationsDoc.setParent($doc.name))
641 + #set($discard = $translationsDoc.setParent($doc.documentReference.name))
627 627   #set($translationsGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassTranslationsGenerator'))
628 628   #set($discard = $translationsDoc.setContent($doc.getRenderedContent($translationsGeneratorDoc.content,
629 629   $translationsGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
... ... @@ -637,17 +637,17 @@
637 637  #**
638 638   * Updates and saves the class definition, the class sheet and the class template.
639 639   *#
640 -#macro(doSave)
641 - #set($minorEdit = "$!request.minorEdit" != '')
655 +#macro (doSave)
656 + #set ($minorEdit = "$!request.minorEdit" != '')
642 642   #maybeCreateCodeSpace
643 643   #updateAndSaveClass
644 644   #updateAndSaveTemplate
645 645   #updateAndSaveSheet
646 646   #updateAndSaveTranslations
647 - #if($action == 'save')
648 - #if($errorMessage)
649 - {{error}}{{html}}$errorMessage{{/html}}{{/error}}
650 - #elseif("$!request.wizard" == 'true')
662 + #if ($action == 'save')
663 + #if ($errorMessage)
664 + <div class="box errormessage">$errorMessage</div>
665 + #elseif ("$!request.wizard" == 'true')
651 651   ## Redirect to next wizard step.
652 652   #set ($className = $stringtool.removeEnd($doc.fullName, 'Class'))
653 653   #set ($templateProviderReference = $services.model.resolveDocument("${className}TemplateProvider"))
... ... @@ -667,7 +667,7 @@
667 667   $response.sendRedirect($doc.getURL())
668 668   #end
669 669   #else
670 - #if($errorMessage)
685 + #if ($errorMessage)
671 671   $response.sendError(400, $errorMessage)
672 672   #else
673 673   $response.setStatus(204)
... ... @@ -683,21 +683,23 @@
683 683  {{/velocity}}
684 684  
685 685  {{velocity}}
701 +{{html clean="false"}}
686 686  ## Determine the action button that triggered the request
687 -#set($action = 'edit')
688 -#foreach($paramName in $request.getParameterMap().keySet())
689 - #if($paramName.startsWith('xaction_'))
690 - #set($action = $paramName.substring(8))
703 +#set ($action = 'edit')
704 +#foreach ($paramName in $request.getParameterMap().keySet())
705 + #if ($paramName.startsWith('xaction_'))
706 + #set ($action = $paramName.substring(8))
691 691   #break
692 692   #end
693 693  #end
694 -#if($action == 'edit')
710 +#if ($action == 'edit')
695 695   #doEdit()
696 -#elseif($action == 'save' || $action == 'saveandcontinue')
697 - #if($services.csrf.isTokenValid($request.form_token))
712 +#elseif ($action == 'save' || $action == 'saveandcontinue')
713 + #if ($services.csrf.isTokenValid($request.form_token))
698 698   #doSave()
699 699   #else
700 - $response.sendRedirect($services.csrf.getResubmissionURL());
716 + $response.sendRedirect($services.csrf.getResubmissionURL())
701 701   #end
702 702  #end
719 +{{/html}}
703 703  {{/velocity}}
XWiki.JavaScriptExtension[2]
Code
... ... @@ -367,7 +367,11 @@
367 367   hintInput.title = 'Hint';
368 368   }
369 369   // Move the hint input below the pretty name input, in the field viewer.
370 + var dd = hintInput.up('dd');
371 + var dt = dd.previous('dt');
370 370   field.getViewer().down('label').insert({after: hintInput});
373 + dt.remove();
374 + dd.remove();
371 371   // Enhance the hint input.
372 372   new XWiki.InputWithTitle(hintInput);
373 373   new XWiki.AutoResizeInput(hintInput);
... ... @@ -426,7 +426,7 @@
426 426   });
427 427   },
428 428   _onDrop : function(field) {
429 - var fieldContainer = new Element('li');
433 + var fieldContainer = new Element('li', {'data-new': 'true'});
430 430   this.fields.insert(fieldContainer);
431 431   this.container.removeClassName('empty');
432 432   new XWiki.FormField(fieldContainer).enhance(field.down('.data').value);
... ... @@ -516,10 +516,10 @@
516 516   if (!form) {
517 517   return false;
518 518   }
519 - // Let the sheet handle the form submit.
520 - // NOTE: The code that handles Save&Continue uses this URL to make the AJAX request and Firefox 3.6 doesn't resolve
521 - // the empty string to the current page URL so we have to explicitly specify it.
522 - form.action = window.location.href;
523 + // Let the sheet handle the form submit. The form is submitted by default to the preview action which dispatches the
524 + // request to the save action if the save button is detected on the request parameters. By submitting to the edit
525 + // action the edit sheet is evaluated and thus it can handle the save by itself.
526 + form.action = XWiki.currentDocument.getURL('edit');
523 523  
524 524   // Apply the vertical form layout standard.
525 525   form.addClassName('xform');
... ... @@ -558,3 +558,44 @@
558 558   }
559 559   (XWiki.domIsLoaded && init()) || document.observe('xwiki:dom:loaded', init);
560 560  }).call();
565 +
566 +require(['jquery', 'xwiki-events-bridge'], function($) {
567 + $(document).on('xwiki:class:displayField xwiki:class:previewField', function(event, data) {
568 + var container = $(data.field.getContainer());
569 + if (container.attr('data-new') === 'true') {
570 + // We can't suggest property values for properties that don't exist yet (have not been saved) so we provide
571 + // suggestions for the template property that was used to create them. Note that the suggested values depend on
572 + // the saved property meta data so changing the property (field) meta data may not affect the suggestions until
573 + // those changes are saved.
574 + var templateHiddenInput = container.find('#' + 'template-' + data.field.getName());
575 + var propertyValueSuggester = container.find('.field-viewer .suggest-propertyValues').first();
576 + propertyValueSuggester.attr({
577 + 'data-className': templateHiddenInput.val(),
578 + 'data-propertyName': templateHiddenInput.attr('data-propertyName')
579 + });
580 + }
581 + }).on('xwiki:document:saved', function(event) {
582 + // We need to update the property value suggesters because:
583 + // * newly saved properties should have their own suggestions instead of relying on the template property
584 + // * for renamed properties we need to fetch the suggestions from a different location
585 + $('ul#fields > li').each(function() {
586 + var container = $(this);
587 + container.removeAttr('data-new');
588 + var propertyValueSuggester = container.find('.field-viewer .suggest-propertyValues').first();
589 + if (propertyValueSuggester.length > 0) {
590 + // We need to preserve the selected values because they are lost when the suggester is destroyed.
591 + var selectedValues = propertyValueSuggester.children();
592 + propertyValueSuggester[0].selectize.destroy();
593 + // Restore the selected values.
594 + propertyValueSuggester.empty().append(selectedValues);
595 + var className = XWiki.Model.serialize(XWiki.currentDocument.documentReference.relativeTo(
596 + new XWiki.WikiReference(XWiki.currentWiki)));
597 + propertyValueSuggester.attr({
598 + 'data-className': className,
599 + 'data-propertyName': propertyValueSuggester.attr('name').substr((className + '_0_').length)
600 + });
601 + propertyValueSuggester.suggestPropertyValues();
602 + }
603 + });
604 + });
605 +});
XWiki.StyleSheetExtension[1]
Code
... ... @@ -38,7 +38,9 @@
38 38  }
39 39  
40 40  #fields input.xHint {
41 - border: 0 none;
41 + color: $theme.textSecondaryColor;
42 + font-size: smaller;
43 + font-weight: normal;
42 42  }
43 43  
44 44  #fields .labelLine label {