Child pages
  • Creating Custom Renderers

Creating Custom Renderers (XSL files) for OSP Forms Using Oxygen

Creating a custom renderer is a complex task. It is simplified somewhat by using the “xslt-façade”, which helps you run your transformation locally and see results that are very similar to what you would see in production. Without the façade, the local version of the file and the version that runs on the Sakai server use different paths. As a result, every time you want to upload the file to your Sakai server, you need to edit the paths, which is a tedious and error-prone task.  What the façade does is pretend to be a Sakai server, catching commands that are requesting output from the server, and returning output that corresponds to what the server would have provided. Specifically, the façade manages file references specified with the Sakai function sakaifn:getReferenceUrl() . These file references will work both in the façade and on the server, allowing you to use the same, unaltered file both places. For example, in the Page Composer the authoring directory, which holds most of the files that make the Page Composer work, is referenced with the line:

sakaifn:getReferenceUrl('/group/PortfolioAdmin/authoring/')

As long as the path /group/PortfolioAdmin/authoring is valid on both the local host and the production server, the same XSL file will work in both places. Note that you will need to use sakafn:getReferenceUrl() to include any ancillary files your custom renderer needs, such as CSS or JavaScript. The process adding ancillary files is described in the instructions below.

The façade also manages other information that would normally come from the server by virtue of sakaifn functions, though it may not look the same both places. For example, the label for the Display Name might be displayed as: {loaderKey: messages, key: display.name.label} –  the façade knows that a label is being requested, though it doesn’t know what string should be supplied for display.name.label .

The instructions in this document explain how to set up and run local custom renderer transformations using the Oxygen XML editor. They also introduce the topic of creating the renders themselves. The façade is written in Java and works on Windows, Macs, and Linux. These instructions are written from a Windows perspective, but they should be clear to Mac and Linux users.

A Note: Creation v. View Renderers

When a user opens a file for editing, OSP uses a “creation renderer” ( formCreate.xslt ) to display the form. When a form has been filled out and saved in a matrix, and the name of the form is clicked on by either the user or a reviewer, OSP uses a “view renderer” ( formView.xslt ) to display the form. 

When you create a custom renderer, you must create it either as a creation or a view renderer.  These instructions will focus primarily on creation renderers, but the last example, Creating a View Renderer on page 20 presents a view renderer.

Setting up your environment

  1. If your custom renderer will not be using its own CSS or JavaScript files, simply create a working directory somewhere on your system where you can create the files you need. I usually just create a directory in the Documents folder.

    If your custom renderer will reference its own CSS or JavaScript, or if you want your forms to use Sakai CSS files, you will want to install a local web server to be able to see the effects of those files. On Windows, I use either XAMPP ( http://www.apachefriends.org/en/xampp-windows.html ) or WampServer ( http://www.wampserver.com/en/ ).  Both of these are very easy to install and use. I install them directly under C:\ (e.g., C:\wamp\.)

    Note that if you are using a local web server, you will want to do some more setup after you have downloaded your passthrough XML (see The Structure of the Passthrough XML on page 13 and Creating a View Renderer on page 20 below).
  2. Copy the xslt-facade-1.0.jar file (available from https://confluence.sakaiproject.org/display/OSP/Custom+XSLT+offline+with+xslt-facade ) into a central location on your system. I usually put it in the document root directory of my web server or, when I am not using a web server, in my Documents directory. This will make it easy to find for multiple projects, though it can go anywhere. (For WampServer, the document root is the www directory, for XAMPP it is htdocs .)
  3. If relevant, start your web server:
    For WampServer: Start > All Programs > WampServer > Start WampServer .
    For XAMPP: go to C:\xampp and click the xampp startup exe.
  4. Make your PortfolioAdmin “ system ” directory available to the façade in the appropriate directory structure. That is, place it in this directory structure:

       C:\group\PortfolioAdmin\system

    NOTE : This directory must be off the root directory for your system , not off the document root of your web server.

    TIP : You may want to use a WebDAV client like AnyClient to do this, though there are really only three files there that you need, formCreate.xslt , formView.xslt , and formFieldTemplate.xslt .

    NOTE : A large number of versions of formCreate.xslt have accumulated in the Sakai PortfolioAdmin > Resources > system folder. To get the correct file, sort the list by Modified, and select the most recent version.
     
  5. Create a working directory for this project under your web server document root or any other place that is convenient for you (e.g., C:\wamp\www\myproject or C:\Users\yourname\My Documents\myproject ).
  6. Create a “starter” XSL file by placing a copy of formCreate.xslt (available in PortfolioAdmin > Resources > system ) in your project directory and rename it something like mycustomrenderer.xsl .
  7. In line 2 of the starter file, change the version of the stylesheet from 2.0 to 1.0 (i.e., change <xsl:stylesheet version = "2.0" to <xsl:stylesheet version = "1.0"… ) This will allow you to get relevant error messages. Sakai uses XSL 1.0, so this change won’t hurt anything when you copy the file up to your Sakai server.
  8. Above line 8 in the starter file (just before the line <xsl:param name = "panelId" /> ) insert the following line:
    <xsl:import href = "/group/PortfolioAdmin/system/formCreate.xslt" />

    TIP : Remember that <xsl:import> must always come first in the stylesheet. Also be aware that you always want to use <xsl:import> not <xsl:include> when you want to override templates in the imported file(s).  It is “import” that establishes the precedence of the custom renderer over the imported file(s), while “include” will simply cause a conflict between the identically named templates.
  9. Comment out the line (around line 16): 
    <xsl:include href = "/group/PortfolioAdmin/system/formFieldTemplate.xslt" /> .
  10. Add some HTML to your starter file so that you will know whether it has been used or not when you run your transformation. For example, in mycustomrenderer.xsl , find the HTML <title> tag, comment out the existing content, and add in something like, “THIS IS MY CUSTOM RENDERER”:

    <title>
              THIS IS MY CUSTOM RENDERER
             <!--    <xsl:value-of select="formData/artifact… /> -->
    </title>

    Then when you run your custom renderer, you can look at the title at the top of your browser and verify that it has the correct content.

Getting “Passthrough” Data to Run Your Transformation Against

In order to run your transformation locally, you need a copy of the data that the transform will be manipulating. This is obtained by attaching a “passthrough” file to the form that you are trying to modify.  The passthrough file, usually named “ passthrough.xsl ”, simply copies all the data that it is handed and makes it available to the user. The content of a typical passthrough.xsl file is:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
  <xsl:template match = "/" >
    <xsl:copy-of select = "*" />
  </xsl:template>
</xsl:stylesheet>

You can download a passthrough.xsl file from https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers .

TIP : I recommend using Firefox for the steps below, since that will make it easier to copy the “passthrough” source from the iframe in which it will be embedded.

The steps to obtaining your passthrough data are:

  1. In the site that you are working with on your Sakai server, fill out a form of the type you wish to modify. Be sure to fill in every field, and you may want to put identifying information in each field to show where it is coming from (e.g., if you have a field name “Title”, you might enter a value like “Title from Form”.) Be sure that text fields have a typical amount of text in them, so that the results of your transformation look realistic.
  2. Upload the passthrough.xsl file to your site’s Resources .
  3. In your site, use the Forms tool to attach the passthrough.xsl file as the Alternate Form Creation Renderer or the Alternate Form View Renderer , as shown in the screenshot below:
    AddingCreationRenderers.png  
  4. View the form in the appropriate context. If you are creating a creation renderer, find the form you created in Step 1 above and open it for editing. If you are creating a view renderer, go to the matrix and click on the name of the completed form to view it, as shown in the screenshot below:
    CustomRenderer-ViewMatrix.png
    You will see a jumble of unformatted text, like that shown below:
    unformattedpassthrough.png  
  5. In Firefox, for a creation renderer, right click in the unformatted text and select This Frame > View Frame Source . For a view renderer, simply select View Source .
  6. Save the frame source file into your project directory with a name such as “ myform_passthrough.xml ”.

    Note that if, instead of saving the file directly, you select all the text of the source file and copy it into a new XML document in Oxygen, there will be red markings indicating that the file is not valid XML. Select the whitespace at the top of the file and delete it. The red marking should go away, because the file is now valid. Save the valid file.

The structure of the passthrough XML is discussed below in The Structure of the Passthrough XML on page 13 .

Configuring Your Oxygen “Transformation Scenario”

  1. In Oxygen, with your passthrough data file selected (e.g., myform_passthrough.xml ), click the Configure Transformation Scenario   “wrench” icon (or CTRL-Shift-C):
    ConfigureTransformationScenarioWrench.png  
  2. In the Configure Transformation Scenario dialog, accept the default selections Global Scenarios and Scenario type: XML transformation with XSLT .
    ConfigureTransformDialog.png  
  3. Click the New button to bring up the New Scenario dialog:
    NewScenario.png  
  4. In the New Scenario dialog, do the following:
    1. If you wish, modify the name of the scenario
    2. Accept the default for XML URL
    3. Click the folder icon for XSL URL and select your “starter xsl” file (e.g., mycustomrenderer.xsl )
    4. Set the Transformer to “Xalan”
    5. Click the Extensions button to open the Edit Extensions dialog
    6. Click Add in the Edit Extensions dialog, then browse to the xslt-facade-1.0.jar file that you copied to your system in Step 2 of Setting up your environment . Click OK , then OK again to return to the New Scenario dialog.
    7. Click the Output tab of the New Scenario dialog to display the tab shown below:
      NewScenarioOutput.png  
    8. Click the Save As radio button and add a name for your output file. Use an .html extension.
    9. Click the Open in browser check box
    10. Click OK to return to the Configure Transformation Scenario dialog
  5. Click the Transform now button in the Configure Transformation dialog to test your setup. If everything goes right, the HTML for your output will show up in a pane at the bottom of your Oxygen application, and your browser will open up with the file myoutput.html displayed. If you are using a local web server, you can see the file approximately as it will look served from your Sakai server by changing the URL in the browser to use your localhost server. For example, if you have generated the file with the following URL: file:///C:/wamp/www/myproject/myoutput.html ,
    change it to:
    http://localhost/myproject/myoutput.html
    Note that every time you run your transformation, this file will be overwritten with new output, which will open up in a new browser tab. You can save yourself some typing by just refreshing this original tab that has the correct localhost URL in it.

Creating a Custom Renderer : Essential Background Information

Once you have completed the preceding steps and are able to run your transformation successfully, you are ready to begin the process of actually creating a creation renderer or view renderer.  For now, these instructions will focus on writing creation renderers. If you are only interested in view renderers, skip to Creating a View Renderer on page 20 .

Before creating a custom renderer, you are faced with a choice:

  1. You can base your custom renderer on formCreate.xslt and formFieldTemplate.xslt . This approach requires some understanding of these base files, which will take an investment of time. It is especially important to understand the logic of how the file formFieldTemplate.xslt transforms elements specified with the form’s schema into HTML (a topic discussed below in How OSP Transforms XSD Elements into HTML Elements on page 11 ). You will also need to understand the structure of the XML for your form, especially the way that the schema is represented in the passthrough data xml (referred to above as myform_passthrough.xml ). This is the best approach to take if your custom renderer will be used with more than one form type, where you can’t predict exactly what form elements (textfields, radio buttons, etc.) will be used in the forms.

    WARNING: Do not EVER modify the versions of formCreate.xslt , formView.xslt, or formFieldTemplate.xslt that ship with Sakai and are found in PortfolioAdmin > Resources > system. Always create overrides in your custom renderer .
     
  2. You can create a custom renderer from scratch. If you take this approach, you will still need to understand the structure of the passthrough data xml (referred to above as myform_passthrough.xml and discussed below in The Structure of the Passthrough XML on page 13 ), especially the way that the form’s schema is represented in the XML. You may find it helpful to refer to the file formFieldTemplate.xslt to get ideas for how to write your own XSL. This approach is often the best one to take when your custom renderer will only be used with a single form type and you know exactly what fields will be present in the form and how you want them displayed.
  3. If you are using the Page Composer, you will need to use a variant of the first option described above. Since Page Composer forms already have custom renderers, you would be modifying the existing renderers. The Page Composer completely replaces the use of formCreate.xslt with the file formCreate-wywiwyg.xls . It is formCreate-wysiwyg.xsl that is imported into the custom renderer instead of formCreate.xslt .

The remainder of these instructions will focus on the first method, using a form created based on the XSD file test-select.xsd , available at https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers . An example passthrough XML file that corresponds to the test-select.xsd schema is also available there. The example passthrough XML file is named myform_passthrough.xml.

To understand how to create custom renderers using the first approach, it is crucial to understand how “metaobj” (for our purposes, formCreate.xslt , formView.xslt and formFieldTemplate.xslt ) transforms schema-driven data into HTML. That topic is addressed in the next section. Even if you are using the second approach, creating a custom renderer from scratch, you may find the next section helpful, since you will need to be solving the same problems that metaobj solves. Alternatively, you can skip to the following section, The Structure of the Passthrough XML on page 13 .

How OSP Transforms XSD Elements into HTML Elements

The basic elements of a form are defined by the schema, as expressed in the form’s XSD file. An XSD element can have one of six possible restrictions. The first three of them are the ones it is most important to understand:

  • xs:string
  • xs:date
  • xs:anyURI
  • xs:boolean
  • xs:integer
  • xs:decimal

These restrictions can be further limited in certain ways. For example, an element with the restriction xs:string might have a maxLength , limiting it to a certain number of characters. OSP’s metaobj, by means of the file formFieldTemplate.xsl , uses these restrictions and their limitations to determine what kind of HTML to use in displaying the element to the user for input. For example, an xs:string with a maxLength of 99 characters will be displayed as a textfield, while an xs:string with a maxLength of 100 characters or more will be displayed as a text area.

The possible limitations for the XSD restrictions are:

  • minOccurs (if this is set to “1”, then the element is required. “0” means it is optional.)
  • maxOccurs (if this is set to a number greater than “1”, then multiple items of this kind can be created)
  • enumeration (the elements in an enumeration might, for example, be used to create the options in a select list)
  • maxLength (e.g., how many characters can be in a field. OSP uses this to determine things like how many rows should be displayed in a text area or whether to display a textfield or a text area.)

The following table shows how the different combinations of element and restrictions are transformed into HTML elements. The better you understand this table, the easier it will be to work with custom renderers.

Table 1: The Core OSP Element Restrictions and the HTML Elements They Yield

Restriction

Limitations

HTML Element

xs:date

 

date picker

xs:anyURI

 

file upload button

xs:string

element limited in XSD to < 100 characters

textfield

element allowed to have ≥ 100 characters

text area

element has the OSP “annotation” isRichText = true

rich text editor

element has < 4 enumeration items, with maxOccurs = 1

radio buttons

element has < 4 enumeration items, with maxOccurs > 1

checkboxes

element has ≥ 4 enumeration items, with maxOccurs =  1

dropdown

element has ≥ 4 enumeration items, with maxOccurs > 1

multi-select

 

 

 

An invaluable tool for gaining familiarity with these relationships is a set of XSD files created by Gonzalo Silverio and available at: https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers . These files exercise virtually every permutation of restriction and limitation possible.

The PortfolioAdmin “ system ” Files

In creating custom creation renderers, it is important first to get an understanding the functioning of two of the most important files in the PortfolioAdmin > Resources > system folder, formCreate.xslt and formFieldTemplate.xslt .

The file formCreate.xslt orchestrates the transformation of form elements into HTML. The file formCreate.xslt only does two things:

  • It creates the wrapper around the form (the <html>, <head> and <body> tags, the Save and Cancel buttons, etc.)
  • It figures out what kind of element has been encountered in the XML (e.g., xs:string or xs:anyURI ) and calls the correct template to process the element.  The template that gets called is not contained in formCreate.xslt , but rather in formFieldTemplate.xslt .

To repeat, the template that gets called to carry out the actual transformation lives in formFieldTemplate.xslt . So, for example, formCreate.xslt contains the template shown below, which is triggered whenever an xs:string that contains an enumeration is encountered (see the bolded text). When this happens, it calls formFieldTemplate.xslt ’s “ select-field ” template, since it knows it will be creating some kind of HTML selection input (radio buttons, checkboxes, a drop down menu, or a multi-select box). But it is formFieldTemplate.xslt , not formCreate.xslt that decides what particular kind of input to actually create.

<xsl:template match = "element[xs:simpleType/xs:restriction[@base= 'xs:string' ]/ xs:enumeration ]" >
<xsl:param name = "currentParent" />
<xsl:param name = "rootNode" />
<xsl:call-template name = " select-field " >
<xsl:with-param name = "currentSchemaNode" select = "." />
<xsl:with-param name = "currentParent" select = "$currentParent" />
<xsl:with-param name = "rootNode" select = "$rootNode" />
</xsl:call-template>
</xsl:template>

For the most part, what you will be doing when creating a custom renderer is overriding the default templates contained in formFieldTemplate.xslt . However, please remember:

Never modify formFieldTemplate.xslt or formCreate.xslt directly. Always use your custom renderer to override the templates in these files.

The Structure of the Passthrough XML

The passthrough XML that you captured in Getting “Passthrough” Data to Run Your Transformation Against on p. 4 contains the information that the user has entered in the form (if any), so the contents will be different for every form. However, all OSP passthrough XML has a standard structure, which you need to understand. If you have not created passthrough output yourself, you can see some very simple output in the file myform_passthrough.xml , available at https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers .

The skeleton of the structure of the XML is:

<formView>

<formData>

<artifact>

<metaData>

</metaData>

<structuredData>

</structuredData>

<schema>

</schema>

</artifact>

</formData>

<css>

<uri order="1">/ctlib/skin/tool_base.css</uri>

        <uri order="2">/ctlib/skin/ctoolstest/tool.css</uri>

</css>

</formView>

 

These elements play the following roles:

  • <formView>: The root node of the form will always be “formView”. The first template in your custom renderer will probably “match” on this.
  • <artifact>: This holds all the data specific to the particular form, including metadata, structured data, and a representation of the form’s schema.
  • <metaData>: This holds information about the form, such as the ID of this form instance, the Display Name of the form, the user’s EID and name, etc.
  • <structuredData>: This is the actual data entered by the user. For example, if in the “select-radio” field the user chose “Score 2”, the structured data would look like:
    <select-radio>Score2</select-radio>
  • <schema>: The schema is reproduced in the XML so that metaobj and your custom renderer know what elements (textfields, radio buttons, selects, etc.) need to be placed in the form. After these elements are in the form, metaobj goes back through and sets the values of the different elements to the values represented in the “structured data”. So, continuing the example of the “select-radio” field, metaobj sees that the element “ select-radio ” is of type “ xs:string ” with maxOccurs equal to one and with only three enumerations. It knows from this that it should build a radio group. Once it has done that, it sees that there is structured data for “select-radio”, so it sets the “Score 2” radio button in the selected state.
  • <css>: The location of the tool_base.css and tool.css files, which control the appearance of forms. In an out-of-the-box Sakai instance, these files are located in /library/skin/tool_base.css and /library/skin/default/tool.css . In the skeleton XSL shown above, the University of Michigan skin versions of these files are located off the /ctlib/skin/ directory. If you are using a local web server, you will want to make these files available to your server by creating this directory hierarchy in your web server document root (for example, you might download https://yoursakaiserver/library/skin/tool_base.css to C:\wamp\www\library\skin\tool_base.css , etc.).

With this understanding, it is time to turn to creating custom renderers.

A First Custom Renderer

As we mentioned above, when one XSL file imports another XSL file, the templates in the importing file have precedence (will override) the templates in the imported file. For this exercise, the strategy we will use to override templates in formFieldTemplate.xslt is to have a custom renderer which imports formCreate.xslt , which in turn imports formFieldTemplate.xslt (see the figure below). Once we determine what template is responsible for the transformation we want to modify, we will copy that entire template from formFieldTemplate.xslt into our custom renderer and modify the template there to meet our needs.

Overriding a Template From formFieldTemplate.xsl to Set “htmldeterm”

A common need in OSP is to get a drop down menu when OSP wants to give you radio buttons, to get checkboxes when OSP wants to give you a multi-select box, or the reverse of these. This decision is controlled by a single variable in the “ select-field ” template of formFieldTemplate.xsl . Unfortunately, the way formFieldTemplate.xslt is currently structured, you have to pull in the entire “ select-field ” template to change this one variable.  To get an idea of where we are going, the screenshots below show how the form would look in a real Sakai server both before and after attaching the custom renderer. Note that in the second screenshot, all the HTML “selection-type” elements are drop-down menus:

The steps to make this change are given below:

  1. If your passthrough data XML (e.g., myform_passthrough.xml ) does not have some kind of selection input in it (radio buttons, checkboxes, a drop-down menu, or a multi-select box,) create a form that has such an input. For this tutorial, you can use the file test-select.xsd , available from https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers .
  2. Open the “starter” XSL file ( mycustomrenderer.xsl ), which you will remember is just a slightly modified version of formCreate.xslt that you created in Steps 6 through 10 of Setting up Your Environment on page 3 above.
  3. Delete all the xsl:templates in the custom renderer, leaving:
    1. the XML declaration (the first line),
    2. the opening of the <xsl:stylesheet> declaration (line 2),
    3. the two xs:import statements we added in Step 8 of Setting up Your Environment ,
    4. the five xsl:params following the imports, and
    5. the very last line of the file (the closing of the </xsl:stylesheet> declaration).
  4. Open formFieldTemplate.xslt , locate the “ select-field ” template, and copy the entire thing into your custom renderer file. The template is big and complex, so be sure that you are starting and ending your selection in the right places. Paste the template between the last xsl:param ( <xsl:param name = "edit" />) and the closing </xsl:stylesheet> tag.
  5. In the custom renderer, search for the term “ htmldeterm ” and change it to the number you want (refer to Table 1: The Core OSP Element Restrictions and the HTML Elements They Yield on page 12 for guidance.) If you are using a form based on the example file test-select.xsd , set htmldeterm to 1.
  6. Save the custom renderer file.
  7. In Oxygen, select your passthrough data file (e.g., myform_passthrough.xml ). This is important: you must be in the passthrough XML for the form in order to run your transformation.
  8. Click the Apply Transformation Scenario button transformarrow.png .
  9. If your browser does not open with the output file displayed, look at the bottom pane of the Oxygen window to see if there is an error message. Correct the error and run the transformation scenario again.

If you have set “ htmldeterm ” to 1, then the output will display in your browser showing all the select-type inputs as drop-downs or multi-select boxes, as shown in the screenshot below.

CustomRenderer-CreateFormNoServer.png

If you have set up a local web server and downloaded the different Sakai CSS files ( tool_base.css and tool.css ), the page will look something like the screenshot shown below. (Note that the screenshot shows the result of using the University of Michigan skin’s versions of tool_base.css and tool.css .)

CustomRenderer-CreateLocalWithToolCSS.png

 

Adding a CSS File to Your Custom Renderer

If you wish to have your custom renderer link to a CSS or JavaScript file, you must do two things:

  • Override the template in formCreate.xslt that creates the wrapper for the form. This template matches “ formView ” (look for: <xsl:template match = "formView" > ).
  • Use the sakaifn:getReferenceUrl() function to make the CSS or JavaScript file available to OSP.

Note that to actually see the effect of the CSS on the file, you will need to view it served from your local web server. However, this is not necessary to determine whether or not the transformation produced the desired results; simply look in the source HTML for the link to the CSS file and verify that the name and paths are correct.

This tutorial will attach the file testcss.css to the form created in A First Custom Renderer above.

  1. Make a folder for ancillary files available to the façade by creating a new directory named “ support ” in C:\group\PortfolioAdmin\ .

    NOTE : you should never add your own files to the “ system ” directory, so that you do not complicate upgrades.
     
  2. Download the file testcss.css from https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers into the “ support ” directory.
  3. Open formCreate.xslt and find the template that matches formView ( <xsl:template match = "formView" > ).
  4. Copy this template into your custom renderer in front of the “ select-field ” template that you modified in A First Custom Renderer above.
  5. Near the top of the custom renderer, just before the first template, create an xsl:variable that uses sakaifn:getReferenceUrl() to identify the CSS file to OSP:

    <xsl:variable name = "supportPath" select = "sakaifn:getReferenceUrl('/group/PortfolioAdmin/support/')" />
  6. In the template that matches “ formView ”, use this variable in a <link> tag in the <head> section. For example, place the following line just above the closing </head> tag:

    <link type = "text/css" rel = "stylesheet" media = "all" href = "{$supportPath}testcss.css" />
    Note that the $supportPath variable is surrounded by curly braces {}, and there is no slash before the filename. Variables do not usually need to be surrounded by curly braces in XSL. The reason they are required here is to differentiate the variable from the rest of the filename.
  7. Save the file.
  8. Run the transformation by clicking the red arrow transformarrow.png .
  9. If you have a web server set up, change the beginning of the URL to use http://localhost / instead of file:///c:/wamp/www/ (or whatever the path is to your document root) and verify that there is more spacing below the drop down menus and the labels are blue. If you are not using a web server, view the source of the output and verify that the <link> to the CSS file is present and the paths are accurate.

CustomRenderer-CreateLocalWithTestcss.png

Creating a View Renderer

Our next example will be to create a view renderer by making modifications to a copy of formView.xslt , the default view renderer for OSP. It is worth noting that formView.xslt , the default view renderer in OSP, is much simpler than the combination of formCreate.xslt and formFieldTemplate.xslt . While formView.xslt has several templates with the same names as templates in formFieldTemplate.xslt, these template are completely independent; formView.xslt does not import or include formFieldTemplate.xslt, so it is not overriding any of its templates.

The passthrough XML for the “view” and the “creation” views of the form is identical, so you can use your existing passthrough. Remember that the view renderer is only relevant in the Matrices tool; it is what is used to render the page when you click on the name of the form in the matrix cell:

In our example, we will make two changes:

  • Include a CSS file that gets rid of the orange text
  • Add the Owner of the form to the metadata that is displayed so that the reviewer is reminded of whose form they are reviewing.

If you are using a web server in order to be able to see what the form will look like with CSS applied to it, you will want to make the following files available off your server’s document root (e.g., C:\wamp\www or C:\xampp\htdocs ):

  • \sakai-metaobj-tool\css\metaobj.css
  • \library\image\sakai\checkon.gif
  • \library\image\sakai\checkoff.gif

These files can be found by appending the paths above to https://yoursakaiserver/ (do not use “ portal ” or “ site ” in the address.) Note that checkoff.gif is a clear image, so you won’t be able to see it. Just click in the upper left-hand corner of the browser window to select it for viewing and downloading.

If you are not using a web server, instructions will be included below for how to ensure that your transformation has worked correctly.

The before and after screenshots below are from a production Sakai server and show what we are aiming for: a different color for the H4 headings and the inclusion of the name of the person who created the form.


 

  1. If you are using a local web server, download the file testviewcss.css from https://confluence.sakaiproject.org/display/OSP/Creating+Custom+Renderers into the directory C:\yourdocumentroot\group\PortfolioAdmin\support . Note that this is not the \group\PortfolioAdmin directory that you have created off of your system root directory; what you are doing now is making files available to your web server, rather than to the façade.
  2. If you are using a local web server, make the Sakai files mentioned above ( metaobj.css , checkon.gif , and checkoff.gif ) available in your document root in the expected places.
  3. In your project directory make a copy of formView.xslt and rename it something like myviewrenderer.xsl .
  4. Click the Configure Transformation Scenario icon transformarrow.png   and click Edit to modify the scenario. In the XSL URL row, click the folder icon to browse for and select your custom view renderer (myviewrenderer.xsl).  You may also wish to change the name of the output file by clicking the Output tab.
  5. Click OK .
  6. Click Transform now to test your setup. Your browser should open up with output like the screenshot below:
    CustomRenderer-ViewTransformNoRenderer.png
    There are two things to note about this screenshot. First, the text {loaderKey: messages, key: created} indicates that in the environment of a real Sakai server, the value for the “created” key from the localization bundle “messages” would be plugged in here. Second, since the checkon.gif and checkoff.gif images are not available, the alt text “unchecked” or “checked” is displayed in front of each possible value, indicating whether the item has been selected by the user or not.
  7. If you are using a local web server, change the address of the form to use “localhost” in order to see what the form looks like with CSS and the images present. It should look like the left-hand preview screenshot given above, but with the {loaderKey: …} text still present in place of the words “Created” and “Modified”.
  8. In the <head> section of your custom view renderer, add the following lines:
    <link type = "text/css" rel = "stylesheet" media = "all" >
          <xsl:attribute name = "href" >
         <xsl:value-of select = "sakaifn:getReferenceUrl('/group/PortfolioAdmin/support/testviewcss.css')" />
         </xsl:attribute>
    </link>
    Note that we are adding an <xsl:attribute>   with the name “ href ” to the stylesheet link. This is taking a slightly different approach to solving the same problem we were faced with in Steps 5 and 6 of Adding a CSS File to Your Custom Renderer above: we need a way to work the “ sakaifn:getReferenceUrl() ” function into the <link>.
  9. Locate the template “ produce-metadata ” (around line 283) and find the line:
    <strong>
         <xsl:value-of select = "sakaifn:getMessage('messages', 'created')" />
    </strong>
  10. Between the end of the <xsl:value-of> tag and the beginning of the </strong> tag, add in the following:

    by <xsl:value-of select = "/formView/formData/artifact/metaData/repositoryNode/owner/displayName" />

    The section of code should now look like:

    <strong>
         <xsl:value-of select = "sakaifn:getMessage('messages', 'created')" /> by <xsl:value-of select = "/formView/formData/artifact/metaData/repositoryNode/owner/displayName" />
    </strong>

    Note that we have typed in the literal word “by” into the XSL. If this form were going to be used in a localized context, you would want to add “by” to the messages bundle and reference it with the sakaifn:getMessage() function, as is done for the words “Created “ and “Modified”.
  11. Click the Apply Transformation Scenario icon transformarrow.png . Your results should look like this:
    CustomRenderer-ViewCustomNoWebServer.png
    Note the presence of the phrase “by User Name” after the “created” key.
  12. If you are using a local web server, change the address to use “ localhost ” and refresh the page. The output should now look like:
    CustomRenderer-ViewFormCustomRenderer.png
    If you are not using a local web server, simply view the source of the file and verify that the <link> tag we added has the href “ /group/PortfolioAdmin/support/testviewcss.css