From version 1.1 >
edited by Xwiki Admin
on 2018/03/14 16:00
To version < 4.1
edited by Xwiki Admin
on 2019/12/20 09:53
Change comment: Install extension [org.xwiki.platform:xwiki-platform-appwithinminutes-ui/11.10.1]

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 {

Field Palette

Drag & drop fields from the palette to create the form that will be used to input your data.

  • Standard
    • Short Text Short Text
    • Long Text Long Text
    • Number Number
    • Boolean Boolean
    • Static List Static List
  • Standard
    • Short Text Short Text
    • Long Text Long Text
    • Number Number
    • Boolean Boolean
    • Static List Static List
  • Pickers
    • Page Page
    • Date Date
    • User User
    • Group Group
  • Pickers
    • Page
    • Date
    • User
    • Group
  • Page
    • Content Content
    • Title Title
  • Page
    • Content
    • Title
  • Advanced
    • Database List Database List
  • Advanced
    • Database List Database List

Drag fields from the palette and drop them in this area.

Drag fields from the palette and drop them in this area.

    My Recent Modifications

    Need help?

    If you need help with XWiki you can contact:

    ----------------------------