Show last authors
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 https://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 ## 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}}
94 #end
95 #end
96 )))
97 #end
98
99 #**
100 * Displays the field canvas.
101 *#
102 #macro(displayFieldCanvas)
103 #set($propertyType2FormField = {})
104 #foreach($formFieldDoc in $formFieldDocs)
105 ## Use the type of the field template.
106 #set($type = $formFieldDoc.getxWikiClass().properties.get(0).classType)
107 #set($discard = $propertyType2FormField.put($type, $formFieldDoc))
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 #end
124 #end
125 #if(!$empty)
126 ## Leave an empty line to separate the blocks.
127
128 #end
129 ##
130 (% class="hidden" %)
131 {{html}}
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)
134 #displayFieldMetaData($field)
135 #end
136 {{/html}}
137 )))
138 #end
139
140 #**
141 * Display the options to create/update the class template, the class sheet and the class translation bundle.
142 *#
143 #macro(displayClassOptions)
144 #set ($className = $stringtool.removeEnd($doc.fullName, 'Class'))
145 #set ($templateReference = $services.model.resolveDocument("${className}Template"))
146 #set ($translationsReference = $services.model.resolveDocument("${className}Translations"))
147 #set ($classSheets = $services.sheet.getClassSheets($doc))
148 #set ($sheetReference = $null)
149 #if ($classSheets.isEmpty())
150 #set ($sheetReference = $services.model.resolveDocument("${className}Sheet"))
151 #elseif ($classSheets.size() == 1)
152 #set ($sheetReference = $classSheets.get(0))
153 #end
154 {{html}}
155 ## Hide the options if neither the sheet nor the template nor the translation bundle exists. They don't have to be
156 ## updated, they have to be created.
157 <dl id="options" #if (!$xwiki.exists($sheetReference) && !$xwiki.exists($templateReference)
158 && !$xwiki.exists($translationsReference))class="hidden"#end>
159 <dt>
160 <label for="updateClassTemplate">
161 <input type="checkbox" id="updateClassTemplate" name="updateClassTemplate" checked="checked" />
162 $services.localization.render('platform.appwithinminutes.classEditorUpdateTemplateLabel')
163 </label>
164 </dt>
165 <dd>
166 <span class="xHint">
167 $services.localization.render('platform.appwithinminutes.classEditorUpdateTemplateHint',
168 ["#pageLink($templateReference)"])
169 </span>
170 </dd>
171 <dt>
172 <label for="updateClassSheet">
173 <input type="checkbox" id="updateClassSheet" name="updateClassSheet"
174 #if ($sheetReference)checked="checked" #{else}disabled="disabled" #end/>
175 $services.localization.render('platform.appwithinminutes.classEditorUpdateSheetLabel')
176 </label>
177 </dt>
178 <dd>
179 #if ($sheetReference)
180 <span class="xHint">
181 $services.localization.render('platform.appwithinminutes.classEditorUpdateSheetHint',
182 ["#pageLink($sheetReference)"])
183 </span>
184 #else
185 <span class="warningmessage">
186 $services.localization.render('platform.appwithinminutes.classEditorMultipleSheetsWarning')
187 </span>
188 #end
189 </dd>
190 <dt>
191 <label for="updateClassTranslations">
192 <input type="checkbox" id="updateClassTranslations" name="updateClassTranslations" checked="checked" />
193 $services.localization.render('platform.appwithinminutes.classEditorUpdateTranslationsLabel')
194 </label>
195 </dt>
196 <dd>
197 <span class="xHint">
198 $services.localization.render('platform.appwithinminutes.classEditorUpdateTranslationsHint',
199 ["#pageLink($translationsReference)"])
200 </span>
201 </dd>
202 </dl>
203 {{/html}}
204 #end
205
206 #macro (pageLink $reference)
207 #set ($class = 'wikilink')
208 #set ($action = 'view')
209 #set ($params = {})
210 #if (!$xwiki.exists($reference))
211 #set ($class = 'wikicreatelink')
212 #set ($action = 'create')
213 #set ($discard = $params.put('parent', $doc.fullName))
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 #end
221
222 #**
223 * Display a form field.
224 *#
225 #macro(displayField $field $formFieldDoc)
226 #if($formFieldDoc.getObject('XWiki.StyleSheetExtension'))
227 #set($discard = $xwiki.ssx.use($formFieldDoc.fullName))
228 #end
229 #if($formFieldDoc.getObject('XWiki.JavaScriptExtension'))
230 #set($discard = $xwiki.jsx.use($formFieldDoc.fullName))
231 #end
232 (% class="hidden" %)
233 {{html}}
234 #displayFieldMetaData($field)
235 ## We need this information to avoid querying and loading all FormField documents twice.
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))
243 ## Simulate the editing of the class instance from the template document.
244 ## Note that we can't simply call display on the template document because $field could be a new field that hasn't
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)
259 #end
260 #end
261 #end
262
263 #**
264 * Display the field meta data. This is needed to preserve the field when its type is not supported by the editor.
265 *#
266 #macro(displayFieldMetaData $field)
267 <input type="hidden" id="type-$field.name" name="type-$field.name" value="$field.classType" />
268 #end
269
270 #**
271 * Displays a configuration property of a class field. This macro can also be used to display a property of an object.
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}}
277 #else
278 ; {{html}}<label for="${prefix}$property.name">$escapetool.xml($property.prettyName)</label>{{/html}}
279 : {{html clean="false"}}#displayPropertyEditInput($property, $prefix, $field){{/html}}
280 #end
281 #end
282
283 #**
284 * Displays the input used to edit the specified property of the given object. The given object can be either an
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.
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)
292 #else
293 $doc.displayEdit($property, $prefix, $object)
294 #end
295 #end
296
297 #**
298 * Called when a new form field is added via AJAX.
299 *#
300 #macro(displayNewField)
301 ## Output the SkinExtension hooks to allow field displayers to pull JavaScript/CSS resources.
302 ## The class editor moves this resource includes in the HTML page head.
303 {{html}}
304 #skinExtensionHooks
305 {{/html}}
306
307 #set($formFieldDoc = $xwiki.getDocument($request.field))
308 #set($formFieldDocClassFields = $formFieldDoc.getxWikiClass().getXWikiClass().properties)
309 #if($formFieldDocClassFields.size() > 0)
310 ## Clone the field template.
311 #set($field = $formFieldDocClassFields.get(0).clone())
312 #if("$!field.prettyName" == '')
313 #set($discard = $field.setPrettyName($formFieldDoc.title))
314 #end
315 #set($discard = $doc.getxWikiClass().getXWikiClass().addField($field.name, $field))
316 #displayField($doc.getxWikiClass().get($field.name) $formFieldDoc)
317 #else
318 Unsupported form field.
319 #end
320 #end
321
322 #**
323 * Preview a class field (requires Programming Right).
324 *#
325 #macro(previewField)
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)))
331 #break
332 #end
333 #end
334 ##
335 ## Clone the field template.
336 #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
337 ##
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))
341 ##
342 ## Don't rename the field (ignore the submitted name).
343 #set($discard = $field.setName($fieldName))
344 ##
345 ## We have to add the field to the class before setting its value.
346 ## (otherwise the field value from the request is ignored).
347 #set($xclass = $doc.getxWikiClass().getXWikiClass())
348 #set($discard = $xclass.addField($fieldName, $field))
349 ##
350 ## Create an object that has this field and set its value from request.
351 #set($object = $fieldTemplateDoc.getObject($doc.fullName, true))
352 ##
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))
358 #end
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()))
363 #end
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}}
370 #end
371
372 #**
373 * Display the edit class form.
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')
381 #appWizardHeader('structure')
382
383 #end
384 #displayFieldPalette()
385 #displayFieldCanvas()
386 #displayClassOptions()
387 #if("$!request.wizard" == 'true')
388
389 #appWizardFooter('structure')
390 #end
391 (% class="clearfloats" %)((()))
392 #end
393
394 #**
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 *#
397 #macro(doEdit)
398 #if("$!request.field" != '')
399 #displayNewField()
400 #elseif("$!request.preview" == 'true')
401 #previewField()
402 #else
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
407 #displayEditForm()
408 #end
409 #end
410
411 #**
412 * Create the home page of the application code space, if it doesn't exist already.
413 *#
414 #macro (maybeCreateCodeSpace)
415 #set ($codeHomePageReference = $services.model.resolveDocument('', 'default', $doc.documentReference.parent))
416 #if (!$xwiki.exists($codeHomePageReference))
417 #set ($codeSpaceTemplate = $services.model.resolveDocument('AppWithinMinutes.CodeSpaceTemplate'))
418 #set ($copyAsJob = $services.refactoring.copyAs($codeSpaceTemplate, $codeHomePageReference))
419 #try()
420 #set ($discard = $copyAsJob.join())
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
426 #end
427 #end
428 #end
429
430 #**
431 * Updates and saves the class definition based on the submitted data.
432 *#
433 #macro(updateAndSaveClass)
434 #set($class = $doc.xWikiClass)
435 #set($xclass = $class.getXWikiClass().clone())
436 #set($xdoc = $doc.document)
437 ##
438 ## Handle new fields and field type changes.
439 ##
440 #set($fieldNames = [])
441 #foreach($paramName in $request.getParameterMap().keySet())
442 #if($paramName.startsWith('type-'))
443 #set($fieldName = $paramName.substring(5))
444 #set($fieldType = $request.getParameter($paramName))
445 #set($field = $class.get($fieldName))
446 #if(!$field || $field.classType != $fieldType)
447 #if($field)
448 ## The field type has changed. Remove the field and add a new one with the proper type.
449 #set($discard = $xclass.removeField($fieldName))
450 #end
451 ## Add a new class field with the specified type.
452 #set($fieldTemplateRef = $request.getParameter("template-$fieldName"))
453 #if("$!fieldTemplateRef" != '')
454 #set($fieldTemplateDoc = $xwiki.getDocument($fieldTemplateRef))
455 #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone())
456 #set($discard = $field.setObject($xclass))
457 #set($discard = $xclass.addField($fieldName, $field))
458 #set($discard = $fieldNames.add($fieldName))
459 #set($discard = $xdoc.setMetaDataDirty(true))
460 #end
461 #else
462 #set($discard = $fieldNames.add($fieldName))
463 #end
464 #end
465 #end
466 ##
467 ## Handle deleted fields.
468 ##
469 #foreach($field in $class.properties)
470 #if(!$fieldNames.contains($field.name))
471 #set($discard = $xclass.removeField($field.name))
472 #end
473 #end
474 ##
475 ## Handle field updates.
476 ##
477 #set($fieldsToRename = {})
478 #foreach($fieldName in $xclass.propertyNames)
479 #set($field = $xclass.get($fieldName))
480 #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName"))
481 #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field))
482 #if($field.name.matches('^[a-zA-Z_][\w:\-\.]*$'))
483 #if($fieldName != $field.name)
484 ## The field name has changed.
485 #if($xclass.get($field.name))
486 ## There is already a field with the same name.
487 #set($errorMessage = $services.localization.render('platform.appwithinminutes.classEditorDuplicateFieldNameError', [$field.name]))
488 #break
489 #else
490 #set($discard = $xclass.removeField($fieldName))
491 #set($discard = $xclass.addField($field.name, $field))
492 #set($originalField = $class.get($fieldName))
493 #if($originalField)
494 ## This is not a new field.
495 #set($discard = $fieldsToRename.put($fieldName, $field.name))
496 #set($discard = $xclass.addPropertyForRemoval($originalField.propertyClass))
497 #end
498 #end
499 #end
500 #else
501 #set($errorMessage = $services.localization.render('propertynamenotcorrect'))
502 #break
503 #end
504 #end
505 ##
506 ## Save
507 ##
508 #if(!$errorMessage)
509 #set($discard = $xdoc.setXClass($xclass))
510 #set($discard = $xdoc.renameProperties($doc.documentReference, $fieldsToRename))
511 #set($discard = $xdoc.setHidden(true))
512 #set($discard = $xdoc.setMetaDataDirty(true))
513 #set($discard = $doc.save($services.localization.render('core.comment.updateClassProperty'), $minorEdit))
514 #end
515 ##
516 ## Handle field renames.
517 ##
518 #if(!$errorMessage && !$fieldsToRename.isEmpty())
519 ## 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.
520 ## 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.
521 ##
522 ## 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
523 ## as well. Note that there is a possibility that objects in the class' document are automatically updated. Needs checking.
524 ##
525 ## We use HQL because XWQL doesn't allow us to escape the special characters from the class name.
526 #set($instancesStatement = ', BaseObject as obj where doc.fullName = obj.name and obj.className = :className'
527 + ' and doc.fullName not in (:className, :templateName)')
528 #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
529 #set($instancesQuery = $services.query.hql($instancesStatement).bindValue('className', $doc.fullName).bindValue(
530 'templateName', "${className}Template"))
531 #foreach($instanceDocName in $instancesQuery.execute())
532 #set($instanceDoc = $xwiki.getDocument($instanceDocName))
533 #set($discard = $instanceDoc.document.renameProperties($doc.documentReference, $fieldsToRename))
534 #set($discard = $instanceDoc.save($services.localization.render('core.comment.updateClassPropertyName'), true))
535 #end
536 #end
537 #end
538
539 #**
540 * Handle Date fields that have the "Empty is today" option checked in the class edit form.
541 * See https://jira.xwiki.org/browse/XWIKI-10296
542 **#
543 #macro(handleEmptyIsTodayDateFields $templateDoc)
544 #foreach($property in $doc.xWikiClass.properties)
545 ## We check directly on the request if the user provided an empty date. We can not check from the template
546 ## document's object that we've just parsed from the request using the updateObjectFromRequest method because it
547 ## already applies the emtpyIsToday mechanism and that would not be good for us.
548 #set($newValueRequestParameterName = "${doc.fullName}_0_${property.name}")
549 #set($newDateStringValue = "$!{request.getParameter($newValueRequestParameterName)}")
550 #if($property.classType == 'Date' && $property.getValue('emptyIsToday') == 1 && $newDateStringValue == '')
551 #set($discard = $templateDoc.set($property.name, $MAGIC_DATE))
552 #end
553 #end
554 #end
555
556 #**
557 * Updates and saves the class template based on the submitted data.
558 *#
559 #macro(updateAndSaveTemplate)
560 #if(!$errorMessage && $request.updateClassTemplate)
561 #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
562 #set($templateRef = $services.model.resolveDocument("${className}Template"))
563 #set($templateDoc = $xwiki.getDocument($templateRef))
564 #set($discard = $templateDoc.setParent($doc.name))
565 #if ($request.templateTitle)
566 #set($discard = $templateDoc.setTitle($request.templateTitle))
567 #end
568 #if ($request.templateContent)
569 #set($discard = $templateDoc.setContent($request.templateContent))
570 #end
571 ## Rename the properties of the template's object, if applicable.
572 #set($discard = $templateDoc.document.renameProperties($doc.documentReference, $fieldsToRename))
573 ## Fill the template's object with the default values from the class editor's form.
574 #set($discard = $templateDoc.updateObjectFromRequest($doc.fullName))
575 ##
576 #handleEmptyIsTodayDateFields($templateDoc)
577 #set($discard = $templateDoc.setHidden(true))
578 #set($discard = $templateDoc.save(
579 $services.localization.render('platform.appwithinminutes.classEditorTemplateSaveComment'),
580 $minorEdit))
581 #end
582 #end
583
584 #**
585 * Updates and saves the class sheet based on the submitted data.
586 *#
587 #macro(updateAndSaveSheet)
588 #if(!$errorMessage && $request.updateClassSheet)
589 #set($classSheets = $services.sheet.getClassSheets($doc))
590 #if($classSheets.isEmpty())
591 #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
592 #set($sheetReference = $services.model.resolveDocument("${className}Sheet"))
593 #set($discard = $services.sheet.bindClassSheet($doc, $sheetReference))
594 #set($discard = $doc.save($services.localization.render('platform.appwithinminutes.classEditorBindSheetSaveComment'),
595 $minorEdit))
596 #elseif($classSheets.size() == 1)
597 #set($sheetReference = $classSheets.get(0))
598 #end
599 #if($sheetReference)
600 #set($sheetDoc = $xwiki.getDocument($sheetReference))
601 #set($sheetGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassSheetGenerator'))
602 #set($discard = $sheetDoc.setParent($doc.name))
603 #set($discard = $sheetDoc.setContent($doc.getRenderedContent($sheetGeneratorDoc.content,
604 $sheetGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
605 #set($discard = $sheetDoc.setHidden(true))
606 #set($discard = $sheetDoc.save($services.localization.render('platform.appwithinminutes.classEditorSheetSaveComment'),
607 $minorEdit))
608 #end
609 #end
610 #end
611
612 #**
613 * Updates and saves the class translation bundle based on the submitted data.
614 *#
615 #macro(updateAndSaveTranslations)
616 #if(!$errorMessage && $request.updateClassTranslations)
617 #set($className = $stringtool.removeEnd($doc.fullName, 'Class'))
618 #set($translationsRef = $services.model.resolveDocument("${className}Translations"))
619 #set($translationsDoc = $xwiki.getDocument($translationsRef))
620 #set($translationsObj = $translationsDoc.getObject('XWiki.TranslationDocumentClass', true))
621 #set ($scope = 'USER')
622 #if ($services.security.authorization.hasAccess('admin', $doc.documentReference.wikiReference))
623 #set ($scope = 'WIKI')
624 #end
625 #set($discard = $translationsObj.set('scope', $scope))
626 #set($discard = $translationsDoc.setParent($doc.name))
627 #set($translationsGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassTranslationsGenerator'))
628 #set($discard = $translationsDoc.setContent($doc.getRenderedContent($translationsGeneratorDoc.content,
629 $translationsGeneratorDoc.syntax.toIdString(), 'plain/1.0')))
630 #set($discard = $translationsDoc.setHidden(true))
631 #set($discard = $translationsDoc.save(
632 $services.localization.render('platform.appwithinminutes.classEditorTranslationsSaveComment'),
633 $minorEdit))
634 #end
635 #end
636
637 #**
638 * Updates and saves the class definition, the class sheet and the class template.
639 *#
640 #macro(doSave)
641 #set($minorEdit = "$!request.minorEdit" != '')
642 #maybeCreateCodeSpace
643 #updateAndSaveClass
644 #updateAndSaveTemplate
645 #updateAndSaveSheet
646 #updateAndSaveTranslations
647 #if($action == 'save')
648 #if($errorMessage)
649 {{error}}{{html}}$errorMessage{{/html}}{{/error}}
650 #elseif("$!request.wizard" == 'true')
651 ## Redirect to next wizard step.
652 #set ($className = $stringtool.removeEnd($doc.fullName, 'Class'))
653 #set ($templateProviderReference = $services.model.resolveDocument("${className}TemplateProvider"))
654 #set ($queryString = {
655 'wizard': true,
656 'sheet': 'AppWithinMinutes.TemplateProviderEditSheet'
657 })
658 #if (!$xwiki.exists($templateProviderReference))
659 #set ($discard = $queryString.putAll({
660 'template': 'XWiki.TemplateProviderTemplate',
661 'parent': $doc.fullName
662 }))
663 #end
664 $response.sendRedirect($xwiki.getURL($templateProviderReference, 'edit', $escapetool.url($queryString)))
665 #else
666 ## Redirect to view mode.
667 $response.sendRedirect($doc.getURL())
668 #end
669 #else
670 #if($errorMessage)
671 $response.sendError(400, $errorMessage)
672 #else
673 $response.setStatus(204)
674 #end
675 #end
676 #end
677 {{/velocity}}
678
679 {{velocity}}
680 #if("$!request.wizard" == 'true')
681 {{include reference="AppWithinMinutes.WizardStep" /}}
682 #end
683 {{/velocity}}
684
685 {{velocity}}
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))
691 #break
692 #end
693 #end
694 #if($action == 'edit')
695 #doEdit()
696 #elseif($action == 'save' || $action == 'saveandcontinue')
697 #if($services.csrf.isTokenValid($request.form_token))
698 #doSave()
699 #else
700 $response.sendRedirect($services.csrf.getResubmissionURL());
701 #end
702 #end
703 {{/velocity}}

My Recent Modifications

Need help?

If you need help with XWiki you can contact:

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