paulb@353 | 1 | #!/usr/bin/env python |
paulb@353 | 2 | |
paulb@353 | 3 | """ |
paulb@353 | 4 | Resources for use with WebStack. |
paulb@353 | 5 | |
paulb@666 | 6 | Copyright (C) 2005, 2006, 2007, 2008 Paul Boddie <paul@boddie.org.uk> |
paulb@353 | 7 | |
paulb@600 | 8 | This program is free software; you can redistribute it and/or modify it under |
paulb@600 | 9 | the terms of the GNU Lesser General Public License as published by the Free |
paulb@600 | 10 | Software Foundation; either version 3 of the License, or (at your option) any |
paulb@600 | 11 | later version. |
paulb@353 | 12 | |
paulb@600 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paulb@600 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paulb@600 | 15 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
paulb@600 | 16 | details. |
paulb@353 | 17 | |
paulb@600 | 18 | You should have received a copy of the GNU Lesser General Public License along |
paulb@600 | 19 | with this program. If not, see <http://www.gnu.org/licenses/>. |
paulb@353 | 20 | """ |
paulb@353 | 21 | |
paulb@353 | 22 | import WebStack.Generic |
paulb@353 | 23 | import XSLForms.Fields |
paulb@353 | 24 | import XSLForms.Prepare |
paulb@353 | 25 | import XSLForms.Output |
paulb@637 | 26 | import XSLForms.Utils |
paulb@354 | 27 | import XSLForms.Resources.Common |
paulb@353 | 28 | from XSLTools import XSLOutput |
paulb@353 | 29 | import os |
paulb@353 | 30 | |
paulb@354 | 31 | class XSLFormsResource(XSLForms.Resources.Common.CommonResource): |
paulb@353 | 32 | |
paulb@353 | 33 | """ |
paulb@353 | 34 | A generic XSLForms resource for use with WebStack. |
paulb@353 | 35 | |
paulb@353 | 36 | When overriding this class, define the following attributes appropriately: |
paulb@353 | 37 | |
paulb@353 | 38 | * template_resources - a dictionary mapping output identifiers to |
paulb@353 | 39 | (template_filename, output_filename) tuples, |
paulb@353 | 40 | indicating the template and stylesheet filenames |
paulb@353 | 41 | to be employed |
paulb@353 | 42 | |
paulb@353 | 43 | * in_page_resources - a dictionary mapping fragment identifiers to |
paulb@509 | 44 | (output_identifier, output_filename, |
paulb@509 | 45 | node_identifier) tuples, indicating the output |
paulb@509 | 46 | identifier for which the fragment applies, the |
paulb@509 | 47 | stylesheet filename to be employed, along with |
paulb@509 | 48 | the node identifier used in the original |
paulb@509 | 49 | template and output documents to mark a region |
paulb@509 | 50 | of those documents as the fragment to be updated |
paulb@509 | 51 | upon "in-page" requests |
paulb@353 | 52 | |
paulb@353 | 53 | * init_resources - a dictionary mapping initialiser/input |
paulb@353 | 54 | identifiers to (template_filename, |
paulb@353 | 55 | input_filename) tuples, indicating the template |
paulb@353 | 56 | and initialiser/input stylesheet filenames to be |
paulb@353 | 57 | employed |
paulb@353 | 58 | |
paulb@353 | 59 | * transform_resources - a dictionary mapping transform identifiers to |
paulb@353 | 60 | lists of stylesheet filenames for use with the |
paulb@353 | 61 | transformation methods |
paulb@353 | 62 | |
paulb@353 | 63 | * document_resources - a dictionary mapping document identifiers to |
paulb@353 | 64 | single filenames for use as source documents or |
paulb@353 | 65 | as references with the transformation methods |
paulb@353 | 66 | |
paulb@353 | 67 | * resource_dir - the absolute path of the directory in which |
paulb@353 | 68 | stylesheet resources are to reside |
paulb@353 | 69 | |
paulb@353 | 70 | All filenames shall be simple leafnames for files residing in the resource's |
paulb@353 | 71 | special resource directory 'resource_dir'. |
paulb@353 | 72 | |
paulb@353 | 73 | The following attributes may also be specified: |
paulb@353 | 74 | |
paulb@353 | 75 | * path_encoding - the assumed encoding of characters in request |
paulb@353 | 76 | paths |
paulb@353 | 77 | |
paulb@353 | 78 | * encoding - the assumed encoding of characters in request |
paulb@353 | 79 | bodies |
paulb@637 | 80 | |
paulb@637 | 81 | To provide actual functionality to resources, either override the |
paulb@637 | 82 | 'respond_to_form' method and write the code for obtaining input, |
paulb@637 | 83 | initialising documents, creating output, and so on in that method, or |
paulb@637 | 84 | provide implementations for the following methods: |
paulb@637 | 85 | |
paulb@637 | 86 | * select_activity - sets the activity name which will be used by the |
paulb@637 | 87 | default implementations of the other methods |
paulb@637 | 88 | |
paulb@637 | 89 | * create_document - creates or obtains a document for the resource's |
paulb@637 | 90 | activity (need not be overridden) |
paulb@637 | 91 | |
paulb@637 | 92 | * respond_to_input - application logic relying on any input from the |
paulb@637 | 93 | request, including submitted document |
paulb@637 | 94 | information |
paulb@637 | 95 | |
paulb@637 | 96 | * init_document - initialises the document according to the |
paulb@637 | 97 | 'init_resources' attribute described above (need |
paulb@637 | 98 | not be overridden) |
paulb@637 | 99 | |
paulb@637 | 100 | * respond_to_document - application logic relying on any information |
paulb@637 | 101 | from the initialised document |
paulb@637 | 102 | |
paulb@637 | 103 | * create_output - creates and sends final output to the user (need |
paulb@637 | 104 | not be overridden) |
paulb@353 | 105 | """ |
paulb@353 | 106 | |
paul@672 | 107 | #path_encoding = "utf-8" |
paul@672 | 108 | #encoding = "utf-8" |
paul@672 | 109 | |
paulb@353 | 110 | template_resources = {} |
paulb@353 | 111 | in_page_resources = {} |
paulb@354 | 112 | init_resources = {} |
paulb@353 | 113 | transform_resources = {} |
paulb@353 | 114 | |
paulb@353 | 115 | def clean_parameters(self, parameters): |
paulb@353 | 116 | |
paulb@353 | 117 | """ |
paulb@353 | 118 | Workaround stray zero value characters from Konqueror in XMLHttpRequest |
paulb@353 | 119 | communications. |
paulb@353 | 120 | """ |
paulb@353 | 121 | |
paulb@353 | 122 | for name, values in parameters.items(): |
paulb@353 | 123 | new_values = [] |
paulb@353 | 124 | for value in values: |
paul@674 | 125 | if isinstance(value, (str, unicode)) and value.endswith("\x00"): |
paulb@353 | 126 | new_values.append(value[:-1]) |
paulb@353 | 127 | else: |
paulb@353 | 128 | new_values.append(value) |
paulb@353 | 129 | parameters[name] = new_values |
paulb@353 | 130 | |
paulb@353 | 131 | def prepare_output(self, output_identifier): |
paulb@353 | 132 | |
paulb@353 | 133 | """ |
paulb@353 | 134 | Prepare the output stylesheets using the given 'output_identifier' to |
paulb@353 | 135 | indicate which templates and stylesheets are to be employed in the |
paulb@353 | 136 | production of output from the resource. |
paulb@353 | 137 | |
paulb@353 | 138 | The 'output_identifier' is used as a key to the 'template_resources' |
paulb@353 | 139 | dictionary attribute. |
paulb@353 | 140 | |
paulb@353 | 141 | Return the full path to the output stylesheet for use with 'send_output' |
paulb@353 | 142 | or 'get_result'. |
paulb@353 | 143 | """ |
paulb@353 | 144 | |
paulb@509 | 145 | template_path, output_path = prepare_output(self, output_identifier) |
paulb@353 | 146 | return output_path |
paulb@353 | 147 | |
paulb@509 | 148 | def prepare_fragment(self, fragment_identifier): |
paulb@353 | 149 | |
paulb@353 | 150 | """ |
paulb@509 | 151 | Prepare the output stylesheets for the given 'fragment_identifier', |
paulb@509 | 152 | indicating which templates and stylesheets are to be employed in the |
paulb@509 | 153 | production of output from the resource. |
paulb@353 | 154 | |
paulb@509 | 155 | The 'fragment_identifier' is used as a key to the 'in_page_resources' |
paulb@509 | 156 | dictionary attribute which in turn obtains an 'output_identifier', which |
paulb@509 | 157 | is used as a key to the 'template_resources' dictionary attribute. |
paulb@353 | 158 | |
paulb@353 | 159 | Return the full path to the output stylesheet for use with 'send_output' |
paulb@353 | 160 | or 'get_result'. |
paulb@353 | 161 | """ |
paulb@353 | 162 | |
paulb@509 | 163 | template_path, fragment_path = prepare_fragment(self, fragment_identifier) |
paulb@353 | 164 | return fragment_path |
paulb@353 | 165 | |
paulb@353 | 166 | def prepare_parameters(self, parameters): |
paulb@353 | 167 | |
paulb@353 | 168 | """ |
paulb@353 | 169 | Prepare the stylesheet parameters from the given request 'parameters'. |
paulb@353 | 170 | This is most useful when preparing fragments for in-page update output. |
paulb@353 | 171 | """ |
paulb@353 | 172 | |
paulb@353 | 173 | element_path = parameters.get("element-path", [""])[0] |
paulb@353 | 174 | if element_path: |
paulb@353 | 175 | return {"element-path" : element_path} |
paulb@353 | 176 | else: |
paulb@353 | 177 | return {} |
paulb@353 | 178 | |
paulb@353 | 179 | def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None, |
paulb@353 | 180 | stylesheet_expressions=None, references=None): |
paulb@353 | 181 | |
paulb@353 | 182 | """ |
paulb@353 | 183 | Send the output from the resource to the user employing the transaction |
paulb@353 | 184 | 'trans', stylesheets having the given 'stylesheet_filenames', the |
paulb@353 | 185 | 'document' upon which the output will be based, the optional parameters |
paulb@353 | 186 | as defined in the 'stylesheet_parameters' dictionary, the optional |
paulb@353 | 187 | expressions are defined in the 'stylesheet_expressions' dictionary, and |
paulb@353 | 188 | the optional 'references' to external documents. |
paulb@353 | 189 | """ |
paulb@353 | 190 | |
paulb@353 | 191 | # Sanity check for the filenames list. |
paulb@353 | 192 | |
paulb@353 | 193 | if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode): |
paulb@353 | 194 | raise ValueError, stylesheet_filenames |
paulb@353 | 195 | |
paulb@353 | 196 | proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, |
paulb@353 | 197 | expressions=stylesheet_expressions, references=references) |
paulb@353 | 198 | proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), |
paulb@353 | 199 | document) |
paulb@353 | 200 | |
paulb@353 | 201 | def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None, |
paulb@353 | 202 | stylesheet_expressions=None, references=None): |
paulb@353 | 203 | |
paulb@353 | 204 | """ |
paulb@353 | 205 | Get the result of applying a transformation using stylesheets with the |
paulb@353 | 206 | given 'stylesheet_filenames', the 'document' upon which the result will |
paulb@353 | 207 | be based, the optional parameters as defined in the |
paulb@353 | 208 | 'stylesheet_parameters' dictionary, the optional parameters as defined |
paulb@534 | 209 | in the 'stylesheet_parameters' dictionary and the optional 'references' |
paulb@353 | 210 | to external documents. |
paulb@353 | 211 | """ |
paulb@353 | 212 | |
paulb@353 | 213 | # Sanity check for the filenames list. |
paulb@353 | 214 | |
paulb@353 | 215 | if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode): |
paulb@353 | 216 | raise ValueError, stylesheet_filenames |
paulb@353 | 217 | |
paulb@353 | 218 | proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, |
paulb@353 | 219 | expressions=stylesheet_expressions, references=references) |
paulb@353 | 220 | return proc.get_result(document) |
paulb@353 | 221 | |
paulb@365 | 222 | def prepare_initialiser(self, input_identifier, init_enumerations=1): |
paulb@353 | 223 | |
paulb@353 | 224 | """ |
paulb@353 | 225 | Prepare an initialiser/input transformation using the given |
paulb@365 | 226 | 'input_identifier'. The optional 'init_enumerations' (defaulting to |
paulb@365 | 227 | true) may be used to indicate whether enumerations are to be initialised |
paulb@365 | 228 | from external documents. |
paulb@353 | 229 | |
paulb@353 | 230 | Return the full path to the input stylesheet for use with 'send_output' |
paulb@353 | 231 | or 'get_result'. |
paulb@353 | 232 | """ |
paulb@353 | 233 | |
paulb@509 | 234 | template_path, input_path = prepare_initialiser(self, input_identifier, init_enumerations) |
paulb@353 | 235 | return input_path |
paulb@353 | 236 | |
paulb@353 | 237 | def prepare_transform(self, transform_identifier): |
paulb@353 | 238 | |
paulb@353 | 239 | """ |
paulb@353 | 240 | Prepare a transformation using the given 'transform_identifier'. |
paulb@353 | 241 | |
paulb@353 | 242 | Return a list of full paths to the output stylesheets for use with |
paulb@353 | 243 | 'send_output' or 'get_result'. |
paulb@353 | 244 | """ |
paulb@353 | 245 | |
paulb@353 | 246 | filenames = self.transform_resources[transform_identifier] |
paulb@419 | 247 | |
paulb@419 | 248 | # Sanity check for the filenames list. |
paulb@419 | 249 | |
paulb@419 | 250 | if isinstance(filenames, str) or isinstance(filenames, unicode): |
paulb@419 | 251 | raise ValueError, filenames |
paulb@419 | 252 | |
paulb@353 | 253 | paths = [] |
paulb@353 | 254 | for filename in filenames: |
paulb@353 | 255 | paths.append(os.path.abspath(os.path.join(self.resource_dir, filename))) |
paulb@353 | 256 | return paths |
paulb@353 | 257 | |
paulb@666 | 258 | def _get_in_page_resource(self, trans): |
paulb@353 | 259 | |
paulb@353 | 260 | """ |
paulb@353 | 261 | Return the in-page resource being referred to in the given transaction |
paulb@353 | 262 | 'trans'. |
paulb@353 | 263 | """ |
paulb@353 | 264 | |
paulb@560 | 265 | if hasattr(self, "path_encoding"): |
paulb@560 | 266 | return trans.get_path_info(self.path_encoding).split("/")[-1] |
paulb@560 | 267 | else: |
paulb@560 | 268 | return trans.get_path_info().split("/")[-1] |
paulb@353 | 269 | |
paulb@666 | 270 | def get_in_page_resource(self, trans): |
paulb@666 | 271 | |
paulb@666 | 272 | """ |
paulb@666 | 273 | Return the in-page resource being referred to in the given transaction |
paulb@666 | 274 | 'trans' or None if no valid in-page resource is being referenced. |
paulb@666 | 275 | """ |
paulb@666 | 276 | |
paulb@666 | 277 | name = self._get_in_page_resource(trans) |
paulb@666 | 278 | if self.in_page_resources.has_key(name): |
paulb@666 | 279 | return name |
paulb@666 | 280 | else: |
paulb@666 | 281 | return None |
paulb@666 | 282 | |
paulb@353 | 283 | def respond(self, trans): |
paulb@353 | 284 | |
paulb@353 | 285 | """ |
paulb@353 | 286 | Respond to the request described by the given transaction 'trans'. |
paulb@353 | 287 | """ |
paulb@353 | 288 | |
paulb@353 | 289 | # Only obtain field information according to the stated method. |
paulb@353 | 290 | |
paulb@534 | 291 | content_type = trans.get_content_type() |
paulb@353 | 292 | method = trans.get_request_method() |
paulb@353 | 293 | in_page_resource = self.get_in_page_resource(trans) |
paulb@353 | 294 | |
paulb@353 | 295 | # Handle typical request methods, processing request information. |
paulb@353 | 296 | |
paulb@353 | 297 | if method == "GET": |
paulb@353 | 298 | |
paulb@353 | 299 | # Get the fields from the request path (URL). |
paulb@353 | 300 | |
paulb@560 | 301 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@353 | 302 | parameters = trans.get_fields_from_path() |
paulb@353 | 303 | form.set_parameters(parameters) |
paulb@353 | 304 | |
paul@674 | 305 | elif method == "POST" and content_type.media_type in ( |
paul@674 | 306 | "application/x-www-form-urlencoded", "multipart/form-data"): |
paulb@353 | 307 | |
paulb@353 | 308 | # Get the fields from the request body. |
paulb@353 | 309 | |
paulb@560 | 310 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@560 | 311 | if hasattr(self, "encoding"): |
paulb@560 | 312 | parameters = trans.get_fields_from_body(self.encoding) |
paulb@560 | 313 | else: |
paulb@560 | 314 | parameters = trans.get_fields_from_body() |
paulb@353 | 315 | |
paulb@353 | 316 | # NOTE: Konqueror workaround. |
paulb@353 | 317 | self.clean_parameters(parameters) |
paulb@353 | 318 | |
paulb@353 | 319 | form.set_parameters(parameters) |
paulb@353 | 320 | |
paulb@353 | 321 | else: |
paulb@353 | 322 | |
paulb@450 | 323 | # Initialise empty container. |
paulb@353 | 324 | |
paulb@560 | 325 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@353 | 326 | |
paulb@353 | 327 | # Call an overridden method with the processed request information. |
paulb@353 | 328 | |
paulb@353 | 329 | self.respond_to_form(trans, form) |
paulb@353 | 330 | |
paulb@353 | 331 | def respond_to_form(self, trans, form): |
paulb@353 | 332 | |
paulb@353 | 333 | """ |
paulb@353 | 334 | Respond to the request described by the given transaction 'trans', using |
paulb@353 | 335 | the given 'form' object to conveniently retrieve field (request |
paulb@353 | 336 | parameter) information and structured form information (as DOM-style XML |
paulb@353 | 337 | documents). |
paulb@353 | 338 | """ |
paulb@353 | 339 | |
paulb@637 | 340 | self.select_activity(trans, form) |
paulb@637 | 341 | self.create_document(trans, form) |
paulb@637 | 342 | self.respond_to_input(trans, form) |
paulb@637 | 343 | self.init_document(trans, form) |
paulb@637 | 344 | self.respond_to_document(trans, form) |
paulb@637 | 345 | self.create_output(trans, form) |
paulb@353 | 346 | raise WebStack.Generic.EndOfResponse |
paulb@353 | 347 | |
paulb@637 | 348 | # Modular methods for responding to requests. |
paulb@637 | 349 | |
paulb@637 | 350 | def select_activity(self, trans, form): |
paulb@637 | 351 | |
paulb@637 | 352 | """ |
paulb@637 | 353 | Using the given transaction 'trans' and 'form' information, select the |
paulb@637 | 354 | activity being performed and set the 'current_activity' attribute in the |
paulb@637 | 355 | transaction. |
paulb@637 | 356 | """ |
paulb@637 | 357 | |
paulb@637 | 358 | pass |
paulb@637 | 359 | |
paulb@637 | 360 | def create_document(self, trans, form): |
paulb@637 | 361 | |
paulb@637 | 362 | """ |
paulb@637 | 363 | Using the given transaction 'trans' and 'form' information, create the |
paulb@637 | 364 | document involved in the current activity and set the 'current_document' |
paulb@637 | 365 | attribute in the transaction. |
paulb@637 | 366 | |
paulb@637 | 367 | Return whether a new document was created. |
paulb@637 | 368 | """ |
paulb@637 | 369 | |
paulb@637 | 370 | documents = form.get_documents() |
paulb@641 | 371 | activity = form.get_activity() |
paulb@637 | 372 | |
paulb@637 | 373 | if documents.has_key(activity): |
paulb@641 | 374 | form.set_document(documents[activity]) |
paulb@637 | 375 | return 0 |
paulb@637 | 376 | else: |
paulb@666 | 377 | form.new_document(activity) |
paulb@666 | 378 | form.new_documents.add(activity) |
paulb@637 | 379 | return 1 |
paulb@637 | 380 | |
paulb@637 | 381 | def respond_to_input(self, trans, form): |
paulb@637 | 382 | |
paulb@637 | 383 | """ |
paulb@637 | 384 | Using the given transaction 'trans' and 'form' information, perform the |
paulb@637 | 385 | parts of the current activity which rely on the information supplied in |
paulb@637 | 386 | the current document. |
paulb@637 | 387 | """ |
paulb@637 | 388 | |
paulb@637 | 389 | pass |
paulb@637 | 390 | |
paulb@637 | 391 | def init_document(self, trans, form, stylesheet_parameters=None, |
paulb@637 | 392 | stylesheet_expressions=None, references=None): |
paulb@637 | 393 | |
paulb@637 | 394 | """ |
paulb@637 | 395 | Using the given transaction 'trans' and 'form' information, initialise |
paulb@637 | 396 | the current document. |
paulb@637 | 397 | """ |
paulb@637 | 398 | |
paulb@646 | 399 | activity = form.get_activity() |
paulb@646 | 400 | |
paulb@637 | 401 | # Transform, adding enumerations/ranges. |
paulb@637 | 402 | |
paulb@646 | 403 | if self.init_resources.has_key(activity): |
paulb@646 | 404 | init_xsl = self.prepare_initialiser(activity) |
paulb@646 | 405 | form.set_document( |
paulb@646 | 406 | self.get_result( |
paulb@646 | 407 | [init_xsl], form.get_document(), stylesheet_parameters, |
paulb@646 | 408 | stylesheet_expressions, references |
paulb@646 | 409 | ) |
paulb@637 | 410 | ) |
paulb@637 | 411 | |
paulb@637 | 412 | def respond_to_document(self, trans, form): |
paulb@637 | 413 | |
paulb@637 | 414 | """ |
paulb@637 | 415 | Using the given transaction 'trans' and 'form' information, perform the |
paulb@637 | 416 | parts of the current activity which rely on a populated version of the |
paulb@637 | 417 | current document. |
paulb@637 | 418 | """ |
paulb@637 | 419 | |
paulb@637 | 420 | pass |
paulb@637 | 421 | |
paulb@637 | 422 | def create_output(self, trans, form, content_type=None, |
paulb@637 | 423 | stylesheet_parameters=None, stylesheet_expressions=None, references=None): |
paulb@637 | 424 | |
paulb@637 | 425 | """ |
paulb@637 | 426 | Using the given transaction 'trans' and 'form' information, create the |
paulb@637 | 427 | output for the current activity using the previously set attributes in |
paulb@637 | 428 | the transaction. |
paulb@637 | 429 | """ |
paulb@637 | 430 | |
paulb@637 | 431 | attributes = trans.get_attributes() |
paulb@637 | 432 | in_page_resource = self.get_in_page_resource(trans) |
paulb@637 | 433 | parameters = form.get_parameters() |
paulb@637 | 434 | |
paulb@637 | 435 | # Start the response. |
paulb@637 | 436 | |
paul@672 | 437 | if attributes.has_key("encoding"): |
paul@672 | 438 | encoding = attributes["encoding"] # NOTE: Potentially redundant. |
paul@672 | 439 | elif hasattr(self, "encoding"): |
paul@672 | 440 | encoding = self.encoding |
paul@672 | 441 | else: |
paul@672 | 442 | encoding = trans.default_charset |
paul@672 | 443 | |
paulb@637 | 444 | content_type = content_type or WebStack.Generic.ContentType("application/xhtml+xml", encoding) |
paulb@637 | 445 | trans.set_content_type(content_type) |
paulb@637 | 446 | |
paulb@637 | 447 | # Ensure that an output stylesheet exists. |
paulb@637 | 448 | |
paulb@637 | 449 | stylesheet_parameters = stylesheet_parameters or {} |
paulb@637 | 450 | |
paulb@666 | 451 | if in_page_resource: |
paulb@637 | 452 | trans_xsl = self.prepare_fragment(in_page_resource) |
paulb@637 | 453 | stylesheet_parameters.update(self.prepare_parameters(parameters)) |
paulb@637 | 454 | else: |
paulb@641 | 455 | trans_xsl = self.prepare_output(form.get_activity()) |
paulb@637 | 456 | |
paulb@637 | 457 | # Complete the response. |
paulb@637 | 458 | |
paulb@641 | 459 | self.send_output(trans, [trans_xsl], form.get_document(), |
paulb@637 | 460 | stylesheet_parameters, stylesheet_expressions, references) |
paulb@637 | 461 | |
paulb@637 | 462 | # General helper methods. |
paulb@637 | 463 | |
paulb@637 | 464 | def add_elements(self, positions, *element_names): |
paulb@637 | 465 | |
paulb@637 | 466 | """ |
paulb@637 | 467 | At the given 'positions', typically obtained as "selectors", add the |
paulb@637 | 468 | hierarchy of elements given in the 'element_names' parameters. |
paulb@637 | 469 | """ |
paulb@637 | 470 | |
paulb@637 | 471 | XSLForms.Utils.add_elements(positions, *element_names) |
paulb@637 | 472 | |
paulb@637 | 473 | def remove_elements(self, positions): |
paulb@637 | 474 | |
paulb@637 | 475 | """ |
paulb@637 | 476 | Remove elements at the given 'positions', typically obtained as |
paulb@637 | 477 | "selectors". |
paulb@637 | 478 | """ |
paulb@637 | 479 | |
paulb@637 | 480 | XSLForms.Utils.remove_elements(positions) |
paulb@637 | 481 | |
paulb@509 | 482 | def prepare_output(self, output_identifier): |
paulb@509 | 483 | |
paulb@509 | 484 | """ |
paulb@509 | 485 | Prepare the output stylesheet for the resource class or object 'self' |
paulb@509 | 486 | corresponding to the given 'output_identifier'. Return the template path |
paulb@509 | 487 | and the output stylesheet path in a 2-tuple. |
paulb@509 | 488 | """ |
paulb@509 | 489 | |
paulb@509 | 490 | template_filename, output_filename = self.template_resources[output_identifier] |
paulb@509 | 491 | output_path = os.path.abspath(os.path.join(self.resource_dir, output_filename)) |
paulb@509 | 492 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 493 | XSLForms.Prepare.ensure_stylesheet(template_path, output_path) |
paulb@509 | 494 | return template_path, output_path |
paulb@509 | 495 | |
paulb@509 | 496 | def prepare_fragment(self, fragment_identifier): |
paulb@509 | 497 | |
paulb@509 | 498 | """ |
paulb@509 | 499 | Prepare the output stylesheet for the resource class or object 'self' |
paulb@509 | 500 | corresponding to the given 'fragment_identifier'. Return the template path |
paulb@509 | 501 | and the output stylesheet path in a 2-tuple. |
paulb@509 | 502 | """ |
paulb@509 | 503 | |
paulb@509 | 504 | output_identifier, fragment_filename, node_identifier = self.in_page_resources[fragment_identifier] |
paulb@509 | 505 | fragment_path = os.path.abspath(os.path.join(self.resource_dir, fragment_filename)) |
paulb@509 | 506 | template_filename, output_filename = self.template_resources[output_identifier] |
paulb@509 | 507 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 508 | XSLForms.Prepare.ensure_stylesheet_fragment(template_path, fragment_path, node_identifier) |
paulb@509 | 509 | return template_path, fragment_path |
paulb@509 | 510 | |
paulb@509 | 511 | def prepare_initialiser(self, input_identifier, init_enumerations): |
paulb@509 | 512 | |
paulb@509 | 513 | """ |
paulb@509 | 514 | Prepare the initialising stylesheet for the resource class or object 'self' |
paulb@509 | 515 | corresponding to the given 'input_identifier' and 'init_enumerations' flag. |
paulb@509 | 516 | Return the template path and the initialising stylesheet path in a 2-tuple. |
paulb@509 | 517 | """ |
paulb@509 | 518 | |
paulb@509 | 519 | template_filename, input_filename = self.init_resources[input_identifier] |
paulb@509 | 520 | input_path = os.path.abspath(os.path.join(self.resource_dir, input_filename)) |
paulb@509 | 521 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 522 | XSLForms.Prepare.ensure_input_stylesheet(template_path, input_path, init_enumerations) |
paulb@509 | 523 | return template_path, input_path |
paulb@509 | 524 | |
paulb@509 | 525 | def prepare_resources(cls): |
paulb@509 | 526 | |
paulb@509 | 527 | "Prepare the resources associated with the class 'cls'." |
paulb@509 | 528 | |
paulb@509 | 529 | for output_identifier in cls.template_resources.keys(): |
paulb@509 | 530 | prepare_output(cls, output_identifier) |
paulb@509 | 531 | for fragment_identifier in cls.in_page_resources.keys(): |
paulb@509 | 532 | prepare_fragment(cls, fragment_identifier) |
paulb@509 | 533 | |
paulb@509 | 534 | # NOTE: Using init_enumerations=1 here. |
paulb@509 | 535 | |
paulb@509 | 536 | for input_identifier in cls.init_resources.keys(): |
paulb@509 | 537 | prepare_initialiser(cls, input_identifier, 1) |
paulb@509 | 538 | |
paulb@634 | 539 | # Convenience methods for specifying resources. |
paulb@634 | 540 | |
paulb@634 | 541 | def split(filename): |
paulb@634 | 542 | |
paulb@634 | 543 | """ |
paulb@634 | 544 | Return a tuple containing the directory and filename without extension for |
paulb@634 | 545 | 'filename'. |
paulb@634 | 546 | """ |
paulb@634 | 547 | |
paulb@634 | 548 | d, leafname = os.path.split(filename) |
paulb@634 | 549 | name, ext = os.path.splitext(leafname) |
paulb@634 | 550 | return d, name |
paulb@634 | 551 | |
paulb@634 | 552 | def output(template_filename): |
paulb@634 | 553 | |
paulb@634 | 554 | """ |
paulb@634 | 555 | Return a tuple containing the 'template_filename' and a suitable output |
paulb@634 | 556 | stylesheet filename. |
paulb@634 | 557 | """ |
paulb@634 | 558 | |
paulb@634 | 559 | d, name = split(template_filename) |
paulb@634 | 560 | output_name = name.replace("_template", "_output") + os.path.extsep + "xsl" |
paulb@634 | 561 | return (template_filename, os.path.join(d, output_name)) |
paulb@634 | 562 | |
paulb@634 | 563 | def input(template_filename): |
paulb@634 | 564 | |
paulb@634 | 565 | """ |
paulb@634 | 566 | Return a tuple containing the 'template_filename' and a suitable output |
paulb@634 | 567 | stylesheet filename. |
paulb@634 | 568 | """ |
paulb@634 | 569 | |
paulb@634 | 570 | d, name = split(template_filename) |
paulb@634 | 571 | input_name = name.replace("_template", "_input") + os.path.extsep + "xsl" |
paulb@634 | 572 | return (template_filename, os.path.join(d, input_name)) |
paulb@634 | 573 | |
paulb@634 | 574 | def resources(filename, d="Resources"): |
paulb@634 | 575 | |
paulb@634 | 576 | """ |
paulb@634 | 577 | Return the resource directory for the given 'filename', using the optional |
paulb@634 | 578 | directory name 'd' to indicate the directory relative to the directory of |
paulb@634 | 579 | 'filename' (or the default directory name, indicating that the directory |
paulb@634 | 580 | called "Resources" - a sibling of 'filename' - is the resource directory). |
paulb@634 | 581 | |
paulb@634 | 582 | It is envisaged that callers provide the value of the __file__ special |
paulb@634 | 583 | variable to get the resource directory relative to a particular module. |
paulb@634 | 584 | """ |
paulb@634 | 585 | |
paulb@634 | 586 | return os.path.join(os.path.split(filename)[0], d) |
paulb@634 | 587 | |
paulb@353 | 588 | # vim: tabstop=4 expandtab shiftwidth=4 |