1 #!/usr/bin/env python 2 3 "A WebStack questionnaire application." 4 5 import WebStack.Generic 6 from XSLForms.Resources.WebResources import \ 7 XSLFormsResource, input, output, resources, prepare_resources as xslforms_prepare_resources 8 import os 9 import libxml2dom 10 import xml.dom 11 12 # Site map imports. 13 14 from WebStack.Resources.ResourceMap import MapResource 15 from WebStack.Resources.Selectors import EncodingSelector 16 from WebStack.Resources.Static import DirectoryResource 17 18 # Configuration settings. 19 20 encoding = "utf-8" 21 22 # Resource classes. 23 24 class QuestionnaireEditorResource(XSLFormsResource): 25 26 "A resource providing a questionnaire editor." 27 28 resource_dir = resources(__file__) 29 template_resources = { 30 "questionnaire" : output("question_template.xhtml") 31 } 32 init_resources = { 33 "questionnaire" : input("question_template.xhtml") 34 } 35 document_resources = { 36 "response-types" : "question_response_types.xml" 37 } 38 39 def select_activity(self, trans, form): 40 form.set_activity("questionnaire") 41 42 def respond_to_input(self, trans, form): 43 44 parameters = form.get_parameters() 45 selectors = form.get_selectors() 46 questionnaire = form.get_document() 47 48 self.remove_elements(selectors.get("remove-question")) 49 self.add_elements(selectors.get("add-choice"), "choice") 50 self.remove_elements(selectors.get("remove-choice")) 51 52 # Move questions. 53 # NOTE: Potentially a DOM convenience method here. 54 55 for question in selectors.get("move-question", []): 56 57 # Only move a question to a different position. 58 59 position = question.xpath("count(preceding-sibling::question) + 1") 60 destination = int(question.getAttribute("destination")) 61 62 if destination != position: 63 64 # Where the question is before the destination, find the 65 # question after the current one at that position, since the 66 # subsequent deletion of the question being moved will then 67 # reduce the destination by one. 68 69 if destination > position: 70 destination += 1 71 72 root = questionnaire.documentElement 73 target = (root.xpath("question[position() = %d]" % destination) or [None])[0] 74 root.removeChild(question) 75 if target is not None: 76 try: 77 root.insertBefore(question, target) 78 except xml.dom.NotFoundErr: 79 target = (root.xpath("question[position() = %d]" % destination) or [None])[0] 80 root.insertBefore(question, target) 81 else: 82 root.appendChild(question) 83 84 # Add questions using the normal request parameter. 85 86 if parameters.has_key("add-question"): 87 new_question = questionnaire.ownerDocument.createElementNS(None, "question") 88 questionnaire.xpath("questionnaire")[0].appendChild(new_question) 89 90 # Send a response according to certain parameters. 91 # When exported, an XML version of the data is returned. 92 93 if parameters.has_key("export"): 94 trans.set_content_type(WebStack.Generic.ContentType("text/xml", encoding)) 95 questionnaire.toStream(trans.get_response_stream(), trans.get_response_stream_encoding(), prettyprint=1) 96 raise WebStack.Generic.EndOfResponse 97 98 # Support uploading of files. 99 100 if parameters.has_key("import"): 101 importfile = parameters["importfile"][0] 102 103 if hasattr(importfile, "stream"): 104 try: 105 doc = libxml2dom.parse(importfile.stream) 106 form.set_document(doc) 107 return # success 108 except libxml2dom.LSException: 109 pass 110 111 questionnaire.documentElement.setAttribute("error", "true") 112 113 def init_document(self, trans, form): 114 115 # Transform, adding enumerations/ranges. 116 117 response_types_xml = self.prepare_document("response-types") 118 XSLFormsResource.init_document(self, trans, form, references={"response-type" : response_types_xml}) 119 120 # Site map initialisation. 121 122 def get_site(): 123 124 "Return a simple Web site resource." 125 126 # Get the main resource and the directory used by the application. 127 128 questionnaire_resource = QuestionnaireEditorResource() 129 directory = questionnaire_resource.resource_dir 130 131 # Make a simple Web site. 132 133 resource = MapResource({ 134 # Static resources: 135 "styles" : DirectoryResource(os.path.join(directory, "styles"), {"css" : "text/css"}), 136 # Main page: 137 "" : questionnaire_resource 138 }) 139 140 return EncodingSelector(resource, encoding) 141 142 # Resource preparation ahead of time - useful for making installations. 143 144 def prepare_resources(): 145 for cls in [QuestionnaireEditorResource]: 146 xslforms_prepare_resources(cls) 147 148 # vim: tabstop=4 expandtab shiftwidth=4