Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: typos

...

This quick guide is intended to walk you through the process of setting up your first Manakin theme. The first part will take you from the process for creating a blank new theme, configuring that theme, and finally installing it to apply to specific DSpace pages in order to set the stage for further development. The second part will cover some useful debugging and development methods as well as some common "gochasgotchas".

Part 1: Creating a new theme

...

Locate your local themes directory. In DSpace 1.5 it is located at dspace-source/dspace-xmlui/dspace-xmlui-webapp/src/main/webbappwebapp/themes/
If this is a fresh installation, you might have to create the themes directory inside webapp. Create a new directory inside themes and name it after your new theme. Remember the directory name; it will come in useful when configuring the pages that the theme will be applied to.

...

The template is located in the dspace-source/dspace-xmlui/dspace-xmlui-webbappwebapp/src/main/webbappwebapp/themes/ template directory and includes a sitemap configured with the most common settings as well as the instructions on changing them. The template also comes with blank xsl and css files, referenced by the sitemap, to help you get started. Copy the contents of the template directory into your new theme.

...

Before you begin work on CSS or XSL changes, the newly created theme should also be installed. A theme is installed by adding an entry for it in the xmlui.xconf file, found in your DSpace config directory. Locate the <themes> block inside the xmlui.xconf and add an entry to your own theme there. The theme's location is specified by the path attribute while the set of DSpace pages it applies to can be specified in thee three different ways:

  • With regex pattern: <theme name=" Theme's name" regex="community-list" path=" YourThemeDir /"/>
  • Directly with a handle: <theme name=" Theme's name" handle="123456789/42" path=" YourThemeDir /"/>
  • Or both: <theme name=" Theme's name" regex="browse-title^" handle="123456789/42" path=" YourThemeDir /"/>

...

  1. prepending DRI/ to the beginning of the page url but after the context path, i.e. http://<manakin-url>/DRI/search or http://<manakin-url>/DRI/handle/123456789/10
  2. appending the XML parameter to the end of the URL, i.e. http://<manakin-url>/search?XML or http://<manakin-url>/search?query=texas&page=2&XML

The only difference between these two methods is the whether the XML is passed through the Internationalization (i18n) transformer. The first one (using the DRI/debug directive) resolves them to their corresponding string values, while the second method (using the ?XML parameter) returns raw DRI XML with <i18n:text> tags still unprocessed, while the second one resolves them to their corresponding string values. In general, using the DRI/ directive allows for easier navigation though the DRI document, although the ?XML is still useful when access to the raw DRI is needed.

...

Code Block
<map:transform type="IncludePageMeta">
        <map:parameter name="stylesheet.screen#1" value="style.css"/>
        <map:parameter name="stylesheet.screen#3" value="style-ie6.css"/>
        <map:parameter name="stylesheet.screen#2" value="style-ie.css"/>
        ...
    </map:transform>

The syntax of the paramer parameter statement is as follows. The format for a parameter name must follow the form:

...

It is possible to add simple static pages to DSpace using Manakin. This is useful for adding "one-shot" pages like About and FAQs where creating a new aspect would be overkill. There are three ways to add a static page:

1. (Pre broken in 1.8.0) XSL-based method. You can override the main body template and then add a check for the url of the page you want to add. The current page's url is always present in the DRI pageMeta section as request.URI. If the current page url is one you designated for your static page, then instead of rendering the body of the DRI page normally, you can have XSL insert different content. This content can either be placed in the code of the XSL template or imported from an external source using the document() function. This method is useful if the number of extra pages you want to include is relatively small and they are not edited frequently. You can access the page via www.example.com/xmlui/page/about

Code Block
xml
xml
<!-- Overriding the main body template -->
    <xsl:template match="dri:body">
        <div id="ds-body">
            <!-- Check for the custom pages -->
            <xsl:choose>
                <xsl:when test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='request'][@qualifier='URI']='about'">
                    <div>
                        <h1>About us</h1>
                        <p>Lorem Ipsum dolor sit amet</p>
                    </div>
                </xsl:when>
                <xsl:when test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='request'][@qualifier='URI']='faq'">
                    <xsl:copy-of select="document('faq.xml')" />
                </xsl:when>
                <!-- Otherwise use default handling of body -->
                <xsl:otherwise>
                    <xsl:apply-templates />
                </xsl:otherwise>
            </xsl:choose>
        </div>
    </xsl:template>

...

This method also allows your page to have a defined Title and breadcrumbs added via DRI, which one doesn't get by simply adding information to the xsl template (but there probably are ways of doing it directly via xsl).unmigrated-wiki-markup

Create the java file which will add the DRI \
[dspace-src\]/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/artifactbrowser/AboutPage.java

Code Block

/**
 * AboutPage.java
 *
 * Basead on the code by Peter Dietz:
 * https://gist.github.com/842301#file_dspace_add_about.diff (acessed 11-05-23)
 *
 * Modified to work with internationalization (i18n locales) and breadcrumbs
 * by Andre Nito Assada e Josi Perez Alvarez on 11-05-23
 */

package org.dspace.app.xmlui.aspect.artifactbrowser;


import org.apache.log4j.Logger;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.Body;
import org.dspace.app.xmlui.wing.element.Division;
import org.dspace.app.xmlui.wing.element.PageMeta;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.authorize.AuthorizeException;


/**
 * Display about us page.
 *
 * @author Peter Dietz
 */
public class AboutPage extends AbstractDSpaceTransformer
{

/**
 * Internationalization
 * 110523
 */
    public static final Message T_dspace_home =
        message("xmlui.general.dspace_home");
    public static final Message T_title =
        message("xmlui.ArtifactBrowser.AboutPage.title");
    public static final Message T_trail =
        message("xmlui.ArtifactBrowser.AboutPage.trail");
    public static final Message T_head =
        message("xmlui.ArtifactBrowser.AboutPage.head");
    public static final Message T_para =
        message("xmlui.ArtifactBrowser.AboutPage.para");

    private static Logger log = Logger.getLogger(AboutPage.class);

        /**
        * Add a page title and trail links.
        */
        public void addPageMeta(PageMeta pageMeta) throws SAXException, WingException {
            // Set the page title

            // pageMeta.addMetadata("title").addContent("About Us");
            // 110523 modified page title with internationalization and added breadcrumbs
            pageMeta.addMetadata("title").addContent(T_title);
            // add trail
            pageMeta.addTrailLink(contextPath + "/",T_dspace_home);
            pageMeta.addTrail().addContent(T_trail);
        }

        /**
        * Add some basic contents
        */
        public void addBody(Body body) throws SAXException, WingException {
            //Division division = body.addDivision("about-page", "primary");
            //Division.setHead("About Us - Institutional Repository");
            //Division.addPara("We are an institutional repository that specializes in storing your digital artifacts.");

            //110523 modified with internationalization
            Division division = body.addDivision("about-page", "primary");
            division.setHead(T_head);
            division.addPara(T_para);
        }
}

...

Then map it on \
[dspace-src\]/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/BrowseArtifacts/sitemap.xmap
under the tags:

Code Block

<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
    <map:components>
        <map:transformers>

we add:

Code Block

<map:transformer name="AboutPage" src="org.dspace.app.xmlui.aspect.artifactbrowser.AboutPage" />

and under the tags:

Code Block

<map:pipelines>
        <map:pipeline>

We add:

Code Block

<map:match pattern="about">
<map:transform type="AboutPage"/>
<map:serialize type="xml" />
</map:match>

...

_note:_ On Manakin 1.7, this mapping should be done on BrowseArtifacts sitemap, and *not* on ArtifactBrowser sitemap, as it's deprecated in this version. On older versions, one should check which aspect is valid (and therefore which sitemap should be eddited) on the \ [dspace-src\]/config/xmlui.xconfunmigrated-wiki-markup

Now we override the <dri:body> of our theme to fit the calls for this aspect. On the Mirage theme one should edit \ [dspace-src\]/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Mirage/Mirage.xsl
and on the standard theme, one should edit the dri2xhtml.xsl

Code Block

<xsl:template match="dri:body">

<xsl:variable name="meta" select="/dri:document/dri:meta/dri:pageMeta/dri:metadata"/>
<xsl:variable name="pageName" select="$meta[@element='request'][@qualifier='URI']"/>
<xsl:variable name="doc" select="document(concat('pages/', $pageName, '.xhtml'))"/>

        <div id="ds-body">
            <!-- when conditional to handle the call for {dspace-webhost}/about -->
            <xsl:choose>
                <xsl:when test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='request'][@qualifier='URI']='about'">
                    <div>
                        <h1>This is a simple ABOUT page</h1>
                        <xsl:apply-templates />
                    </div>
                </xsl:when>
[ e t c . . . ]

Now one must create a link calling for this page, eg. on the side menus under <xsl:template match="dri:options">

Code Block

<div id="ds-search-option" class="ds-option-set">
                    <a>
                      <xsl:attribute name="href">
                            <!-- 1) catch issothe pegaraapplication's oweb context, in nestethis casocase http://143.107.73.153:8080[MY_HOST]:[MY_WEB_PORT]/xmlui/  -->
                            <xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='contextPath'][not(@qualifier)]"/>
                            <!-- e entao concatenando teremos context/contact 2) concatenates the context path with "/about", resulting in: http://[MY_HOST]:[MY_WEB_PORT]/xmlui/about -->
                            <xsl:text>/about</xsl:text>
                        </xsl:attribute>
                        <!-- e aqui o label descritivo3) the link's i18n label -->
                        <i18n:text>xmlui.dri2xhtml.structural.static.about</i18n:text>
                    </a><br/>

...

To customize the Page Title:

Code Block

<title>
    <xsl:choose>
        <xsl:when test="starts-with($request-uri, 'page/about')">
            <xsl:text>About This Repository</xsl:text>
        </xsl:when>
        ...
</title>

To customize the breadcrumb / trail:

Code Block

<ul id="ds-trail">
    <xsl:choose>
        <xsl:when test="starts-with($request-uri, 'page/about')">
            <xsl:text>About This Repository</xsl:text>
        </xsl:when>
        ...
    </xsl:choose>
</ul>

To customize the body:

Code Block

<xsl:template match="dri:body">
    <div id="ds-body">
    ...
    <xsl:choose>
        <xsl:when test="starts-with($request-uri, 'page/about')">
            <div>
                <h1>About This Repository</h1>
                <p>To add your own content to this page, edit webapps/xmlui/themes/dri2xhtml/structural.xsl and add your own content to the title, trail, and body.
                   ....
                </p>
           </div>
        </xsl:when>
        <xsl:otherwise>
	   <xsl:apply-templates />
	</xsl:otherwise>
    </xsl:choose>
        ...
    </div>
</xsl:template>

...

XSL comments

A very simple gocha gotcha that is bound to get any developer working with XML at least once is the single restriction XML places on its comments. In XML (and therefore XSL) syntax, comments as designated by the pair <!-- comments -->. The character sequence – (dash dash) cannot appear inside the XML comment section and its inclusion will throw an error. Some processors do not explicitly report the exact line where the offending character sequence occurs, instead pointing the developer to the beginning or the end of the entire comment block. In general, if you are getting a malformed XML error somewhere in the comment block, a simple string search for a double dash should fix the problem.

...

One of the more common entities used in HTML is the non-breaking white space, used to offset text and pad empty elements. While it is defined in XHTML as   as (as are about 250 other entities like © ® etc.), the XSL processor will throw an error if those entities are used in the XSL code. The reason for this is that only the following five entities are explicitly defined in XML, mostly because the symbols are part of the syntax structure:

...

In order to insert other symbols into the HTML, use the ISO 8859-1 codes for those entities, i.e. U+00A0 instead of   and U+00A9 instead of ©. A full list of entities and their corresponding codes can be found in section 24 of the W3C Recommendation for HTML4: http://www.w3.org/TR/html401/sgml/entities.html

...

  • <xsl:template match="dri:list">
  • Wiki Markup{{<xsl:template match="dri:list\[1\]" priority="2">}}
  • Wiki Markup{{<xsl:template match="dri:list\[count(child:.*)=0\]" priority="3">}}

and so on to any level of complexity. Furthermore, this relationship is not necessarily symmetrical; in the example above a template that matches only empty lists will only trigger for empty lists, but a template that matches all lists can match all empty lists as well. This creates an ambiguity that must be resolved by the XSL processor. To that end templates are prioritized as follows:

...

Since the question of what constitutes a complex vs. a simple match is processor-specific, the safest way to ensure desired behaviour is through explicit priorities. Thus, for empty lists in our example, all three templates might match a given element, but the one designed to match the specific case wins because it is explicitly given a higher priority. If you look through the templates in the dri2xhtml.xsl file itself, you will notice many templates bearing a priority attribute to disambigute disambiguate cases where their match sets intersect.

A problem may arise, however, when these templates are imported into another stylesheet, as is the case in all themes overriding templates from the dri2xhtml base library. Because templates belonging to the importing stylesheet have higher priority than those that are being imported (which is what allows the original templates to be overridden in the first place), this can produce unintended consequences when overriding only the simple and low-priority templates. Using our example above, we cannot just override the template than matches all lists if we also wish to preserve the original behaviorbehaviour, because it will always override the more specific ones simply by the virtue of having higher import priority. For this reason, when overriding simple templates for a particular element, always make sure that the templates dealing with the more esoteric conditions for that element are imported as well, even if you do not intend to change them.

The last thing to point out here is the use of the "mode" attribute on templates. These are used to differentiate templates that apply to the exact same elements, usually to process the same element under different conditions. In order to match, a template's mode must correspond to the mode of the template call, so a call of the form <xsl:apply-template select="dri:list" mode="nested"/> will only match templates that have the same mode attribute, i.e. <xsl:template match="dri:list" mode="nested">. This pairing overrides all other templates, regardless of priority and import precedence, so it is generally advisable to preserve the modes in imported templates. If the modes are kept consisentconsistent, however, those templates are subject to the same disambiguation rules as templates with modes.

...