‘Manakin’ Archive

17 Septembris 2008

And it was good

Earlier this week, the godly sysadmin got the last of his major hacks into 1.5, and got our test installation up and running thereupon.

Yesterday I got down to brass tacks installing my themes, which promptly broke because the Manakin devs fixed their misspelling of “standardAttributes.” (I’m not pointing and laughing. Really I’m not. These things happen.) That was a simple enough fix, as were a couple of messages.xml fixes.

And today I hacked at the bad stuff. My scoped search box was amazingly unbelievably broken, but I got it fixed after a lot of unnecessary metaprogramming and a similar amount of very necessary cussing. (If the fit comes upon you to program Javascript inside XSLT? For your own sanity, I urge you to resist it.)

The other thing that broke badly was my big logo hack. The problem was that Manakin doesn’t put METS metadata inside the DRI any more; it’s all called by reference. Since the logo URL lives in METS, I had to figure out how to make XSLT call the right METS file and return the URL from it. Once I had that sorted, the $context-path variable confused me rather, but Tim Donohue kindly got me straightened out and flying right, and so the logos are now fixed as well.

At this point, I have some minor XSLT and CSS tweaks to do before I’m willing to set 1.5 free, but I think I can tear through them in a day or two (although considering the number of meetings I’ve got for the next three workdays, it may take longer than that). If I get through those, I can start wading through the wishlist. Drop-dead rollout date is Open Access Day, and I’m fairly confident we’ll make that.

And it was a good day.

13 Martii 2008

Search scope in consortial repositories

If you run a consortial repository, one of the things Manakin brings you is the possibility of separating each institution in your repository from the others visually, such that each institution practically seems to have its own site!

Manakin is actually pretty careful about the URL design of its scoped browsing. If you start browsing inside a particular community or collection, you’ll still see that community or collection’s design (as opposed to the default), because the URL hangs onto the handle, which is what the theme chooser uses to decide which theme to display. Very smart!

Scoped searching, however, is a different and rather nastier problem. Out of the box, Manakin’s search box is designed to allow the user to choose between two types of search: the entire repository, and the currently-browsed community or collection. This is a problem for consortial repositories who want their institution-level communities to seem wholly independent of each other. There shouldn’t be any all-of-DSpace search available from a community’s page. The “all of DSpace” scope should be replaced by an “all of the institution’s community” scope.

(I initially thought there shouldn’t be any broad-scope search at all. This was completely wrongheaded of me. If you’re in a departmental collection, you should be able to search the entire institution’s collections. I mention this so that you won’t make the same mistake.)

At present, I have solved about half this problem. The half I can’t solve is the search-results page, which uses the site-default theme no matter what I do, and cannot be made to respect the scoping established on the search page. I am annoyed by this, but I’m pretty sure that solving it is beyond my abilities. (What it would take, I suspect, is sticking information about the referring page and its theme into the DRI. Somebody want to write an Aspect to do that?)

However, I have solved the search-box scoping problem. It’s a start. Here’s how you can too.

First, you need to know when you’re on the main community page. For this, you need to record that page’s handle in the theme’s XSLT. This got slightly hairy for me because my test and production servers have different handle prefixes. If yours don’t, your solution is easier than mine. Anyway, here’s mine (and yes, I’m giving away the farm here a bit, revealing which community I’m doing this for, but I don’t see that that’s a problem):

<xsl:variable name="handle-prefix" select="substring-after(/dri:document/dri:meta/dri:repositoryMeta/dri:repository/@repositoryIdentifier, 'hdl:')"/>
<xsl:variable name="uwmad-handle">
    <xsl:choose>
        <xsl:when test="$handle-prefix='1960'">1960/10498</xsl:when>
        <xsl:when test="$handle-prefix='1793'">1793/8334</xsl:when>
    </xsl:choose>
</xsl:variable>

Now you need to mess with the radio buttons in the search form. On your community’s main page, you’ll replace them with a hidden input containing that community’s handle as scope. Everywhere else, you’ll sneakily change the “everything” scope to search just your community. Take a deep breath — a lot of code here:

<xsl:choose>
    <!-- when we're on the UW-Madison home page, don't offer a choice of scope -DS -->
    <xsl:when
        test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container']=concat(’hdl:’,$uwmad-handle)”>
        <input id=”ds-search-form-scope-container” name=”scope” type=”hidden”>
            <xsl:attribute name=”value”>
                <xsl:value-of select=”$uwmad-handle”/>
            </xsl:attribute>
        </input>
    </xsl:when>
    <xsl:otherwise>
        <label>
            <!– edited so that a scope of “all” ONLY searches UW-Madison stuff –>
            <input id=”ds-search-form-scope-all” type=”radio” name=”scope”
                checked=”checked”>
                <xsl:attribute name=”value”>
                    <xsl:value-of select=”$uwmad-handle”/>
                </xsl:attribute>
            </input>
            <i18n:text>All of MINDS@UW-Madison</i18n:text>
        </label>
        <br/>
        <label>
            <input id=”ds-search-form-scope-container” type=”radio” name=”scope”>
                <xsl:attribute name=”value”>
                    <xsl:value-of
                        select=”substring-after(/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container'],’:')”
                    />
                </xsl:attribute>
            </input>
            <xsl:choose>
                <xsl:when
                    test=”/dri:document/dri:meta/dri:objectMeta/dri:object[@objectIdentifier=/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container']]/mets:METS/mets:structMap[@TYPE='LOGICAL']/mets:div[@TYPE='DSpace Collection']”
                    >This Collection</xsl:when>
                <xsl:when
                    test=”/dri:document/dri:meta/dri:objectMeta/dri:object[@objectIdentifier=/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container']]/mets:METS/mets:structMap[@TYPE='LOGICAL']/mets:div[@TYPE='DSpace Community']”
                    >This Community</xsl:when>
            </xsl:choose>
        </label>
    </xsl:otherwise>
</xsl:choose>

As best I can tell, this works quietly and without fuss. Best kind of hack!

5 Februarii 2008

Argh, Manakin, don’t do that!

Manakin has one seriously broken behavior that I can’t figure out how to fix, but there’s a workaround that I recommend to everyone.

If you try to click on a link to a page that needs you to be logged in, Manakin duly asks you to log in and then shoots you over to your page. Fine. If, however, you click a login link from an open page, once you’re logged in, Manakin returns you to the root (main) page of your repository.

Let me count the ways in which this is broken:

  1. It doesn’t clearly inform you that you’ve logged in properly. When I first ran into this, I wondered if I had!
  2. If you came from a page with a different theme (visual design) from the main repository page, welcome to total confusion!
  3. It doesn’t take you to a page that does anything useful with your logged-in status. If you’re coming from an open page, you probably logged in to deposit an item or handle something in your workflow. To do this from the main page, you’re stuck clicking at least once, and probably twice!
  4. It’s not what the JSP UI does. The JSP UI sensibly sends you to your profile (”My DSpace”) page. Switching to Manakin and not fixing this behavior will confuse every single existing user of your repository. (How did TAMU not find this out on user testing? Didn’t they test? Or do they not have any existing JSP UI users?)

My recommendation is never to link to Manakin’s login page in a theme. Instead, link to Manakin’s profile page (”/profile” instead of “/login”). You can still label it “Log in” if you like. This way, Manakin will say “oops! can’t go to your profile page if you’re not logged in!” It will then log you in and send you to your profile page. Which is correct, not-confusing behavior.

Edited to add: To make this happen by default, go to Navigation.java in the EPerson aspect of Manakin. Find “/login” and change it to “/profile”. Install and rebuild. You’re done.

17 Ianuarii 2008

Theming different parts and pages in Manakin

I’m sure everyone else figured this out already and I’m the only one who didn’t, but just in case someone else is as slow on the uptake as I am…

You set which pages get which theme in Manakin via [dspace]/config/xmlui.xconf. Each theme gets a theme element with its name, the path to it, and… a selection regex! REGEX! Pattern-matching!

This means you can set up a theme just to hit certain pages or sections of the site, as long as they have a distinctive, non-handle-based URL. Want a theme just for the admin section? Easy-peasy. Do regex=".*/admin/.*". How cool is that?

Unfortunately, this coolness breaks down with regard to distinctive community and collection pages, because those have handles and so can’t be caught via regex, not to mention that Manakin is set up to cascade a theme down to item pages. This is irksome, because after all, community and collection pages are (after a fashion) home pages, and as such may well want to look or behave a bit differently from item or browse pages. To some extent, Manakin caters to this; the innermost content on a community/collection page is in its own template.

However, if you want to customize the header or the navbar or anything on a community or collection page, you’re sunk—except you’re not, because I figured this one out for you. At the top of your theme, add these variable definitions:

<xsl:variable name="is_comm" select="boolean(/dri:document/dri:body/dri:div[@n='community-home'])”/>
<xsl:variable name=”is_coll” select=”boolean(/dri:document/dri:body/dri:div[@n='collection-home'])”/>
<xsl:variable name=”is_item” select=”boolean(/dri:document/dri:body/dri:div[@n='item-view'])”/>

With these, you can do conditional logic anywhere in the stylesheet you need to. E.g. <xsl:if test="$is_comm">. It just works!

Now if I only understood what themes.xmap does and whether I should actually care…

15 Ianuarii 2008

Redoing navigation in Manakin

One of the commoner tasks involved in redesigning DSpace is reorganization of or additions to the navigation bar. Manakin does not make this simple, but there are ways to do an end-run around it.

The essential problem is that the elements of the navigation bar are not set at the theme level in XSLT, but at the Aspect level, in Java. (DSpace has always suffered from the arrogant notion that it knows interaction design better than you do. Often it is wrong, but the bad interactions are hard-coded in so deep it’s next to impossible to jettison them.)

If you choose, you can go into aspects/ArtifactBrowser/src/org/dspace/app/xmlui/artifactbrowser/Navigation.java and mess around in some rather inscrutable code to make changes that affect the entire Manakin installation. I admit to having done this to get rid of DSpace’s completely pointless browse-by-date function. However, I do not recommend this if adding links is what you need to do, and I triply do not recommend it for theme-specific navigation links.

I have now tested my sitemap.xmap hack, and I am pleased to say that it works exactly as I expected it would. For the situation where you want the normal Manakin sidebar, but you also want a few theme-specific additions, it is a decent way to go. After I threw another temper tantrum on the dspace-tech list, we can eventually expect a better way to inject content into Manakin DRI files. Until then, though, hacking sitemap.xmap works.

If you want to rearrange content in the navigation bar, beyond simply changing wording or adding a few links to the end, you have some work ahead of you. This is because the content and order of the sidebar is not set on the theme level; it’s hardcoded into the Java Aspect gizmo. (Is this stupid? Yes, this is stupid. These kind of interaction-design decisions do not belong in Java; they belong with the designers who are not supposed to be using Java. Eventually, however, I think it will be possible to move Manakin in a more productive direction.)

It is possible to work around this. The easy way to do it is to go into the dri:options template and rip out the <xsl:apply-templates> call, replacing it with hard-coded links. I think this is fully justifiable, though it’s rather annoying that (unless you set up theme inheritance somehow) you have to do it for every theme you write.

(Note also that doing it this way makes possible a rather interesting trick: you could actually make a DSpace community or collection a seamless part of Somebody Else’s Website. Grab up their site design and navigation bar to theme the community/collection with, then add a link on both sites that goes directly to the community/collection, and there you are. Nice trick, isn’t it? I really want to try it.)

The hard way to work around Manakin’s hard-coded navigation is to replace the <xsl:apply-templates> call with markup that pulls the appropriate links out of the DRI. What’s really hard about this is that without the <xsl:apply-templates> call, you’ll have to go through and figure out the logged-in-user and administrative linksets as well. I haven’t been quite daring enough to do this yet, but somebody ought to.

Because navigation is too important a part of interaction design to be left to a bunch of developers, yeah? (Sorry. Been rereading Alan Cooper.)

28 Decembris 2007

Kludging Manakin: IncludePageMeta

So I’m about to start wrangling my new DSpace/Manakin theme into shape in Internet Explorer, as you might have gathered from yesterday’s howl of anguish, and it occurred to me to wonder how to alter the stylesheet setup in Manakin to take note of more versions of IE. (Out of the box, it understands “IE” and “IE6.” I am wondering about IE5. Anything previous to that can jump off a cliff and die horribly.)

What I found was actually a limited but relatively simple way to add static information into a Manakin theme without mucking around in Java and whatnot. Note well, it’s a big fat ugly nasty kludge—but it’ll work, and future versions are highly unlikely to break it.

Open up a sitemap.xmap file. Look for the “Step 2″ comment, which introduces some map:transforms based on browser type. That’s your loophole, right there; the information there is going straight into the DRI, in /document/meta/pageMeta/metadata elements. (I’ve left out the namespaces, but you can’t in your XSLT. All the above are in the DRI namespace.)

So let’s take a closer look. The metadata elements in the DRI are structured more or less like good old familiar Dublin Core. There’s an element attribute and a qualifier attribute, and the value is there as the element’s content, so:

<metadata element="stylesheet" qualifier="screen">style.css</metadata>

How does the sitemap.xmap file make that happen in the DRI? Thusly:

<map:parameter name="stylesheet.screen" value="style.css"/>

See? Simple. But as I said, limited—this isn’t where you’re going to be able to put your entire static Help pages or FAQ. But you could, for example, introduce a new navigation bar or the like without having to hack the living hell out of Navigation.java in the ArtifactBrowser Aspect (which is frankly what I did, though it’s a lousy idea because that Aspect governs the entire system, not just one theme, so I’ll probably be replacing that hack with something based on this).

Now, if you’ve been paying close attention to that sitemap.xmap file, you’ll have noticed that all the code I’ve been referring to is inside some conditional stuff (map:select and map:when). I must say I haven’t tried this yet, but I think the way to just plain old add some stuff is to go outside the map:select element altogether and do something like this:

<map:transform type="IncludePageMeta">
  <map:parameter name="newElement.newQualifier" value="newValue"/>
</map:transform>

It should Just Work, showing up in your DRI where you can grab it via XSLT for whatever nefarious purpose you have in mind.

Kludge at your own risk, as always… but as kludges go, I think this one’s fairly safe and harmless.

20 Decembris 2007

Moving community and collection logos

I don’t want to admit how long it took me to get this right. Weeks. A small glitch elsewhere in the stylesheet that would occasionally throw a wobbly and occasionally not did not help matters. (Have I mentioned that debugging XSLT server-side is an inordinate pain in the posterior? I haven’t? Well, it is.)

Still. If you hate as much as I do that community and collection logos live inside the community/collection box and not in the h1 of the page the way $DEITY intended, read on.

I actually had to comment out the ds-logo-wrapper bit in DS-METS-1.0-DIM.xsl, because nothing I did in my theme seemed to override it. The other sneaky way to dispense with it is to set it to display:none in your CSS.

For our first trick, we will fossick around in the METS and the DRI to determine whether there’s a logo at all, and whether we’re actually on a community or collection page. Add the following variables to the top level of your theme’s stylesheet (look for the context-path variable and put them beside those):

<!-- Whether the current page has a logo associated with it. -->
    <xsl:variable name="has_logo" select="boolean(/dri:document/dri:meta/dri:objectMeta/dri:object/mets:METS/mets:fileSec/mets:fileGrp[@USE='LOGO'])”/>

<!–  Whether the current page is a community or collection home page. –>
     <xsl:variable name=”is_comm” select=”boolean(/dri:document/dri:body/dri:div[@n='community-home'])”/>
    <xsl:variable name=”is_coll” select=”boolean(/dri:document/dri:body/dri:div[@n='collection-home'])”/>

Next, we will go into the template where we want the logo to live and add this to it:

<xsl:if test="$is_coll or $is_comm">
  <img>
    <xsl:attribute name="src">
      <xsl:value-of select="/dri:document/dri:meta/dri:objectMeta/dri:object/mets:METS/mets:fileSec/mets:fileGrp[@USE='LOGO']/mets:file/mets:FLocat[@LOCTYPE='URL']/@xlink:href”/>
    </xsl:attribute>
    <xsl:attribute name=”class”>logo</xsl:attribute>
    <xsl:attribute name=”id”>commcollogo</xsl:attribute>
    <xsl:choose>
      <xsl:when test=”$is_comm”>
        <xsl:attribute name=”alt”>xmlui.dri2xhtml.METS-1.0.community-logo-alt</xsl:attribute>
        <xsl:attribute name=”attr” namespace=”http://apache.org/cocoon/i18n/2.1″>alt</xsl:attribute>
      </xsl:when>
      <xsl:when test=”$is_coll”>
        <xsl:attribute name=”alt”>xmlui.dri2xhtml.METS-1.0.collection-logo-alt</xsl:attribute>
        <xsl:attribute name=”attr” namespace=”http://apache.org/cocoon/i18n/2.1″>alt</xsl:attribute>
      </xsl:when>
    </xsl:choose>
  </img>
</xsl:if>

There is an additional wrinkle if (as I did) you want the logo to live in the ds-div-head with the community’s name in it. For this, you need to test whether a given head on the page is an h1, or you’ll get the damn logo on every head on the page. (Yep. I made that mistake.)

The fix is relatively easy; just change the xsl:if line above to <xsl:if test="$head_count=1 and ($is_coll or $is_comm)"> and you’re golden.

I hope somebody else uses this. Figuring it out drove me crazy for weeks.

30 Novembris 2007

Distinctive “current” navigation links

One of the (sadly few) nice things that DSpace’s JSP interface did was call out the link for the page you happened to be on in the navigation sidebar. The magic was a class attribute on the current page’s link, plus a bit of CSS.

Manakin doesn’t do that out of the box. But it can, and I just spent entirely too much time making it do so. Y’all get the benefit of my cussing streak.

The first trick is to figure out just what the address of the current page is. Go up to the top level of your theme’s XSLT stylesheet and add this:

<xsl:variable name="currentpage">
  <xsl:value-of select="$context-path"/>
  <xsl:text>/</xsl:text>
  <xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='request' and @qualifier='URI']“/>
</xsl:variable>

(Incidentally, could somebody with more XSLT-fu than I have kindly explain what the difference is between dri:metadata[@element='request' and @qualifier='URI'] and dri:metadata[@element='request'][@qualifier='URI']? I know there is one, because it keeps tripping me up.)

Now you need your <dri:xref> transformation to take notice. Here’s how it works:

<xsl:template match="dri:xref">
  <a>
    <xsl:attribute name="href"><xsl:value-of select="@target"/></xsl:attribute>
      <xsl:if test="($currentpage)=(@target)">
        <xsl:attribute name="class">
          <xsl:text>current</xsl:text>
        </xsl:attribute>
      </xsl:if>
    <xsl:apply-templates />
  </a>
</xsl:template>

And then you may style at will.

This only works for side navbar links. It doesn’t currently work for the alphabet links at the top of browse-by pages, because they’ve got parameters attached. (If I recall correctly, there may be some URL-space rearrangements in current Manakin versions that might fix this.) Happy designing!

Clickable authors and subjects in Manakin

The default Manakin install, just so you know, doesn’t put subject terms on the short item-display page. It’s not hard to add them back, and I recommend it; you’ll see what I did with them in a moment.

Making authors and subjects clickable is a bit trickier. Up-front warning: what I’m about to show you is apparently not in line with the latest version of Manakin, but if you get the idea, making the necessary fixes won’t be hard.

The first problem is that the names need to be URL-encoded or browsers will break amusingly. This leads to the second problem, which is that XSLT 1 doesn’t have a built-in URL encoder. Fortunately, Cocoon does, and you can enable it for your Manakin themes. In your main sitemap.xmap file, add the following just below the root <sitemap:xmap> element:

<map:components>
  <map:transformers>
       <map:transformer name="encodeURL"
src="org.apache.cocoon.transformation.EncodeURLTransformer"/>
  </map:transformers>
</map:components>

Then, between Steps 4 and 5 of the <map:pipeline>, add:

<map:transform type="encodeURL"/>

URL encoding problem solved. (Note: if you mouse over links with this working, they don’t look encoded—that’s okay, everything still works.)

Now you need to go into your theme’s XSLT stylesheet and look for the <xsl:template> with the name “itemSummaryView_DS-METS-1.0-DIM”. If it’s not there, go into DS-METS-1.0-QDC.xsl, find it there, and copy it into your theme’s stylesheet.

After breaking things amusingly several times, I found out what works. Note carefully that I am not using Manakin-default table markup for metadata, because I despise table markup. I’m using definition lists instead, and I’ve made them look like tables with CSS. (Hell, my metadata display is prettier than WorldCat’s. Right-justify your labels, people! It helps the eye.)

<xsl:if test="$data/dim:field[@element='subject']“>
<dt><xsl:text>Subject(s):</xsl:text></dt>
<dd>
  <xsl:for-each select=”$data/dim:field[@element='subject']“>
    <a>
      <xsl:attribute name=”href”>
        <xsl:value-of select=”concat($context-path,’/browse-subjects?subject=’)”/>
        <xsl:copy-of select=”text()”/>
      </xsl:attribute>
      <xsl:copy-of select=”text()”/>
    </a>
    <xsl:if test=”count(following-sibling::dim:field[@element='subject']) != 0″>
<xsl:text>; </xsl:text>
        </xsl:if>
  </xsl:for-each>
</dd>
</xsl:if>

Taking that a bit at a time… frankly, you should wrap all your metadata declarations in <xsl:if> statements as I just did, because otherwise they will show up in Manakin whether they actually have values or not! This is just silly.

I put the bare text “Subject(s)” in the code instead of doing something in messages.xml for it. This is bad, it will be fixed, and you should not do it. Use messages.xml instead.

The rest works out to “for each subject, put a link to the corresponding browse-by-subject page, and add a semicolon and space if it’s not the last subject in the list.” It doesn’t take a whole lot of XSLT-fu to see how it works.

This works just as nicely for authors, and I’ve got that enabled too. (I’ve also split out real authors from advisors, translators, editors, etc. in the code. This took a little doing, and may be worth a separate post.) You can do it too—have fun!

29 Octobris 2007

The daily stupid

My stupid, for once. I broke Manakin by creating a false XSLT analogy: because there is a last() function, I assumed there had to be a first() function.

Nope. position()=1 is what I wanted, and if I’d been thinking I would have guessed as much.

For the record, Manakin kicks back a really weird error when something breaks in a theme’s XSLT; it pretends that it can’t find a “transaction handler” for the theme. Now I know.