1 #!/usr/bin/env python 2 3 "A WebStack questionnaire application." 4 5 import WebStack.Generic 6 import XSLForms.Fields 7 import XSLForms.Output 8 import XSLOutput 9 import libxml2dom 10 import os 11 12 # NOTE: Move these functions into a common utility library. 13 14 def add_elements(positions, element_name, element_parent_name=None): 15 if not positions: 16 return 17 for position in positions: 18 if element_parent_name: 19 parent_elements = position.xpath(element_parent_name) 20 if not parent_elements: 21 parent_element = position.ownerDocument.createElementNS(None, element_parent_name) 22 position.appendChild(parent_element) 23 else: 24 parent_element = parent_elements[0] 25 else: 26 parent_element = position 27 parent_element.appendChild(position.ownerDocument.createElementNS(None, element_name)) 28 29 def remove_elements(positions): 30 if not positions: 31 return 32 for position in positions: 33 position.parentNode.removeChild(position) 34 35 # NOTE: This is so much like ConfiguratorResource that some common parts could 36 # NOTE: be extracted. 37 38 class QuestionnaireEditorResource: 39 40 "A resource providing a questionnaire editor." 41 42 resource_dir = os.path.join(os.path.split(__file__)[0], "Resources") 43 encoding = "utf-8" 44 45 def respond(self, trans): 46 47 # Produce stylesheet. 48 49 if trans.get_path_info().split("/")[-1] == "styles.css": 50 trans.set_content_type(WebStack.Generic.ContentType("text/css", self.encoding)) 51 out = trans.get_response_stream() 52 f = open(os.path.join(self.resource_dir, "styles.css"), "rb") 53 out.write(f.read()) 54 f.close() 55 raise WebStack.Generic.EndOfResponse 56 57 global XSLForms # NOTE: Strangely required to avoid UnboundLocalError! 58 method = trans.get_request_method() 59 60 # Only obtain field information according to the stated method. 61 62 if method == "GET": 63 fields = XSLForms.Fields.Fields(encoding="iso-8859-1", values_are_lists=1) 64 parameters = trans.get_fields_from_path() 65 documents = fields.make_documents(parameters.items()) 66 elif method == "POST": 67 fields = XSLForms.Fields.Fields(encoding=self.encoding, values_are_lists=1) 68 parameters = trans.get_fields_from_body(self.encoding) 69 documents = fields.make_documents(parameters.items()) 70 else: 71 trans.set_response_code(405) 72 raise WebStack.Generic.EndOfResponse 73 74 # Ensure the presence of a document. 75 76 if documents.has_key("questionnaire"): 77 questionnaire = documents["questionnaire"] 78 else: 79 questionnaire = fields.new_instance("questionnaire") 80 81 # Add and remove elements according to the selectors found. 82 83 selectors = fields.get_selectors(parameters.items(), documents) 84 remove_elements(selectors.get("remove-question")) 85 add_elements(selectors.get("add-choice"), "choice") 86 remove_elements(selectors.get("remove-choice")) 87 88 # Add questions using the normal request parameter. 89 90 if parameters.has_key("add-question"): 91 new_question = questionnaire.ownerDocument.createElementNS(None, "question") 92 questionnaire.xpath("questionnaire")[0].appendChild(new_question) 93 94 # Send a response according to certain parameters. 95 # When exported, an XML version of the data is returned. 96 97 if parameters.has_key("export"): 98 trans.set_content_type(WebStack.Generic.ContentType("text/xml", self.encoding)) 99 libxml2dom.toStream(questionnaire, trans.get_response_stream(), trans.get_response_stream_encoding()) 100 101 # When not exported, the data is transformed to produce a normal Web 102 # page. 103 104 else: 105 106 # Start the response. 107 108 trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding)) 109 110 # Ensure that an output stylesheet exists. 111 112 trans_xsl = os.path.join(self.resource_dir, "question_output.xsl") 113 template_xml = os.path.join(self.resource_dir, "question_template.xhtml") 114 115 if not os.path.exists(trans_xsl) or \ 116 os.path.getmtime(trans_xsl) < os.path.getmtime(template_xml): 117 118 import XSLForms.Prepare 119 template_xml = os.path.join(self.resource_dir, "question_template.xhtml") 120 XSLForms.Prepare.make_stylesheet(template_xml, trans_xsl) 121 122 # Complete the response. 123 124 proc = XSLOutput.Processor([trans_xsl]) 125 proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), 126 questionnaire) 127 128 # vim: tabstop=4 expandtab shiftwidth=4