Next Previous navigation in news article for umbraco - xslt

This is driving me a little crazy (been trying to do this for quite some time)
I'm trying to get some xpath code working that will display next and previous links, which will take you to the next newsItem and once it gets to newsItem4, then the next button disappears.
<newsArea>
<newsItem1></newsItem1> <----- currentPage
<newsItem2></newsItem2>
<newsItem3></newsItem3>
<newsItem4></newsItem4>
</newsArea>
I can list al the newsItems whilst on a news item with
<xsl:for-each select="$currentPage/../*">
<h2><xsl:value-of select="#nodeName"/></h2>
</xsl:for-each>
and i can count how many items i have
<xsl:value-of select="count($currentPage/../*)-1"/>
but i dont know how to move to the next news item, or how to tell it when to stop showing the next node when it comes to the end of the newsItems (one example just jummped to another leve)
Any help would be really really appreciated.
Thanks
Tim

Take a look at the paging sample from this blog post: http://www.nibble.be/?p=11
That should give you an idea of how it works. You could always set your page size to 1.
Also, there is a package based on that method: http://our.umbraco.org/projects/developer-tools/paging-xslt
That should get you on the right path.

You could easily create a "Page Navigation" macro to add to the bottom of any template you want it, XSLT would be as follows:
<xsl:template match="/">
<!-- if there's a previous page -->
<xsl:if test="$currentPage/preceding-sibling::*[1]">
< Prev
</xsl:if>
<!-- if there's next and previous, show divider -->
<xsl:if test="$currentPage/preceding-sibling::*[1] and $currentPage/following-sibling::*[1]">
<xsl:text> | </xsl:text>
</xsl:if>
<!-- if there's a next page -->
<xsl:if test="$currentPage/following-sibling::*[1]">
Next >
</xsl:if>
</xsl:template>

Related

get first element whose preceding

I've the below sample xml tree.
-root
-para
-page
-footnum
-para
-footnum
-para
-footnum
-para
-page
-footnum
I want to apply templates on the first footnum whose preceding is page. From inside the footnum template. here below para there will be even more nodesbut here i want to apply-template only to the first footnum followed by page,, whether it is in same para or different.
The code i tried is as below.
<xsl:template match="footnote" mode="footnote">
<xsl:variable name="rt">
<xsl:value-of select="//page/#num/following::footnote[1]/#num"/>
</xsl:variable>
<xsl:value-of select="$rt"/>
<xsl:if test="contains($rt,#num)">
<xsl:variable name="op"><</xsl:variable>
<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="cl">></xsl:variable>
<xsl:value-of select="concat($op,'?pb label=',$apos,./#num,$apos,'?',$cl)"/>
</xsl:if>
<div class="tr_footnote">
<div class="footnote">
<sup>
<a>
<xsl:attribute name="name"><xsl:text>ftn.</xsl:text><xsl:value-of select="#num"/></xsl:attribute>
<xsl:attribute name="href"><xsl:text>#f</xsl:text><xsl:value-of select="#num"/></xsl:attribute>
<xsl:attribute name="class"><xsl:text>tr_ftn</xsl:text></xsl:attribute>
<xsl:value-of select="#num"/>
</a>
</sup>
<xsl:apply-templates/>
</div>
</div>
</xsl:template>
Update:
here when i'm running this template, it is giving me before which footnotes the number is to be placed, but here i'm getting the footnote number, but not the pagenumber. please let me know how i can retrieve the page number.
here it is applying templates for all the footnums. please let me know where am i going wrong.
Thanks
You are already in the footnote context. To get the first preceding page node, you must use
<xsl:variable name="rt" select="preceding-sibling::*[1][local-name()='page']/#num"/>
If (as I think you are saying) you want to call apply-templates to the first footnum with a preceding page element, then your first problem is that the apply-templates instruction in your sample code applies to the page element, not to the footnum element.
Your second problem (whether the error is in your code or in your problem description) is that you say you wish to do this work only in some cases (it's not clear to me what conditions you have in mind -- one footnum per document, or once per page element on the first footnum following that page element, or something else), but you don't seem to have any test in your code that tests for the condition you have in mind. The test in your conditional is preceding::page[1], which is synonymous (as a Boolean) with preceding::page, and which excludes all those footnum elements which appear before any page element in the document, and includes all the others.
Assuming that your page elements mark page breaks, and your footnum elements mark footnote numbers, and what you want is to do something special for the first footnote (if any) on each page [if that's not right, you'll have to make the appropriate adjustments to the solution], then you need to find an XPath expression that returns true for the first footnote on each page, and not for the others.
What is the crucial characteristic here of the first footnum on each page? That there is no other footnum element between it and the immediately preceding page. So we could write (not tested):
<xsl:variable name="mypage" as="element(page)?"
select="preceding::page[1]"/>
<xsl:variable name="preceding-footnum-on-same-page"
as="element(footnum)?"
select="preceding::footnum[preceding::page[. is $mypage]]"/>
<xsl:if test="$mypage and not($preceding-footnum-on-same-page)">
... do your stuff here ...
</xsl:if>
Another way to formulate it is: the current node is the first footnum on the current page if, when we find the current page and then find its first footnum, it's the current node.
<xsl:if test=". is ./preceding::page[1]/following::footnum[1]">
...
</xsl:if>
I hope this helps.

Sitecore rendering: searching of first item by condition using fields

I have few items with parent/children dependencies:
Item1 -> Item2 -> Item3
They have fields with the same name: "Main Info". Some of them have this field filled, some of them with empty "Main Info". Main goal: if page with filled "Main Info" selected - show this info. If page with empty "Main Info" selected - show info from ancestor.
So i have rendering:
<xsl:variable name="home" select="$sc_currentitem/ancestor-or-self::*[contains(#template, 'page') and #Main Info != '']" />
<!-- entry point -->
<xsl:template match="*">
<xsl:apply-templates select="$home" mode="main"/>
</xsl:template>
<xsl:template match="*" mode="main">
<sc:text field="Right Footer Text" />
</xsl:template>
This shows nothing.
<xsl:variable name="home" select="$sc_currentitem/ancestor-or-self::*[contains(#template, 'page')]" />
<xsl:template match="*">
<xsl:apply-templates select="$home" mode="main"/>
</xsl:template>
<xsl:template match="*" mode="main">
<sc:text field="Right Footer Text" />
</xsl:template>
This shows "Main Info" from every ancestor of selected item.
How can i get only one "Main Info"? From selected item if this field isn't empty or from first parent item with "Main Info" filled.
I really believe this demonstrates why you should be looking at writing your components in C# as opposed to wasting time trying to "hack" a solution in via XSLT. Sure, you can write your own extension if you like - but let's consider how little code this would be to begin with.
On your .ASCX file, you would have this:
<sc:Text runat="server" ID="sctMainInfo" Field="main info" />
And in your .cs codebehind/codebeside:
Sitecore.Data.Item myItem = Sitecore.Context.Item; // Should be your Datasource item
while (string.IsNullOrWhiteSpace(myItem["main info"]))
{
myItem = myItem.Parent; // you need to add a check here,
// so you don't move up past your Site Root node
}
sctMainInfo.Item = myItem;
By far simpler than a combined XSLT/XSL Helper approach, and performance will be a lot better.
One last thing. The very premise of your rendering has a problem. You shouldn't really be crawling through the item hierarchy to find content for your component, you prevent any possibilities for performing M/V testing or personalizing the component. This is a story for a different day however.
Performance-wise you might not want to use the ancestor-or-self selector. If you have a lot of items and a deep tree its bad for performance.
I think I'd either create an <xsl:choose> like so:
<xsl:choose>
<xsl:when test="sc:fld('main info',.)!=''">
<sc:text field="main info" select="." /> <!-- Display main info from item -->
</xsl:when>
<xsl:otherwise>
<sc:text field="main info" select=".." /> <!-- Display main info from parent -->
</xsl:otherwise>
</xsl:choose>
Of course, if there's a possibility that it's not the parent but the parents parent (and so forth) that has the main info I'd make it simpler by creating my own XSL Extension.
You can read more on XSL Extensions on this article by Jens Mikkelsen.

Display images from tree list in Sitecore

In Sitecore, I have a tree list for the user to select certain images. I would like to use the presentation api to display the images that the user selects. While looking through the Presentation Component XSL reference guide, I found this code:
<xsl:variable name="slideShow" select="/*/item[#key='content']/item[#key='home']/item[#key='Foundation']/item[#key='Landing Pages']/item[#key='Legends Trail Ride']" />
<xsl:variable name="mediaid" select="sc:fld('Slide Show',$slideShow,'mediaid')" />
<xsl:if test="$mediaid">
<xsl:variable name="mediaitem" select="sc:item($mediaid,$slideShow)" />
<xsl:if test="$mediaitem">
<a href="{concat('/',sc:GetMediaUrl ($mediaitem))}">
<xsl:choose>
<xsl:when test="sc:fld ('title',$mediaitem)">
<sc:text field="title" select="$mediaitem" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$mediaitem/#name" />
</xsl:otherwise>
</xsl:choose>
</a>
</xsl:if>
</xsl:if>
The page will display so technically there isn't anything wrong with the code but the image still aren't showing. Is this code going in the right direction or is there an alternative way to display images from a tree list?
If your site is using the 'web' database, make sure you have published all of your media items or they won't display.
A typical scenario for your case would be to check if all templates and subtemplates of the specific items on which those images are attached are published. If this is done check your media library folders and media items in those folders. You have to make sure the folder in which you added the images is also published. What you can do to verify the above after you have published is login to the 'desktop' mode of Sitecore and change the database (bottom right corner) to 'web'. Then find all of the described items and see if everything is really published. Most of the times you will encounter issues like this it will actually be publishing.

Umbraco XSLT select newsitem sub nodes regardless of currentpage

I need to say; I'm pretty green in xslt so, most likely, that's the main problem; nonetheless been on it for hours and can't get it.
I want to fill a column on my main template with the 5 most recent newsitems. These newsitems should be shown regardless of the currentpage.
I've tried this:
<xsl:template match="/">
<xsl:for-each select="umbraco.library:GetXmlNodeById(1075)/child::node">
<p>
<strong>
<xsl:value-of select="header"/>
</strong>
</p>
</xsl:for-each>
</xsl:template>
Where, at the moment, 1075 is my News template. Ive tried it with just: GetXmlNodeById(1076)/node (where 1076) is my NewsItem template. I've tried it with the node-Id's from the content-tree, but no luck..
Anyone able to help me out here? Am stuck and I've searched high and low on Google, the forums and documentation, but I'm most likely missing something vital here. TIA!
P.S. Using Umbraco 4.5 BTW
This should output current and child nodes.
<xsl:copy-of select="umbraco.library:GetXmlNodeById(1075)"/>
In Umbraco 4.5 the schema has changed, from /node[#nodeTypeAlias='News'] to /News [#isDoc]
http://blog.leekelleher.com/2010/04/02/working-with-xslt-using-new-xml-schema-in-umbraco-4-1/
So your xslt should look like
<xsl:template match="/">
<ul>
<xsl:for-each select="umbraco.library:GetXmlNodeById(1075)/News [#isDoc]">
<li><xsl:value-of select="#nodeName"/></li>
</xsl:for-each>
</ul>
</xsl:template>

XSLT: pass value from one for-each match to the next

I'm using the following to match all <section>s with a revision attribute set. <section>can appear at many different levels of the document tree, always contained within <chapter>s.
<xsl:for-each select="//section[#revision]">
<!-- Do one thing if this is the first section
matched in this chapter -->
<!-- Do something else if this section is in the same
chapter as the last section matched -->
</xsl:for-each>
As the comments say, I need to make each for-each iteration aware of the chapter to which the previous matched section belonged. I know that <xsl:variable>s are actually static once set, and that <xsl:param> only applies to calling templates.
This being Docbook, I can retreive a section's chapter number with:
<xsl:apply-templates select="ancestor::chapter[1]" mode="label.markup" />
but I think it can be done with purely XPath.
Any ideas? Thanks!
Not sure if I unterstood your requirements 100%, but…
<xsl:variable name="sections" select="//section[#revision]" />
<xsl:for-each select="$sections">
<xsl:variable name="ThisPos" select="position()" />
<xsl:variable name="PrevMatchedSection" select="$sections[$ThisPos - 1]" />
<xsl:choose>
<xsl:when test="
not($PrevMatchedSection)
or
generate-id($PrevMatchedSection/ancestor::chapter[1])
!=
generate-id(ancestor::chapter[1])
">
<!-- Do one thing if this is the first section
matched in this chapter -->
</xsl:when>
<xsl:otherwise>
<!-- Do something else if this section is in the same
chapter as the last section matched -->
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
However, I suspect this whole thing can be solved more elegantly with a <xsl:template> / <xsl:apply-templates> approach. But without seeing your input and expected output this is hard to say.
position() will return your position within the current for-each iteration. The first iteration, IIRC, will return 0, so testing for "position()=0" will tell you if you are in the first iteration.