Versión 2.1 por Administrator el 2024/06/05 19:09

Ocultar los últimos autores
Administrator 2.1 1 {{groovy}}
2 import com.xpn.xwiki.XWikiContext;
3 import com.xpn.xwiki.api.Context;
4 import com.xpn.xwiki.api.Object;
5 import com.xpn.xwiki.api.PropertyClass;
6 import com.xpn.xwiki.doc.XWikiDocument;
7 import com.xpn.xwiki.objects.BaseObject;
8
9 /**
10 * Used to preview class fields that have a custom display associated, before they are actually added/saved to the
11 * class. For instance, when the user drags a Date field from the palette to the field canvas the class editor needs to
12 * display that Date field as if the user would be editing an object with this Date field in "Inline form" edit mode.
13 * This means that if the Date field has a custom display, the custom display should be used (e.g. using a Date picker).
14 */
15 class PropertyCustomDisplayer
16 {
17 private XWikiContext context;
18
19 public PropertyCustomDisplayer(Context context)
20 {
21 this.context = context.getContext();
22 }
23
24 public String display(PropertyClass property, String prefix, com.xpn.xwiki.api.Object object)
25 {
26 HashMap<String, Object> backup = new HashMap<String, Object>();
27 try {
28 XWikiDocument.backupContext(backup, this.context);
29 return this.displayInternal(property.getPropertyClass(), prefix, object.getXWikiObject());
30 } finally {
31 XWikiDocument.restoreContext(backup, this.context);
32 }
33 }
34
35 private String displayInternal(com.xpn.xwiki.objects.classes.PropertyClass property, String prefix, BaseObject object)
36 {
37 StringBuffer result = new StringBuffer();
38 property.displayCustom(result, property.getName(), prefix, "edit", object, this.context);
39 return result.toString();
40 }
41 }
42 xcontext.put('propertyCustomDisplayer', new PropertyCustomDisplayer(xcontext))
43 {{/groovy}}
44
45 {{velocity output="false"}}
46 #**
47 * Constants
48 *#
49 ## Magic date used to mark in AWM that the date field is not set for the current entry. See http://jira.xwiki.org/browse/XWIKI-10296
50 #set($MAGIC_DATE = $datetool.toDate('yyyy-MM-dd', '9999-12-31'))
51
52 #**
53 * Displays the field palette.
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
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))
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 <input type="hidden" value="$doc.getURL('edit', "xpage=plain&sheet=AppWithinMinutes.ClassEditSheet&field=$escapetool.url($formFieldDoc.fullName)")" class="data"/>
89 {{/html}}
90 #end
91 #end
92 )))
93 #end
94
95 #**
96 * Displays the field canvas.
97 *#
98 #macro(displayFieldCanvas)
99 #set($propertyType2FormField = {})
100 #foreach($formFieldDoc in $formFieldDocs)
101 ## Use the type of the field template.
102 #set($type = $formFieldDoc.getxWikiClass().properties.get(0).classType)
103 #set($discard = $propertyType2FormField.put($type, $formFieldDoc))
104 #end
105 (% id="canvas" %)
106 (((
107 (% class="hint" %)
108 $services.localization.render('platform.appwithinminutes.classEditorCanvasHint')
109
110 #set($unknownFields = [])
111 #set($empty = true)
112 #foreach ($field in $doc.getxWikiClass().properties)
113 #set($formFieldDoc = $propertyType2FormField.get($field.classType))
114 #if($formFieldDoc)
115 #set($empty = false)
116 * (((#displayField($field $formFieldDoc))))
117 #else
118 #set($discard = $unknownFields.add($field))
119 #end
120 #end
121 #if(!$empty)
122 ## Leave an empty line to separate the blocks.
123
124 #end
125 ##
126 (% class="hidden" %)
127 {{html}}
128 ## Output the field meta data even if the field is not supported to preserve it when the class is saved.
129 #foreach($field in $unknownFields)
130 #displayFieldMetaData($field)
131 #end
132 {{/html}}
133 )))
134 #end
135
136 #**
137 * Display the options to create/update the class template, the class sheet and the class translation bundle.
138 *#
139 #macro(displayClassOptions)
140 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
141 #set($templateName = "${className}Template")
142 #set($translationsName = "${className}Translations")
143 #set($classSheets = $services.sheet.getClassSheets($doc))
144 #if($classSheets.isEmpty())
145 #set($sheetName = "${className}Sheet")
146 #elseif($classSheets.size() == 1)
147 #set($sheetName = $services.model.serialize($classSheets.get(0)))
148 #end
149 {{html wiki="true"}}
150 ## Hide the options if neither the sheet nor the template nor the translation bundle exists. They don't have to be updated, they have to be created.
151 (% id="options" #if(!$xwiki.exists($sheetName) && !$xwiki.exists($templateName) && !$xwiki.exists($translationsName))class="hidden" #end%)
152 ; <label for="updateClassTemplate"><input type="checkbox" id="updateClassTemplate" name="updateClassTemplate" checked="checked" />$services.localization.render('platform.appwithinminutes.classEditorUpdateTemplateLabel')</label>
153 : (% class="xHint" %)$services.localization.render('platform.appwithinminutes.classEditorUpdateTemplateHint', "[[$templateName]]")
154 ; <label for="updateClassSheet"><input type="checkbox" id="updateClassSheet" name="updateClassSheet" #if($sheetName)checked="checked" #{else}disabled="disabled" #end/>$services.localization.render('platform.appwithinminutes.classEditorUpdateSheetLabel')</label>
155 : #if($sheetName)
156 (% class="xHint" %)$services.localization.render('platform.appwithinminutes.classEditorUpdateSheetHint', "[[$sheetName]]")
157 #else
158 (% class="warningmessage" %)$services.localization.render('platform.appwithinminutes.classEditorMultipleSheetsWarning')
159 #end
160 ; <label for="updateClassTranslations"><input type="checkbox" id="updateClassTranslations" name="updateClassTranslations" checked="checked" />$services.localization.render('platform.appwithinminutes.classEditorUpdateTranslationsLabel')</label>
161 : (% class="xHint" %)$services.localization.render('platform.appwithinminutes.classEditorUpdateTranslationsHint', "[[$translationsName]]")
162 {{/html}}
163 #end
164
165 #**
166 * Display a form field.
167 *#
168 #macro(displayField $field $formFieldDoc)
169 #if($formFieldDoc.getObject('XWiki.StyleSheetExtension'))
170 #set($discard = $xwiki.ssx.use($formFieldDoc.fullName))
171 #end
172 #if($formFieldDoc.getObject('XWiki.JavaScriptExtension'))
173 #set($discard = $xwiki.jsx.use($formFieldDoc.fullName))
174 #end
175 (% class="hidden" %)
176 {{html}}
177 #displayFieldMetaData($field)
178 ## We need this information to avoid querying and loading all FormField documents twice.
179 ## NOTE: We use a different ID format to avoid collisions with the field meta properties.
180 <input type="hidden" id="template-$field.name" name="template-$field.name" value="$escapetool.xml($formFieldDoc.fullName)" />
181 {{/html}}
182
183 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
184 #set($templateRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Template"))
185 #set($templateDoc = $xwiki.getDocument($templateRef))
186 ## Simulate the editing of the class instance from the template document.
187 ## Note that we can't simply call display on the template document because $field could be a new field that hasn't
188 ## been added to the class yet (so the object from the template doesn't have this field yet).
189 (% class="field-viewer" %)
190 #displayFieldProperty($field "${doc.fullName}_0_" $templateDoc.getObject($doc.fullName, true))
191
192 #set($propertyNames = ['name', 'prettyName', 'number', 'required', 'hint'])
193 #set($formFieldObj = $formFieldDoc.getObject('AppWithinMinutes.FormFieldClass'))
194 #set($customPropertyNames = $formFieldObj.getProperty('properties').value.split('\s+'))
195 #set($discard = $customPropertyNames.removeAll($propertyNames))
196 #set($discard = $propertyNames.addAll($customPropertyNames.subList(0, $customPropertyNames.size())))
197 (% class="field-config" %)
198 #foreach($propertyName in $propertyNames)
199 #set($propertyDefinition = $field.xWikiClass.get($propertyName))
200 #if($propertyDefinition)
201 #displayFieldProperty($propertyDefinition "field-${field.name}_" $field)
202 #end
203 #end
204 #end
205
206 #**
207 * Display the field meta data. This is needed to preserve the field when its type is not supported by the editor.
208 *#
209 #macro(displayFieldMetaData $field)
210 <input type="hidden" id="type-$field.name" name="type-$field.name" value="$field.classType" />
211 #end
212
213 #**
214 * Displays a configuration property of a class field. This macro can also be used to display a property of an object.
215 *#
216 #macro(displayFieldProperty $property $prefix $field)
217 #set($displayFormType = $property.getProperty('displayFormType'))
218 #if($property.classType == 'Boolean' && (!$displayFormType || $displayFormType.value == 'checkbox'))
219 ; {{html clean="false"}}<label for="$!{prefix}$property.name">#displayPropertyEditInput($property, $prefix, $field)$escapetool.xml($property.prettyName)</label>{{/html}}
220 #else
221 ; {{html}}<label for="${prefix}$property.name">$escapetool.xml($property.prettyName)</label>{{/html}}
222 : {{html clean="false"}}#displayPropertyEditInput($property, $prefix, $field){{/html}}
223 #end
224 #end
225
226 #**
227 * Displays the input used to edit the specified property of the given object. The given object can be either an
228 * instance of an XWiki class or a class field. In the first case the property represents an object field and in the
229 * second case the property represents a field meta property.
230 *#
231 #macro(displayPropertyEditInput $property $prefix $object)
232 #set($wrappedProperty = $property.propertyClass)
233 #if($wrappedProperty.isCustomDisplayed($xcontext.context))
234 $xcontext.get('propertyCustomDisplayer').display($property, $prefix, $object)
235 #else
236 $doc.displayEdit($property, $prefix, $object)
237 #end
238 #end
239
240 #**
241 * Called when a new form field is added via AJAX.
242 *#
243 #macro(displayNewField)
244 ## Output the SkinExtension hooks to allow field displayers to pull JavaScript/CSS resources.
245 ## The class editor moves this resource includes in the HTML page head.
246 {{html}}
247 #skinExtensionHooks
248 {{/html}}
249
250 #set($formFieldDoc = $xwiki.getDocument($request.field))
251 #set($formFieldDocClassFields = $formFieldDoc.getxWikiClass().getXWikiClass().properties)
252 #if($formFieldDocClassFields.size() > 0)
253 ## Clone the field template.
254 #set($field = $formFieldDocClassFields.get(0).clone())
255 #if("$!field.prettyName" == '')
256 #set($discard = $field.setPrettyName($formFieldDoc.title))
257 #end
258 #set($discard = $doc.getxWikiClass().getXWikiClass().addField($field.name, $field))
259 #displayField($doc.getxWikiClass().get($field.name) $formFieldDoc)
260 #else
261 Unsupported form field.
262 #end
263 #end
264
265 #**
266 * Preview a class field.
267 *#
268 #macro(previewField)
269 ## Find the request parameter that specifies the field template.
270 #foreach($paramName in $request.getParameterMap().keySet())
271 #if($paramName.startsWith('template-'))
272 #set($fieldName = $paramName.substring(9))
273 #set($fieldTemplateDoc = $xwiki.getDocument($request.getParameter($paramName)))
274 #break
275 #end
276 #end
277 ##
278 ## Clone the field template.
279 #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
280 ##
281 ## Update the field meta properties based on the submitted data.
282 #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName"))
283 #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field))
284 ##
285 ## Don't rename the field (ignore the submitted name).
286 #set($discard = $field.setName($fieldName))
287 ##
288 ## We have to add the field to the class before setting its value.
289 ## (otherwise the field value from the request is ignored).
290 #set($xclass = $doc.getxWikiClass().getXWikiClass())
291 #set($discard = $xclass.addField($fieldName, $field))
292 ##
293 ## Create an object that has this field and set its value from request.
294 #set($object = $fieldTemplateDoc.getObject($doc.fullName, true))
295 ##
296 ## Filter empty values from the request, otherwise the update method could try to select an invalid value.
297 #set($values = [])
298 #foreach($value in $request.getParameterValues("${doc.fullName}_0_$fieldName"))
299 #if($value != '')
300 #set($discard = $values.add($value))
301 #end
302 #end
303 #if($values.size() > 0)
304 #set($stringArray = $request.getParameterValues("template-$fieldName"))
305 #set($discard = $xclass.fromMap({$fieldName: $values.toArray($stringArray)}, $object.getXWikiObject()))
306 #end
307 ##
308 ## Display the field.
309 #set($field = $doc.getxWikiClass().get($fieldName))
310 {{html clean="false"}}#displayPropertyEditInput($field, "${doc.fullName}_0_", $object){{/html}}
311 #end
312
313 #**
314 * Display the edit class form.
315 *#
316 #macro(displayEditForm)
317 $xwiki.jsfx.use('js/scriptaculous/dragdrop.js')##
318 $xwiki.jsx.use('AppWithinMinutes.ClassEditSheet')##
319 $xwiki.ssx.use('AppWithinMinutes.ClassEditSheet')##
320 $xwiki.ssx.use('AppWithinMinutes.ClassSheetGenerator')##
321 #if("$!request.wizard" == 'true')
322 #appWizardHeader(2)
323
324 #end
325 #displayFieldPalette()
326 #displayFieldCanvas()
327 #displayClassOptions()
328 #if("$!request.wizard" == 'true')
329
330 #appWizardFooter(2)
331 #end
332 (% class="clearfloats" %)((()))
333 #end
334
335 #**
336 * Displays either the edit class form or a new form field. The later is used when adding a new form field via AJAX.
337 *#
338 #macro(doEdit)
339 #if("$!request.field" != '')
340 #displayNewField()
341 #elseif("$!request.preview" == 'true')
342 #previewField()
343 #else
344 ## Make sure that only the sheet content is rendered when the class is saved using AJAX.
345 (% class="hidden" %)
346 {{html}}<input type="hidden" name="xpage" value="plain" />{{/html}}
347
348 #displayEditForm()
349 #end
350 #end
351
352 #**
353 * Updates and saves the class definition based on the submitted data.
354 *#
355 #macro(updateAndSaveClass)
356 #set($class = $doc.xWikiClass)
357 #set($xclass = $class.getXWikiClass().clone())
358 #set($xdoc = $doc.document)
359 ##
360 ## Handle new fields and field type changes.
361 ##
362 #set($fieldNames = [])
363 #foreach($paramName in $request.getParameterMap().keySet())
364 #if($paramName.startsWith('type-'))
365 #set($fieldName = $paramName.substring(5))
366 #set($fieldType = $request.getParameter($paramName))
367 #set($field = $class.get($fieldName))
368 #if(!$field || $field.classType != $fieldType)
369 #if($field)
370 ## The field type has changed. Remove the field and add a new one with the proper type.
371 #set($discard = $xclass.removeField($fieldName))
372 #end
373 ## Add a new class field with the specified type.
374 #set($fieldTemplateRef = $request.getParameter("template-$fieldName"))
375 #if("$!fieldTemplateRef" != '')
376 #set($fieldTemplateDoc = $xwiki.getDocument($fieldTemplateRef))
377 #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
378 #set($discard = $field.setObject($xclass))
379 #set($discard = $xclass.addField($fieldName, $field))
380 #set($discard = $fieldNames.add($fieldName))
381 #set($discard = $xdoc.setMetaDataDirty(true))
382 #end
383 #else
384 #set($discard = $fieldNames.add($fieldName))
385 #end
386 #end
387 #end
388 ##
389 ## Handle deleted fields.
390 ##
391 #foreach($field in $class.properties)
392 #if(!$fieldNames.contains($field.name))
393 #set($discard = $xclass.removeField($field.name))
394 #end
395 #end
396 ##
397 ## Handle field updates.
398 ##
399 #set($fieldsToRename = {})
400 #foreach($fieldName in $xclass.propertyNames)
401 #set($field = $xclass.get($fieldName))
402 #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName"))
403 #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field))
404 #if($field.name.matches('^[a-zA-Z_][\w:\-\.]*$'))
405 #if($fieldName != $field.name)
406 ## The field name has changed.
407 #if($xclass.get($field.name))
408 ## There is already a field with the same name.
409 #set($errorMessage = $services.localization.render('platform.appwithinminutes.classEditorDuplicateFieldNameError', $field.name))
410 #break
411 #else
412 #set($discard = $xclass.removeField($fieldName))
413 #set($discard = $xclass.addField($field.name, $field))
414 #set($originalField = $class.get($fieldName))
415 #if($originalField)
416 ## This is not a new field.
417 #set($discard = $fieldsToRename.put($fieldName, $field.name))
418 #set($discard = $xclass.addPropertyForRemoval($originalField.propertyClass))
419 #end
420 #end
421 #end
422 #else
423 #set($errorMessage = $services.localization.render('propertynamenotcorrect'))
424 #break
425 #end
426 #end
427 ##
428 ## Save
429 ##
430 #if(!$errorMessage)
431 #set($discard = $xdoc.setXClass($xclass))
432 #set($discard = $xdoc.renameProperties($doc.documentReference, $fieldsToRename))
433 #set($discard = $xdoc.setHidden(true))
434 #set($discard = $xdoc.setMetaDataDirty(true))
435 #set($discard = $doc.save($services.localization.render('core.comment.updateClassProperty'), $minorEdit))
436 #end
437 ##
438 ## Handle field renames.
439 ##
440 #if(!$errorMessage && !$fieldsToRename.isEmpty())
441 ## We need to load all documents (except the class and template, which we handle below) that have objects of this class and rename their properties.
442 ## If we don`t skip the template, we can not control the behaviour of emptyIsToday for date fields, which we want to handle in #updateAndSaveTemplate only once.
443 ##
444 ## FIXME: even if it is not a good practice to have an object in the class document, it is still possible. We should handle field renames for the class document
445 ## as well. Note that there is a possibility that objects in the class' document are automatically updated. Needs checking.
446 ##
447 #set($instancesStatement = "from doc.object($doc.fullName) as obj where doc.fullName not in (:className,:templateName)")
448 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
449 #set($templateRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Template"))
450 #set($templateFullName = $services.model.serialize($templateRef, 'local'))
451 #set($instancesQuery = $services.query.xwql($instancesStatement).bindValue('className', $doc.fullName).bindValue('templateName', $templateFullName))
452 #foreach($instanceDocName in $instancesQuery.execute())
453 #set($instanceDoc = $xwiki.getDocument($instanceDocName))
454 #set($discard = $instanceDoc.document.renameProperties($doc.documentReference, $fieldsToRename))
455 #set($discard = $instanceDoc.save($services.localization.render('core.comment.updateClassPropertyName'), true))
456 #end
457 #end
458 ##
459 ## Clear cache.
460 ##
461 #if(!$errorMessage)
462 #set($discard = $xwiki.getXWiki().flushCache($xcontext.context))
463 #end
464 #end
465
466 #**
467 * Handle Date fields that have the "Empty is today" option checked in the class edit form. See http://jira.xwiki.org/browse/XWIKI-10296
468 **#
469 #macro(handleEmptyIsTodayDateFields $templateDoc)
470 #foreach($property in $doc.xWikiClass.properties)
471 ## We check directly on the request if the user provided an empty date. We can not check from the template document's object that we've just
472 ## parsed from the request using the updateObjectFromRequest method because it already applies the emtpyIsToday mechanism and that would not be good for us.
473 #set($newValueRequestParameterName = "${doc.fullName}_0_${property.name}")
474 #set($newDateStringValue = "$!{request.getParameter($newValueRequestParameterName)}")
475 #if($property.classType == 'Date' && $property.getValue('emptyIsToday') == 1 && $newDateStringValue == '')
476 #set($discard = $templateDoc.set($property.name, $MAGIC_DATE))
477 #end
478 #end
479 #end
480
481 #**
482 * Updates and saves the class template based on the submitted data.
483 *#
484 #macro(updateAndSaveTemplate)
485 #if(!$errorMessage && $request.updateClassTemplate)
486 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
487 #set($templateRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Template"))
488 #set($templateDoc = $xwiki.getDocument($templateRef))
489 #set($discard = $templateDoc.setParent($doc.name))
490 #if ($request.templateTitle)
491 #set($discard = $templateDoc.setTitle($request.templateTitle))
492 #end
493 #if ($request.templateContent)
494 #set($discard = $templateDoc.setContent($request.templateContent))
495 #end
496 ## Rename the properties of the template's object, if applicable.
497 #set($discard = $templateDoc.document.renameProperties($doc.documentReference, $fieldsToRename))
498 ## Fill the template's object with the default values from the class editor's form.
499 #set($discard = $templateDoc.updateObjectFromRequest($doc.fullName))
500 ##
501 #handleEmptyIsTodayDateFields($templateDoc)
502 #set($discard = $templateDoc.setHidden(true))
503 #set($discard = $templateDoc.save($services.localization.render('platform.appwithinminutes.classEditorTemplateSaveComment'), $minorEdit))
504 #end
505 #end
506
507 #**
508 * Updates and saves the class sheet based on the submitted data.
509 *#
510 #macro(updateAndSaveSheet)
511 #if(!$errorMessage && $request.updateClassSheet)
512 #set($classSheets = $services.sheet.getClassSheets($doc))
513 #if($classSheets.isEmpty())
514 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
515 #set($sheetReference = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Sheet"))
516 #set($discard = $services.sheet.bindClassSheet($doc, $sheetReference))
517 #set($discard = $doc.save($services.localization.render('platform.appwithinminutes.classEditorBindSheetSaveComment'), $minorEdit))
518 #elseif($classSheets.size() == 1)
519 #set($sheetReference = $classSheets.get(0))
520 #end
521 #if($sheetReference)
522 #set($sheetDoc = $xwiki.getDocument($sheetReference))
523 #set($sheetGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassSheetGenerator'))
524 #set($discard = $sheetDoc.setParent($doc.name))
525 #set($discard = $sheetDoc.setContent($doc.getRenderedContent($sheetGeneratorDoc.content, $sheetGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
526 #set($discard = $sheetDoc.setHidden(true))
527 #set($discard = $sheetDoc.save($services.localization.render('platform.appwithinminutes.classEditorSheetSaveComment'), $minorEdit))
528 #end
529 #end
530 #end
531
532 #**
533 * Updates and saves the class translation bundle based on the submitted data.
534 *#
535 #macro(updateAndSaveTranslations)
536 #if(!$errorMessage && $request.updateClassTranslations)
537 #set($className = $stringtool.removeEnd($doc.name, 'Class'))
538 #set($translationsRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Translations"))
539 #set($translationsDoc = $xwiki.getDocument($translationsRef))
540 #set($translationsObj = $translationsDoc.getObject('XWiki.TranslationDocumentClass', true))
541 ## We use the translation bundle on demand because none of the available scopes suits our needs. Simple users can't
542 ## register document translation bundles at WIKI level and the SPACE scope doesn't remove the need to create a
543 ## custom live table results page in the same space as the application.
544 #set($discard = $translationsObj.set('scope', 'ON_DEMAND'))
545 #set($discard = $translationsDoc.setParent($doc.name))
546 #set($translationsGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassTranslationsGenerator'))
547 #set($discard = $translationsDoc.setContent($doc.getRenderedContent($translationsGeneratorDoc.content, $translationsGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
548 #set($discard = $translationsDoc.setHidden(true))
549 #set($discard = $translationsDoc.save($services.localization.render('platform.appwithinminutes.classEditorTranslationsSaveComment'), $minorEdit))
550 #end
551 #end
552
553 #**
554 * Updates and saves the class definition, the class sheet and the class template.
555 *#
556 #macro(doSave)
557 #set($minorEdit = "$!request.minorEdit" != '')
558 #updateAndSaveClass()
559 #updateAndSaveTemplate()
560 #updateAndSaveSheet()
561 #updateAndSaveTranslations()
562 #if($action == 'save')
563 #if($errorMessage)
564 {{error}}{{html}}$errorMessage{{/html}}{{/error}}
565 #elseif("$!request.wizard" == 'true')
566 ## Redirect to next wizard step.
567 #set($appName = $doc.getValue('dataSpaceName'))
568 #if("$!appName" == '')
569 ## Backwards compatibility for apps created before 6.3M2 when the code space was not properly cleaned and the data space name was restricted as a consequence.
570 #set($appName = $stringtool.removeEnd($doc.title, ' Class'))
571 #end
572 #set($homePageRef = $services.model.createDocumentReference($doc.wiki, $appName, 'WebHome'))
573 #set($queryString = 'wizard=true')
574 #if(!$xwiki.exists($homePageRef))
575 #set($homePageTitle = '$services.localization.render(''platform.appwithinminutes.appHomePageTitle'', [$doc.space])')
576 #set($queryString = "$queryString&editor=inline&template=AppWithinMinutes.LiveTableTemplate&AppWithinMinutes.LiveTableClass_0_class=$escapetool.url($doc.fullName)&title=$escapetool.url($homePageTitle)&parent=AppWithinMinutes.WebHome")
577 #end
578 $response.sendRedirect($xwiki.getURL($homePageRef, 'edit', $queryString));
579 #else
580 ## Redirect to view mode.
581 $response.sendRedirect($doc.getURL())
582 #end
583 #else
584 #if($errorMessage)
585 $response.sendError(400, $errorMessage)
586 #else
587 $response.setStatus(204)
588 #end
589 #end
590 #end
591 {{/velocity}}
592
593 {{velocity}}
594 #if("$!request.wizard" == 'true')
595 {{include reference="AppWithinMinutes.WizardStep" /}}
596 #end
597 {{/velocity}}
598
599 {{velocity}}
600 ## Determine the action button that triggered the request
601 #set($action = 'edit')
602 #foreach($paramName in $request.getParameterMap().keySet())
603 #if($paramName.startsWith('xaction_'))
604 #set($action = $paramName.substring(8))
605 #break
606 #end
607 #end
608 #if($action == 'edit')
609 #doEdit()
610 #elseif($action == 'save' || $action == 'saveandcontinue')
611 #if($services.csrf.isTokenValid($request.form_token))
612 #doSave()
613 #else
614 $response.sendRedirect($services.csrf.getResubmissionURL());
615 #end
616 #end
617 {{/velocity}}