General Actions:
Log-in
Register
Wiki:
Main wiki
▼
:
Document Index
»
Space:
AppWithinMinutes
▼
:
Document Index
»
Page:
ClassEditSheet
Search
default
Page Actions:
Export
▼
:
Export as PDF
Export as RTF
Export as HTML
More actions
▼
:
Print preview
View Source
Main wiki
»
App Within Minutes
»
ClassEditSheet
Wiki source code of
ClassEditSheet
Last modified by
Administrator
on 2012/03/21 17:41
Content
·
Comments
(0)
·
Annotations
(0)
·
Attachments
(3)
·
History
·
Information
Show line numbers
{{groovy}} import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.api.Context; import com.xpn.xwiki.api.Object; import com.xpn.xwiki.api.PropertyClass; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; /** * Used to preview class fields that have a custom display associated, before they are actually added/saved to the * class. For instance, when the user drags a Date field from the palette to the field canvas the class editor needs to * display that Date field as if the user would be editing an object with this Date field in "Inline form" edit mode. * This means that if the Date field has a custom display, the custom display should be used (e.g. using a Date picker). */ class PropertyCustomDisplayer { private XWikiContext context; public PropertyCustomDisplayer(Context context) { this.context = context.getContext(); } public String display(PropertyClass property, String prefix, com.xpn.xwiki.api.Object object) { HashMap<String, Object> backup = new HashMap<String, Object>(); try { XWikiDocument.backupContext(backup, this.context); return this.displayInternal(property.getPropertyClass(), prefix, object.getXWikiObject()); } finally { XWikiDocument.restoreContext(backup, this.context); } } private String displayInternal(com.xpn.xwiki.objects.classes.PropertyClass property, String prefix, BaseObject object) { StringBuffer result = new StringBuffer(); property.displayCustom(result, property.getName(), prefix, "edit", object, this.context); return result.toString(); } } xcontext.put('propertyCustomDisplayer', new PropertyCustomDisplayer(xcontext)) {{/groovy}} {{velocity output="false"}} #** * Displays the field palette. *# #macro(displayFieldPalette) (% id="palette" %) ((( **$msg.get('platform.appwithinminutes.classEditorPaletteTitle')** (% class="xHint" %) $msg.get('platform.appwithinminutes.classEditorPaletteHint') ## List all form field types, grouped by category. #set($formFieldDocs = []) #set($formFieldClassName = 'AppWithinMinutes.FormFieldClass') #set($categoryListStatement = 'from doc.object(AppWithinMinutes.FormFieldCategoryClass) as category order by category.priority') #foreach($category in $services.query.xwql($categoryListStatement).execute()) #set($categoryDoc = $xwiki.getDocument($category)) * (% class="category" %)$categoryDoc.plainTitle #set($formFieldsForCategoryStatement = "from doc.object($formFieldClassName) as field where field.category = :category order by field.priority") #set($formFieldsForCategoryQuery = $services.query.xwql($formFieldsForCategoryStatement).bindValue('category', $category)) #foreach($formField in $formFieldsForCategoryQuery.execute()) #set($formFieldDoc = $xwiki.getDocument($formField)) #set($discard = $formFieldDocs.add($formFieldDoc)) #set($formFieldIcon = $formFieldDoc.getObject($formFieldClassName).getProperty('icon').value) #if($formFieldIcon.contains('/')) #set($formFieldIconURL = $xwiki.getSkinFile($formFieldIcon)) #else #set($formFieldIconURL = $formFieldDoc.getAttachmentURL($formFieldIcon)) #end ** (% class="field" %){{html}} <img src="$formFieldIconURL" alt="$escapetool.xml($formFieldDoc.title)" class="icon" /> $escapetool.xml($formFieldDoc.plainTitle) ## FIXME: We should use the 'get' action instead to prevent the stats module from recording this AJAX request. ## The 'edit' action is a temporary solution until the sheet module is modified to allow a sheet to be enforced through ## the query string even if it doesn't match the action (e.g. the 'get' action). ## The sheet parameter is required when editing a new class because the request will be made to a document that doesn't exist. <input type="hidden" value="$doc.getURL('edit', "xpage=plain&sheet=AppWithinMinutes.ClassEditSheet&field=$escapetool.url($formFieldDoc.fullName)")" class="data"/> {{/html}} #end #end ))) #end #** * Displays the field canvas. *# #macro(displayFieldCanvas) #set($propertyType2FormField = {}) #foreach($formFieldDoc in $formFieldDocs) ## Use the type of the field template. #set($type = $formFieldDoc.getxWikiClass().properties.get(0).classType) #set($discard = $propertyType2FormField.put($type, $formFieldDoc)) #end (% id="canvas" %) ((( (% class="hint" %) $msg.get('platform.appwithinminutes.classEditorCanvasHint') #set($unknownFields = []) #set($empty = true) #foreach ($field in $doc.getxWikiClass().properties) #set($formFieldDoc = $propertyType2FormField.get($field.classType)) #if($formFieldDoc) #set($empty = false) * (((#displayField($field $formFieldDoc)))) #else #set($discard = $unknownFields.add($field)) #end #end #if(!$empty) ## Leave an empty line to separate the blocks. #end ## (% class="hidden" %) {{html}} ## Output the field meta data even if the field is not supported to preserve it when the class is saved. #foreach($field in $unknownFields) #displayFieldMetaData($field) #end {{/html}} ))) #end #** * Display the options to create/update the class template and the class sheet. *# #macro(displayClassOptions) #set($className = $doc.name) #if($className.endsWith('Class')) #set($className = $className.substring(0, $mathtool.sub($className.length(), 5))) #end #set($templateName = "${className}Template") #set($classSheets = $services.sheet.getClassSheets($doc)) #if($classSheets.isEmpty()) #set($sheetName = "${className}Sheet") #elseif($classSheets.size() == 1) #set($sheetName = $services.model.serialize($classSheets.get(0))) #end {{html wiki="true"}} ## Hide the options if neither the sheet nor the template exists. They don't have to be updated, they have to be created. (% id="options" #if(!$xwiki.exists($sheetName) && !$xwiki.exists($templateName))class="hidden" #end%) ; <label for="updateClassTemplate"><input type="checkbox" id="updateClassTemplate" name="updateClassTemplate" checked="checked" />$msg.get('platform.appwithinminutes.classEditorUpdateTemplateLabel')</label> : (% class="xHint" %)$msg.get('platform.appwithinminutes.classEditorUpdateTemplateHint', "[[$templateName]]") ; <label for="updateClassSheet"><input type="checkbox" id="updateClassSheet" name="updateClassSheet" #if($sheetName)checked="checked" #{else}disabled="disabled" #end/>$msg.get('platform.appwithinminutes.classEditorUpdateSheetLabel')</label> : #if($sheetName) (% class="xHint" %)$msg.get('platform.appwithinminutes.classEditorUpdateSheetHint', "[[$sheetName]]") #else (% class="warningmessage" %)$msg.get('platform.appwithinminutes.classEditorMultipleSheetsWarning') #end {{/html}} #end #** * Display a form field. *# #macro(displayField $field $formFieldDoc) #if($formFieldDoc.getObject('XWiki.StyleSheetExtension')) #set($discard = $xwiki.ssx.use($formFieldDoc.fullName)) #end #if($formFieldDoc.getObject('XWiki.JavaScriptExtension')) #set($discard = $xwiki.jsx.use($formFieldDoc.fullName)) #end (% class="hidden" %) {{html}} #displayFieldMetaData($field) ## We need this information to avoid querying and loading all FormField documents twice. ## NOTE: We use a different ID format to avoid collisions with the field meta properties. <input type="hidden" id="template-$field.name" name="template-$field.name" value="$escapetool.xml($formFieldDoc.fullName)" /> {{/html}} #set($className = $doc.name) #if($className.endsWith('Class')) #set($className = $className.substring(0, $mathtool.sub($className.length(), 5))) #end #set($templateRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Template")) #set($templateDoc = $xwiki.getDocument($templateRef)) ## Simulate the editing of the class instance from the template document. ## Note that we can't simply call display on the template document because $field could be a new field that hasn't ## been added to the class yet (so the object from the template doesn't have this field yet). (% class="field-viewer" %) #displayFieldProperty($field "${doc.fullName}_0_" $templateDoc.getObject($doc.fullName, true)) #set($propertyNames = ['name', 'prettyName', 'number', 'required', 'hint']) #set($formFieldObj = $formFieldDoc.getObject('AppWithinMinutes.FormFieldClass')) #set($customPropertyNames = $formFieldObj.getProperty('properties').value.split('\s+')) #set($discard = $customPropertyNames.removeAll($propertyNames)) #set($discard = $propertyNames.addAll($customPropertyNames.subList(0, $customPropertyNames.size()))) (% class="field-config" %) #foreach($propertyName in $propertyNames) #set($propertyDefinition = $field.xWikiClass.get($propertyName)) #if($propertyDefinition) #displayFieldProperty($propertyDefinition "field-${field.name}_" $field) #end #end #end #** * Display the field meta data. This is needed to preserve the field when its type is not supported by the editor. *# #macro(displayFieldMetaData $field) <input type="hidden" id="type-$field.name" name="type-$field.name" value="$field.classType" /> #end #** * Displays a configuration property of a class field. This macro can also be used to display a property of an object. *# #macro(displayFieldProperty $property $prefix $field) #set($displayFormType = $property.getProperty('displayFormType')) #if($property.type.indexOf('Boolean') != -1 && (!$displayFormType || $displayFormType.value == 'checkbox')) ; {{html clean="false"}}<label for="$!{prefix}$property.name">#displayPropertyEditInput($property, $prefix, $field)$escapetool.xml($property.prettyName)</label>{{/html}} #else ; {{html}}<label for="${prefix}$property.name">$escapetool.xml($property.prettyName)</label>{{/html}} : {{html clean="false"}}#displayPropertyEditInput($property, $prefix, $field){{/html}} #end #end #** * Displays the input used to edit the specified property of the given object. The given object can be either an * instance of an XWiki class or a class field. In the first case the property represents an object field and in the * second case the property represents a field meta property. *# #macro(displayPropertyEditInput $property $prefix $object) #set($wrappedProperty = $property.propertyClass) #if("$!wrappedProperty.customDisplay" != '') $xcontext.get('propertyCustomDisplayer').display($property, $prefix, $object) #else $doc.displayEdit($property, $prefix, $object) #end #end #** * Called when a new form field is added via AJAX. *# #macro(displayNewField) {{html}} <!-- com.xpn.xwiki.plugin.skinx.JsSkinExtensionPlugin --> <!-- com.xpn.xwiki.plugin.skinx.CssSkinExtensionPlugin --> {{/html}} #set($formFieldDoc = $xwiki.getDocument($request.field)) #set($formFieldDocClassFields = $formFieldDoc.getxWikiClass().getXWikiClass().properties) #if($formFieldDocClassFields.size() > 0) ## Clone the field template. #set($field = $formFieldDocClassFields.get(0).clone()) #if("$!field.prettyName" == '') #set($discard = $field.setPrettyName($formFieldDoc.title)) #end #set($discard = $doc.getxWikiClass().getXWikiClass().addField($field.name, $field)) #displayField($doc.getxWikiClass().get($field.name) $formFieldDoc) #else Unsupported form field. #end #end #** * Preview a class field. *# #macro(previewField) ## Find the request parameter that specifies the field template. #foreach($paramName in $request.getParameterMap().keySet()) #if($paramName.startsWith('template-')) #set($fieldName = $paramName.substring(9)) #set($fieldTemplateDoc = $xwiki.getDocument($request.getParameter($paramName))) #break #end #end ## ## Clone the field template. #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone()) ## ## Update the field meta properties based on the submitted data. #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName")) #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field)) ## ## Don't rename the field (ignore the submitted name). #set($discard = $field.setName($fieldName)) ## ## We have to add the field to the class before setting its value. ## (otherwise the field value from the request is ignored). #set($xclass = $doc.getxWikiClass().getXWikiClass()) #set($discard = $xclass.addField($fieldName, $field)) ## ## Create an object that has this field and set its value from request. #set($object = $fieldTemplateDoc.getObject($doc.fullName, true)) ## ## Filter empty values from the request, otherwise the update method could try to select an invalid value. #set($values = []) #foreach($value in $request.getParameterValues("${doc.fullName}_0_$fieldName")) #if($value != '') #set($discard = $values.add($value)) #end #end #if($values.size() > 0) #set($stringArray = $request.getParameterValues("template-$fieldName")) #set($discard = $xclass.fromMap({$fieldName: $values.toArray($stringArray)}, $object.getXWikiObject())) #end ## ## Display the field. #set($field = $doc.getxWikiClass().get($fieldName)) {{html clean="false"}}#displayPropertyEditInput($field, "${doc.fullName}_0_", $object){{/html}} #end #** * Display the edit class form. *# #macro(displayEditForm) $xwiki.jsfx.use('js/scriptaculous/dragdrop.js')## $xwiki.jsx.use('AppWithinMinutes.ClassEditSheet')## $xwiki.ssx.use('AppWithinMinutes.ClassEditSheet')## $xwiki.ssx.use('AppWithinMinutes.ClassSheetGenerator')## #if("$!request.wizard" == 'true') #appWizardHeader(2) #end #displayFieldPalette() #displayFieldCanvas() #displayClassOptions() #if("$!request.wizard" == 'true') #appWizardFooter(2) #end (% class="clearfloats" %)((())) #end #** * Displays either the edit class form or a new form field. The later is used when adding a new form field via AJAX. *# #macro(doEdit) #if("$!request.field" != '') #displayNewField() #elseif("$!request.preview" == 'true') #previewField() #else ## Make sure that only the sheet content is rendered when the class is saved using AJAX. (% class="hidden" %) {{html}}<input type="hidden" name="xpage" value="plain" />{{/html}} #displayEditForm() #end #end #** * Updates and saves the class definition based on the submitted data. *# #macro(updateAndSaveClass) #set($class = $doc.xWikiClass) #set($xclass = $class.getXWikiClass().clone()) #set($xdoc = $doc.document) ## ## Handle new fields and field type changes. ## #set($fieldNames = []) #foreach($paramName in $request.getParameterMap().keySet()) #if($paramName.startsWith('type-')) #set($fieldName = $paramName.substring(5)) #set($fieldType = $request.getParameter($paramName)) #set($field = $class.get($fieldName)) #if(!$field || $field.classType != $fieldType) #if($field) ## The field type has changed. Remove the field and add a new one with the proper type. #set($discard = $xclass.removeField($fieldName)) #end ## Add a new class field with the specified type. #set($fieldTemplateRef = $request.getParameter("template-$fieldName")) #if("$!fieldTemplateRef" != '') #set($fieldTemplateDoc = $xwiki.getDocument($fieldTemplateRef)) #set($field = $fieldTemplateDoc.getxWikiClass().getXWikiClass().properties.get(0).clone()) #set($discard = $field.setObject($xclass)) #set($discard = $xclass.addField($fieldName, $field)) #set($discard = $fieldNames.add($fieldName)) #set($discard = $xdoc.setMetaDataDirty(true)) #end #else #set($discard = $fieldNames.add($fieldName)) #end #end #end ## ## Handle deleted fields. ## #foreach($field in $class.properties) #if(!$fieldNames.contains($field.name)) #set($discard = $xclass.removeField($field.name)) #end #end ## ## Handle field updates. ## #set($fieldsToRename = {}) #foreach($fieldName in $xclass.propertyNames) #set($field = $xclass.get($fieldName)) #set($valuesFromRequest = $xcontext.context.getForm().getObject("field-$fieldName")) #set($discard = $field.getxWikiClass().fromMap($valuesFromRequest, $field)) #if($field.name.matches('^[a-zA-Z_][\w:\-\.]*$')) #if($fieldName != $field.name) ## The field name has changed. #if($xclass.get($field.name)) ## There is already a field with the same name. #set($errorMessage = $msg.get('platform.appwithinminutes.classEditorDuplicateFieldNameError', $field.name)) #break #else #set($discard = $xclass.removeField($fieldName)) #set($discard = $xclass.addField($field.name, $field)) #set($originalField = $class.get($fieldName)) #if($originalField) ## This is not a new field. #set($discard = $fieldsToRename.put($fieldName, $field.name)) #set($discard = $xclass.addPropertyForRemoval($originalField.propertyClass)) #end #end #end #else #set($errorMessage = $msg.get('propertynamenotcorrect')) #break #end #end ## ## Save ## #if(!$errorMessage) #set($discard = $xdoc.setXClass($xclass)) #set($discard = $xdoc.renameProperties($doc.documentReference, $fieldsToRename)) #set($discard = $xdoc.setMetaDataDirty(true)) #set($discard = $doc.save($msg.get('core.comment.updateClassProperty'), $minorEdit)) #end ## ## Handle field renames. ## #if(!$errorMessage && !$fieldsToRename.isEmpty()) ## We need to load all documents that have objects of this class and rename their properties. #set($instancesStatement = "from doc.object($doc.fullName) as obj where doc.fullName <> :className") #set($instancesQuery = $services.query.xwql($instancesStatement).bindValue('className', $doc.fullName)) #foreach($instanceDocName in $instancesQuery.execute()) #set($instanceDoc = $xwiki.getDocument($instanceDocName)) #set($discard = $instanceDoc.document.renameProperties($doc.documentReference, $fieldsToRename)) #set($discard = $instanceDoc.save($msg.get('core.comment.updateClassPropertyName'), true)) #end #end ## ## Clear cache. ## #if(!$errorMessage) #set($discard = $xwiki.getXWiki().flushCache($xcontext.context)) #end #end #** * Updates and saves the class template based on the submitted data. *# #macro(updateAndSaveTemplate) #if(!$errorMessage && $request.updateClassTemplate) #set($className = $doc.name) #if($className.endsWith('Class')) #set($className = $className.substring(0, $mathtool.sub($className.length(), 5))) #end #set($templateRef = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Template")) #set($templateDoc = $xwiki.getDocument($templateRef)) #set($discard = $templateDoc.setParent($doc.name)) #set($discard = $templateDoc.updateObjectFromRequest($doc.fullName)) #set($discard = $templateDoc.save($msg.get('platform.appwithinminutes.classEditorTemplateSaveComment'), $minorEdit)) #end #end #** * Updates and saves the class sheet based on the submitted data. *# #macro(updateAndSaveSheet) #if(!$errorMessage && $request.updateClassSheet) #set($classSheets = $services.sheet.getClassSheets($doc)) #if($classSheets.isEmpty()) #set($className = $doc.name) #if($className.endsWith('Class')) #set($className = $className.substring(0, $mathtool.sub($className.length(), 5))) #end #set($sheetReference = $services.model.createDocumentReference($doc.wiki, $doc.space, "${className}Sheet")) #set($discard = $services.sheet.bindClassSheet($doc, $sheetReference)) #set($discard = $doc.save($msg.get('platform.appwithinminutes.classEditorBindSheetSaveComment'), $minorEdit)) #elseif($classSheets.size() == 1) #set($sheetReference = $classSheets.get(0)) #end #if($sheetReference) #set($sheetDoc = $xwiki.getDocument($sheetReference)) #set($sheetGeneratorDoc = $xwiki.getDocument('AppWithinMinutes.ClassSheetGenerator')) #set($discard = $sheetDoc.setParent($doc.name)) #set($discard = $sheetDoc.setContent($doc.getRenderedContent($sheetGeneratorDoc.content, $sheetGeneratorDoc.syntax.toIdString(), 'plain/1.0'))) #set($discard = $sheetDoc.save($msg.get('platform.appwithinminutes.classEditorSheetSaveComment'), $minorEdit)) #end #end #end #** * Updates and saves the class definition, the class sheet and the class template. *# #macro(doSave) #set($minorEdit = "$!request.minorEdit" != '') #updateAndSaveClass() #updateAndSaveTemplate() #updateAndSaveSheet() #if($action == 'save') #if($errorMessage) {{error}}{{html}}$errorMessage{{/html}}{{/error}} #elseif("$!request.wizard" == 'true') ## Redirect to next wizard step. #set($homePageRef = $services.model.createDocumentReference($doc.wiki, $doc.space, 'WebHome')) #set($queryString = 'wizard=true') #if(!$xwiki.exists($homePageRef)) #set($homePageTitle = '$msg.get(''platform.appwithinminutes.appHomePageTitle'', $doc.space)') #set($queryString = "$queryString&editor=inline&template=AppWithinMinutes.LiveTableTemplate&AppWithinMinutes.LiveTableClass_0_class=$escapetool.url($doc.fullName)&title=$escapetool.url($homePageTitle)&parent=Main.WebHome") #end $response.sendRedirect($xwiki.getURL($homePageRef, 'edit', $queryString)); #else ## Redirect to view mode. $response.sendRedirect($doc.getURL()) #end #else #if($errorMessage) $response.sendError(400, $errorMessage) #else $response.setStatus(204) #end #end #end {{/velocity}} {{velocity}} #if("$!request.wizard" == 'true') {{include document="AppWithinMinutes.WizardStep" /}} #end {{/velocity}} {{velocity}} ## Determine the action button that triggered the request #set($action = 'edit') #foreach($paramName in $request.getParameterMap().keySet()) #if($paramName.startsWith('xaction_')) #set($action = $paramName.substring(8)) #break #end #end #if($action == 'edit') #doEdit() #elseif($action == 'save' || $action == 'saveandcontinue') #if($services.csrf.isTokenValid($request.form_token)) #doSave() #else $response.sendRedirect($services.csrf.getResubmissionURL()); #end #end {{/velocity}}