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 | |
paulb@637 | 107 | path_encoding = "utf-8" |
paulb@637 | 108 | encoding = "utf-8" |
paulb@353 | 109 | template_resources = {} |
paulb@353 | 110 | in_page_resources = {} |
paulb@354 | 111 | init_resources = {} |
paulb@353 | 112 | transform_resources = {} |
paulb@353 | 113 | |
paulb@353 | 114 | def clean_parameters(self, parameters): |
paulb@353 | 115 | |
paulb@353 | 116 | """ |
paulb@353 | 117 | Workaround stray zero value characters from Konqueror in XMLHttpRequest |
paulb@353 | 118 | communications. |
paulb@353 | 119 | """ |
paulb@353 | 120 | |
paulb@353 | 121 | for name, values in parameters.items(): |
paulb@353 | 122 | new_values = [] |
paulb@353 | 123 | for value in values: |
paulb@353 | 124 | if value.endswith("\x00"): |
paulb@353 | 125 | new_values.append(value[:-1]) |
paulb@353 | 126 | else: |
paulb@353 | 127 | new_values.append(value) |
paulb@353 | 128 | parameters[name] = new_values |
paulb@353 | 129 | |
paulb@353 | 130 | def prepare_output(self, output_identifier): |
paulb@353 | 131 | |
paulb@353 | 132 | """ |
paulb@353 | 133 | Prepare the output stylesheets using the given 'output_identifier' to |
paulb@353 | 134 | indicate which templates and stylesheets are to be employed in the |
paulb@353 | 135 | production of output from the resource. |
paulb@353 | 136 | |
paulb@353 | 137 | The 'output_identifier' is used as a key to the 'template_resources' |
paulb@353 | 138 | dictionary attribute. |
paulb@353 | 139 | |
paulb@353 | 140 | Return the full path to the output stylesheet for use with 'send_output' |
paulb@353 | 141 | or 'get_result'. |
paulb@353 | 142 | """ |
paulb@353 | 143 | |
paulb@509 | 144 | template_path, output_path = prepare_output(self, output_identifier) |
paulb@353 | 145 | return output_path |
paulb@353 | 146 | |
paulb@509 | 147 | def prepare_fragment(self, fragment_identifier): |
paulb@353 | 148 | |
paulb@353 | 149 | """ |
paulb@509 | 150 | Prepare the output stylesheets for the given 'fragment_identifier', |
paulb@509 | 151 | indicating which templates and stylesheets are to be employed in the |
paulb@509 | 152 | production of output from the resource. |
paulb@353 | 153 | |
paulb@509 | 154 | The 'fragment_identifier' is used as a key to the 'in_page_resources' |
paulb@509 | 155 | dictionary attribute which in turn obtains an 'output_identifier', which |
paulb@509 | 156 | is used as a key to the 'template_resources' dictionary attribute. |
paulb@353 | 157 | |
paulb@353 | 158 | Return the full path to the output stylesheet for use with 'send_output' |
paulb@353 | 159 | or 'get_result'. |
paulb@353 | 160 | """ |
paulb@353 | 161 | |
paulb@509 | 162 | template_path, fragment_path = prepare_fragment(self, fragment_identifier) |
paulb@353 | 163 | return fragment_path |
paulb@353 | 164 | |
paulb@353 | 165 | def prepare_parameters(self, parameters): |
paulb@353 | 166 | |
paulb@353 | 167 | """ |
paulb@353 | 168 | Prepare the stylesheet parameters from the given request 'parameters'. |
paulb@353 | 169 | This is most useful when preparing fragments for in-page update output. |
paulb@353 | 170 | """ |
paulb@353 | 171 | |
paulb@353 | 172 | element_path = parameters.get("element-path", [""])[0] |
paulb@353 | 173 | if element_path: |
paulb@353 | 174 | return {"element-path" : element_path} |
paulb@353 | 175 | else: |
paulb@353 | 176 | return {} |
paulb@353 | 177 | |
paulb@353 | 178 | def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None, |
paulb@353 | 179 | stylesheet_expressions=None, references=None): |
paulb@353 | 180 | |
paulb@353 | 181 | """ |
paulb@353 | 182 | Send the output from the resource to the user employing the transaction |
paulb@353 | 183 | 'trans', stylesheets having the given 'stylesheet_filenames', the |
paulb@353 | 184 | 'document' upon which the output will be based, the optional parameters |
paulb@353 | 185 | as defined in the 'stylesheet_parameters' dictionary, the optional |
paulb@353 | 186 | expressions are defined in the 'stylesheet_expressions' dictionary, and |
paulb@353 | 187 | the optional 'references' to external documents. |
paulb@353 | 188 | """ |
paulb@353 | 189 | |
paulb@353 | 190 | # Sanity check for the filenames list. |
paulb@353 | 191 | |
paulb@353 | 192 | if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode): |
paulb@353 | 193 | raise ValueError, stylesheet_filenames |
paulb@353 | 194 | |
paulb@353 | 195 | proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, |
paulb@353 | 196 | expressions=stylesheet_expressions, references=references) |
paulb@353 | 197 | proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), |
paulb@353 | 198 | document) |
paulb@353 | 199 | |
paulb@353 | 200 | def get_result(self, stylesheet_filenames, document, stylesheet_parameters=None, |
paulb@353 | 201 | stylesheet_expressions=None, references=None): |
paulb@353 | 202 | |
paulb@353 | 203 | """ |
paulb@353 | 204 | Get the result of applying a transformation using stylesheets with the |
paulb@353 | 205 | given 'stylesheet_filenames', the 'document' upon which the result will |
paulb@353 | 206 | be based, the optional parameters as defined in the |
paulb@353 | 207 | 'stylesheet_parameters' dictionary, the optional parameters as defined |
paulb@534 | 208 | in the 'stylesheet_parameters' dictionary and the optional 'references' |
paulb@353 | 209 | to external documents. |
paulb@353 | 210 | """ |
paulb@353 | 211 | |
paulb@353 | 212 | # Sanity check for the filenames list. |
paulb@353 | 213 | |
paulb@353 | 214 | if isinstance(stylesheet_filenames, str) or isinstance(stylesheet_filenames, unicode): |
paulb@353 | 215 | raise ValueError, stylesheet_filenames |
paulb@353 | 216 | |
paulb@353 | 217 | proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters, |
paulb@353 | 218 | expressions=stylesheet_expressions, references=references) |
paulb@353 | 219 | return proc.get_result(document) |
paulb@353 | 220 | |
paulb@365 | 221 | def prepare_initialiser(self, input_identifier, init_enumerations=1): |
paulb@353 | 222 | |
paulb@353 | 223 | """ |
paulb@353 | 224 | Prepare an initialiser/input transformation using the given |
paulb@365 | 225 | 'input_identifier'. The optional 'init_enumerations' (defaulting to |
paulb@365 | 226 | true) may be used to indicate whether enumerations are to be initialised |
paulb@365 | 227 | from external documents. |
paulb@353 | 228 | |
paulb@353 | 229 | Return the full path to the input stylesheet for use with 'send_output' |
paulb@353 | 230 | or 'get_result'. |
paulb@353 | 231 | """ |
paulb@353 | 232 | |
paulb@509 | 233 | template_path, input_path = prepare_initialiser(self, input_identifier, init_enumerations) |
paulb@353 | 234 | return input_path |
paulb@353 | 235 | |
paulb@353 | 236 | def prepare_transform(self, transform_identifier): |
paulb@353 | 237 | |
paulb@353 | 238 | """ |
paulb@353 | 239 | Prepare a transformation using the given 'transform_identifier'. |
paulb@353 | 240 | |
paulb@353 | 241 | Return a list of full paths to the output stylesheets for use with |
paulb@353 | 242 | 'send_output' or 'get_result'. |
paulb@353 | 243 | """ |
paulb@353 | 244 | |
paulb@353 | 245 | filenames = self.transform_resources[transform_identifier] |
paulb@419 | 246 | |
paulb@419 | 247 | # Sanity check for the filenames list. |
paulb@419 | 248 | |
paulb@419 | 249 | if isinstance(filenames, str) or isinstance(filenames, unicode): |
paulb@419 | 250 | raise ValueError, filenames |
paulb@419 | 251 | |
paulb@353 | 252 | paths = [] |
paulb@353 | 253 | for filename in filenames: |
paulb@353 | 254 | paths.append(os.path.abspath(os.path.join(self.resource_dir, filename))) |
paulb@353 | 255 | return paths |
paulb@353 | 256 | |
paulb@666 | 257 | def _get_in_page_resource(self, trans): |
paulb@353 | 258 | |
paulb@353 | 259 | """ |
paulb@353 | 260 | Return the in-page resource being referred to in the given transaction |
paulb@353 | 261 | 'trans'. |
paulb@353 | 262 | """ |
paulb@353 | 263 | |
paulb@560 | 264 | if hasattr(self, "path_encoding"): |
paulb@560 | 265 | return trans.get_path_info(self.path_encoding).split("/")[-1] |
paulb@560 | 266 | else: |
paulb@560 | 267 | return trans.get_path_info().split("/")[-1] |
paulb@353 | 268 | |
paulb@666 | 269 | def get_in_page_resource(self, trans): |
paulb@666 | 270 | |
paulb@666 | 271 | """ |
paulb@666 | 272 | Return the in-page resource being referred to in the given transaction |
paulb@666 | 273 | 'trans' or None if no valid in-page resource is being referenced. |
paulb@666 | 274 | """ |
paulb@666 | 275 | |
paulb@666 | 276 | name = self._get_in_page_resource(trans) |
paulb@666 | 277 | if self.in_page_resources.has_key(name): |
paulb@666 | 278 | return name |
paulb@666 | 279 | else: |
paulb@666 | 280 | return None |
paulb@666 | 281 | |
paulb@353 | 282 | def respond(self, trans): |
paulb@353 | 283 | |
paulb@353 | 284 | """ |
paulb@353 | 285 | Respond to the request described by the given transaction 'trans'. |
paulb@353 | 286 | """ |
paulb@353 | 287 | |
paulb@353 | 288 | # Only obtain field information according to the stated method. |
paulb@353 | 289 | |
paulb@534 | 290 | content_type = trans.get_content_type() |
paulb@353 | 291 | method = trans.get_request_method() |
paulb@353 | 292 | in_page_resource = self.get_in_page_resource(trans) |
paulb@353 | 293 | |
paulb@353 | 294 | # Handle typical request methods, processing request information. |
paulb@353 | 295 | |
paulb@353 | 296 | if method == "GET": |
paulb@353 | 297 | |
paulb@353 | 298 | # Get the fields from the request path (URL). |
paulb@353 | 299 | |
paulb@560 | 300 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@353 | 301 | parameters = trans.get_fields_from_path() |
paulb@353 | 302 | form.set_parameters(parameters) |
paulb@353 | 303 | |
paulb@534 | 304 | elif method == "POST" and content_type.media_type == "application/x-www-form-urlencoded": |
paulb@353 | 305 | |
paulb@353 | 306 | # Get the fields from the request body. |
paulb@353 | 307 | |
paulb@560 | 308 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@560 | 309 | if hasattr(self, "encoding"): |
paulb@560 | 310 | parameters = trans.get_fields_from_body(self.encoding) |
paulb@560 | 311 | else: |
paulb@560 | 312 | parameters = trans.get_fields_from_body() |
paulb@353 | 313 | |
paulb@353 | 314 | # NOTE: Konqueror workaround. |
paulb@353 | 315 | self.clean_parameters(parameters) |
paulb@353 | 316 | |
paulb@353 | 317 | form.set_parameters(parameters) |
paulb@353 | 318 | |
paulb@353 | 319 | else: |
paulb@353 | 320 | |
paulb@450 | 321 | # Initialise empty container. |
paulb@353 | 322 | |
paulb@560 | 323 | form = XSLForms.Fields.Form(encoding=None, values_are_lists=1) |
paulb@353 | 324 | |
paulb@353 | 325 | # Call an overridden method with the processed request information. |
paulb@353 | 326 | |
paulb@353 | 327 | self.respond_to_form(trans, form) |
paulb@353 | 328 | |
paulb@353 | 329 | def respond_to_form(self, trans, form): |
paulb@353 | 330 | |
paulb@353 | 331 | """ |
paulb@353 | 332 | Respond to the request described by the given transaction 'trans', using |
paulb@353 | 333 | the given 'form' object to conveniently retrieve field (request |
paulb@353 | 334 | parameter) information and structured form information (as DOM-style XML |
paulb@353 | 335 | documents). |
paulb@353 | 336 | """ |
paulb@353 | 337 | |
paulb@637 | 338 | self.select_activity(trans, form) |
paulb@637 | 339 | self.create_document(trans, form) |
paulb@637 | 340 | self.respond_to_input(trans, form) |
paulb@637 | 341 | self.init_document(trans, form) |
paulb@637 | 342 | self.respond_to_document(trans, form) |
paulb@637 | 343 | self.create_output(trans, form) |
paulb@353 | 344 | raise WebStack.Generic.EndOfResponse |
paulb@353 | 345 | |
paulb@637 | 346 | # Modular methods for responding to requests. |
paulb@637 | 347 | |
paulb@637 | 348 | def select_activity(self, trans, form): |
paulb@637 | 349 | |
paulb@637 | 350 | """ |
paulb@637 | 351 | Using the given transaction 'trans' and 'form' information, select the |
paulb@637 | 352 | activity being performed and set the 'current_activity' attribute in the |
paulb@637 | 353 | transaction. |
paulb@637 | 354 | """ |
paulb@637 | 355 | |
paulb@637 | 356 | pass |
paulb@637 | 357 | |
paulb@637 | 358 | def create_document(self, trans, form): |
paulb@637 | 359 | |
paulb@637 | 360 | """ |
paulb@637 | 361 | Using the given transaction 'trans' and 'form' information, create the |
paulb@637 | 362 | document involved in the current activity and set the 'current_document' |
paulb@637 | 363 | attribute in the transaction. |
paulb@637 | 364 | |
paulb@637 | 365 | Return whether a new document was created. |
paulb@637 | 366 | """ |
paulb@637 | 367 | |
paulb@637 | 368 | documents = form.get_documents() |
paulb@641 | 369 | activity = form.get_activity() |
paulb@637 | 370 | |
paulb@637 | 371 | if documents.has_key(activity): |
paulb@641 | 372 | form.set_document(documents[activity]) |
paulb@637 | 373 | return 0 |
paulb@637 | 374 | else: |
paulb@666 | 375 | form.new_document(activity) |
paulb@666 | 376 | form.new_documents.add(activity) |
paulb@637 | 377 | return 1 |
paulb@637 | 378 | |
paulb@637 | 379 | def respond_to_input(self, trans, form): |
paulb@637 | 380 | |
paulb@637 | 381 | """ |
paulb@637 | 382 | Using the given transaction 'trans' and 'form' information, perform the |
paulb@637 | 383 | parts of the current activity which rely on the information supplied in |
paulb@637 | 384 | the current document. |
paulb@637 | 385 | """ |
paulb@637 | 386 | |
paulb@637 | 387 | pass |
paulb@637 | 388 | |
paulb@637 | 389 | def init_document(self, trans, form, stylesheet_parameters=None, |
paulb@637 | 390 | stylesheet_expressions=None, references=None): |
paulb@637 | 391 | |
paulb@637 | 392 | """ |
paulb@637 | 393 | Using the given transaction 'trans' and 'form' information, initialise |
paulb@637 | 394 | the current document. |
paulb@637 | 395 | """ |
paulb@637 | 396 | |
paulb@646 | 397 | activity = form.get_activity() |
paulb@646 | 398 | |
paulb@637 | 399 | # Transform, adding enumerations/ranges. |
paulb@637 | 400 | |
paulb@646 | 401 | if self.init_resources.has_key(activity): |
paulb@646 | 402 | init_xsl = self.prepare_initialiser(activity) |
paulb@646 | 403 | form.set_document( |
paulb@646 | 404 | self.get_result( |
paulb@646 | 405 | [init_xsl], form.get_document(), stylesheet_parameters, |
paulb@646 | 406 | stylesheet_expressions, references |
paulb@646 | 407 | ) |
paulb@637 | 408 | ) |
paulb@637 | 409 | |
paulb@637 | 410 | def respond_to_document(self, trans, form): |
paulb@637 | 411 | |
paulb@637 | 412 | """ |
paulb@637 | 413 | Using the given transaction 'trans' and 'form' information, perform the |
paulb@637 | 414 | parts of the current activity which rely on a populated version of the |
paulb@637 | 415 | current document. |
paulb@637 | 416 | """ |
paulb@637 | 417 | |
paulb@637 | 418 | pass |
paulb@637 | 419 | |
paulb@637 | 420 | def create_output(self, trans, form, content_type=None, |
paulb@637 | 421 | stylesheet_parameters=None, stylesheet_expressions=None, references=None): |
paulb@637 | 422 | |
paulb@637 | 423 | """ |
paulb@637 | 424 | Using the given transaction 'trans' and 'form' information, create the |
paulb@637 | 425 | output for the current activity using the previously set attributes in |
paulb@637 | 426 | the transaction. |
paulb@637 | 427 | """ |
paulb@637 | 428 | |
paulb@637 | 429 | attributes = trans.get_attributes() |
paulb@637 | 430 | in_page_resource = self.get_in_page_resource(trans) |
paulb@637 | 431 | parameters = form.get_parameters() |
paulb@637 | 432 | |
paulb@637 | 433 | # Start the response. |
paulb@637 | 434 | |
paulb@651 | 435 | encoding = attributes.get("encoding") or self.encoding or trans.default_charset |
paulb@637 | 436 | content_type = content_type or WebStack.Generic.ContentType("application/xhtml+xml", encoding) |
paulb@637 | 437 | trans.set_content_type(content_type) |
paulb@637 | 438 | |
paulb@637 | 439 | # Ensure that an output stylesheet exists. |
paulb@637 | 440 | |
paulb@637 | 441 | stylesheet_parameters = stylesheet_parameters or {} |
paulb@637 | 442 | |
paulb@666 | 443 | if in_page_resource: |
paulb@637 | 444 | trans_xsl = self.prepare_fragment(in_page_resource) |
paulb@637 | 445 | stylesheet_parameters.update(self.prepare_parameters(parameters)) |
paulb@637 | 446 | else: |
paulb@641 | 447 | trans_xsl = self.prepare_output(form.get_activity()) |
paulb@637 | 448 | |
paulb@637 | 449 | # Complete the response. |
paulb@637 | 450 | |
paulb@641 | 451 | self.send_output(trans, [trans_xsl], form.get_document(), |
paulb@637 | 452 | stylesheet_parameters, stylesheet_expressions, references) |
paulb@637 | 453 | |
paulb@637 | 454 | # General helper methods. |
paulb@637 | 455 | |
paulb@637 | 456 | def add_elements(self, positions, *element_names): |
paulb@637 | 457 | |
paulb@637 | 458 | """ |
paulb@637 | 459 | At the given 'positions', typically obtained as "selectors", add the |
paulb@637 | 460 | hierarchy of elements given in the 'element_names' parameters. |
paulb@637 | 461 | """ |
paulb@637 | 462 | |
paulb@637 | 463 | XSLForms.Utils.add_elements(positions, *element_names) |
paulb@637 | 464 | |
paulb@637 | 465 | def remove_elements(self, positions): |
paulb@637 | 466 | |
paulb@637 | 467 | """ |
paulb@637 | 468 | Remove elements at the given 'positions', typically obtained as |
paulb@637 | 469 | "selectors". |
paulb@637 | 470 | """ |
paulb@637 | 471 | |
paulb@637 | 472 | XSLForms.Utils.remove_elements(positions) |
paulb@637 | 473 | |
paulb@509 | 474 | def prepare_output(self, output_identifier): |
paulb@509 | 475 | |
paulb@509 | 476 | """ |
paulb@509 | 477 | Prepare the output stylesheet for the resource class or object 'self' |
paulb@509 | 478 | corresponding to the given 'output_identifier'. Return the template path |
paulb@509 | 479 | and the output stylesheet path in a 2-tuple. |
paulb@509 | 480 | """ |
paulb@509 | 481 | |
paulb@509 | 482 | template_filename, output_filename = self.template_resources[output_identifier] |
paulb@509 | 483 | output_path = os.path.abspath(os.path.join(self.resource_dir, output_filename)) |
paulb@509 | 484 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 485 | XSLForms.Prepare.ensure_stylesheet(template_path, output_path) |
paulb@509 | 486 | return template_path, output_path |
paulb@509 | 487 | |
paulb@509 | 488 | def prepare_fragment(self, fragment_identifier): |
paulb@509 | 489 | |
paulb@509 | 490 | """ |
paulb@509 | 491 | Prepare the output stylesheet for the resource class or object 'self' |
paulb@509 | 492 | corresponding to the given 'fragment_identifier'. Return the template path |
paulb@509 | 493 | and the output stylesheet path in a 2-tuple. |
paulb@509 | 494 | """ |
paulb@509 | 495 | |
paulb@509 | 496 | output_identifier, fragment_filename, node_identifier = self.in_page_resources[fragment_identifier] |
paulb@509 | 497 | fragment_path = os.path.abspath(os.path.join(self.resource_dir, fragment_filename)) |
paulb@509 | 498 | template_filename, output_filename = self.template_resources[output_identifier] |
paulb@509 | 499 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 500 | XSLForms.Prepare.ensure_stylesheet_fragment(template_path, fragment_path, node_identifier) |
paulb@509 | 501 | return template_path, fragment_path |
paulb@509 | 502 | |
paulb@509 | 503 | def prepare_initialiser(self, input_identifier, init_enumerations): |
paulb@509 | 504 | |
paulb@509 | 505 | """ |
paulb@509 | 506 | Prepare the initialising stylesheet for the resource class or object 'self' |
paulb@509 | 507 | corresponding to the given 'input_identifier' and 'init_enumerations' flag. |
paulb@509 | 508 | Return the template path and the initialising stylesheet path in a 2-tuple. |
paulb@509 | 509 | """ |
paulb@509 | 510 | |
paulb@509 | 511 | template_filename, input_filename = self.init_resources[input_identifier] |
paulb@509 | 512 | input_path = os.path.abspath(os.path.join(self.resource_dir, input_filename)) |
paulb@509 | 513 | template_path = os.path.abspath(os.path.join(self.resource_dir, template_filename)) |
paulb@509 | 514 | XSLForms.Prepare.ensure_input_stylesheet(template_path, input_path, init_enumerations) |
paulb@509 | 515 | return template_path, input_path |
paulb@509 | 516 | |
paulb@509 | 517 | def prepare_resources(cls): |
paulb@509 | 518 | |
paulb@509 | 519 | "Prepare the resources associated with the class 'cls'." |
paulb@509 | 520 | |
paulb@509 | 521 | for output_identifier in cls.template_resources.keys(): |
paulb@509 | 522 | prepare_output(cls, output_identifier) |
paulb@509 | 523 | for fragment_identifier in cls.in_page_resources.keys(): |
paulb@509 | 524 | prepare_fragment(cls, fragment_identifier) |
paulb@509 | 525 | |
paulb@509 | 526 | # NOTE: Using init_enumerations=1 here. |
paulb@509 | 527 | |
paulb@509 | 528 | for input_identifier in cls.init_resources.keys(): |
paulb@509 | 529 | prepare_initialiser(cls, input_identifier, 1) |
paulb@509 | 530 | |
paulb@634 | 531 | # Convenience methods for specifying resources. |
paulb@634 | 532 | |
paulb@634 | 533 | def split(filename): |
paulb@634 | 534 | |
paulb@634 | 535 | """ |
paulb@634 | 536 | Return a tuple containing the directory and filename without extension for |
paulb@634 | 537 | 'filename'. |
paulb@634 | 538 | """ |
paulb@634 | 539 | |
paulb@634 | 540 | d, leafname = os.path.split(filename) |
paulb@634 | 541 | name, ext = os.path.splitext(leafname) |
paulb@634 | 542 | return d, name |
paulb@634 | 543 | |
paulb@634 | 544 | def output(template_filename): |
paulb@634 | 545 | |
paulb@634 | 546 | """ |
paulb@634 | 547 | Return a tuple containing the 'template_filename' and a suitable output |
paulb@634 | 548 | stylesheet filename. |
paulb@634 | 549 | """ |
paulb@634 | 550 | |
paulb@634 | 551 | d, name = split(template_filename) |
paulb@634 | 552 | output_name = name.replace("_template", "_output") + os.path.extsep + "xsl" |
paulb@634 | 553 | return (template_filename, os.path.join(d, output_name)) |
paulb@634 | 554 | |
paulb@634 | 555 | def input(template_filename): |
paulb@634 | 556 | |
paulb@634 | 557 | """ |
paulb@634 | 558 | Return a tuple containing the 'template_filename' and a suitable output |
paulb@634 | 559 | stylesheet filename. |
paulb@634 | 560 | """ |
paulb@634 | 561 | |
paulb@634 | 562 | d, name = split(template_filename) |
paulb@634 | 563 | input_name = name.replace("_template", "_input") + os.path.extsep + "xsl" |
paulb@634 | 564 | return (template_filename, os.path.join(d, input_name)) |
paulb@634 | 565 | |
paulb@634 | 566 | def resources(filename, d="Resources"): |
paulb@634 | 567 | |
paulb@634 | 568 | """ |
paulb@634 | 569 | Return the resource directory for the given 'filename', using the optional |
paulb@634 | 570 | directory name 'd' to indicate the directory relative to the directory of |
paulb@634 | 571 | 'filename' (or the default directory name, indicating that the directory |
paulb@634 | 572 | called "Resources" - a sibling of 'filename' - is the resource directory). |
paulb@634 | 573 | |
paulb@634 | 574 | It is envisaged that callers provide the value of the __file__ special |
paulb@634 | 575 | variable to get the resource directory relative to a particular module. |
paulb@634 | 576 | """ |
paulb@634 | 577 | |
paulb@634 | 578 | return os.path.join(os.path.split(filename)[0], d) |
paulb@634 | 579 | |
paulb@353 | 580 | # vim: tabstop=4 expandtab shiftwidth=4 |