Using translation strings in componentlinks - tridion

I've been trying to solve this problem since this morning, and I know I'm missing something obvious here but I can't seem to find it.
We are using an XML file that is published to the server which contains translations of all the standard words, such as 'read more'. It is a page with a component that is localized in the appropriate publication.
In our Razor templates we use the following code below a plain news Summary item which in turn links to the full item.
<a tridion:href="#news.ID" class="more" ><%=DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more")%></a>
Thing is, the server tag works just fine, but gets resolved as
<tridion:ComponentLink runat="server" PageURI="tcm:15-407-64" ComponentURI="tcm:15-1475" TemplateURI="tcm:0-0-0" AddAnchor="false" LinkText="<%= DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more") %>" LinkAttributes=" class="more"" TextOnFail="true"/>
As you might notice, it gets written as plain text on the page (no surprise there because the LinkText parameter is declared as String in the first place according to the liveDocs).
If I take away the
tridion:href
in the first example, and write it as
href
It works fine, the code resolves into a translated string and it's even linked... to nothing more than the TCM ID of the component, not the right page with the full news item on it.
I've tried creating a function in Razor, tried replacing the linkText, tried setting the ComponentLink in the template itself, but to no avail. I feel that it should work with just a minor adjustment to this template's code, but I fail to see it and I've started looking at custom TBB's to handle the code.
Anyone have an idea how to resolve this?
EDIT:
Chris' answer was actually the one I was looking for in this particular situation, but I feel that I should point out that Priyank's function is something that should be regarded as such as well. So thank you both for the help, it made my life somewhat easier now!

I hope this razor function will help you lot. This is very helpful function to render the link tag from the component link or external link.
#helper RenderLink(
dynamic link, // the link to render. Handles components + internal / external links
string cssClass = null, // optional custom CSS class
string title = null // optional link text (default is the title of the component being linked to)
)
{
if(link == null)
{
return;
}
if (title == null)
{
title = link.title;
}
string classAttr = string.IsNullOrEmpty(cssClass) ? "" : " class='" + cssClass + "'";
dynamic href;
string tridionLink = "";
string targetAttr = "";
if (link.Schema.Title == "External Link")
{
href = link.link;
}
else if (link.Schema.Title == "Internal Link")
{
href = link.link;
tridionLink = "tridion:";
}
else
{
href = link;
tridionLink = "tridion:";
}
if(link.target != null)
{
targetAttr = link.target == "New window" || link.target == "Popup" ? " target='_blank'" : "";
}
<a #(tridionLink)href="#href"#classAttr#targetAttr>#title</a>
}

I would suggest not using the default templates for resolving your links, rather output the link yourself something like this:
<tridion:ComponentLink runat="server" PageURI="tcm:15-407-64"
ComponentURI="tcm:15-1475" TemplateURI="tcm:0-0-0"
AddAnchor="false" LinkAttributes=" class="more""
TextOnFail="true">
<%=DefaultLabels.TranslatedTerm(((HomePage)Page).Location, "read_more") %>
</tridionComponentLink>
Better still you might consider outputting TCDL rather than the Taglib/ServerControl

Related

What is the simplest way to find current item ID in the template

In my C# or dreamweaver template I need to know what am I rendering. The problem is that I don't know for sure if I'm looking for a page or component. I could probably use package.GetByType(ContentType.Page) and if it's empty - get content of a component, but I feel there should be a shorter way.
Example of David is shorter:
engine.PublishingContext.ResolvedItem.Item.Id
engine.PublishingContext.ResolvedItem.Item.Id
You can also check the Publishing Context's resolved Item and see if it's a Page or not (if it's not, then it's a Component).
For example:
Item currentItem;
if (engine.PublishingContext.ResolvedItem.Item is Page)
{
currentItem = package.GetByName(Package.PageName);
}
else
{
currentItem = package.GetByName(Package.ComponentName);
}
TcmUri currentId = engine.GetObject(currentItem).Id;
If you want to shortcut the engine.GetObject() call, then you may be able to get the ID from the Item's XML directly:
String currentId = currentItem.GetAsSource().GetValue("ID");
That's how I've seen it done before:
// Contains the call you describe in your question
Page page = GetPage();
if (page == null)
{
// Contains a call using package.GetByName("Component")
// to avoid the situation with multiple Components on the package
Component comp = GetComponent();
// Do component stuff
}
else
{
// Do page stuff
}
Not sure you can encapsulate it much nicer than that really but I may be proved wrong.

How to retrieve a sitecore hyperlink?

Situation:
Imagine that I have an item(page) located at 'sitecore/Content/Home/mypage' in my content tree. I want to create a hyperlink to this item in my .aspx layout.
Question:
How can I create a hyperlink to this item in my .aspx layout?
(Can't remember the proper syntax for <asp:Hyperlink>)
If you need to get an Item's url in code, whether or not you're using it in a link, you can use Sitecore.Links.LinkManager.GetItemUrl(item, options).
I recommend against using it with a single parameter (GetItemUrl(item)), as it wont respect configuration options (such as disabling the language string as part of the path: /en/path/to/item might appear instead of /path/to/item).
To use the config options, you can clone the default URL options:
var opts = (UrlOptions) UrlOptions.DefaultOptions.Clone();
var url = LinkManager.GetItemUrl(item, opts);
I use this often enough that I use the following extension method:
public static string GetUrl(this Item source, bool absolutePath = false)
{
if (source == null)
throw new ArgumentNullException("source");
var options = (UrlOptions) UrlOptions.DefaultOptions.Clone();
options.AlwaysIncludeServerUrl = absolutePath;
return LinkManager.GetItemUrl(source, options);
}
The advantage to using this format is that it allows you to identify an item by ID and link to it no matter where it lies in the content tree.
I'm not sure if in Adil's example, the URL is processed by the LinkProvider?
I would usually bind the NavigateUrl property in my code-behind
<asp:HyperLink ID="hlHyperLink" runat="server" Text="my link text" />
then in C#
hlHyperLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Database.GetItem("path_to_item"));

Setting multiple literals that contain the same text in ASP.NET

I have instances where I need to dynamically load 5-10 literals with the same text value. It seems like there has to be a more elegant way of doing it than setting the TEXT property of all the controls to the same value. Any methods out there that I'm not aware of? I thought about setting a protected property on my webform, and then using inline code on my aspx page. Is that a good approach?
Edit: I should add that I also want to handle the situation where a designer could simply add another place to load dynamically to the aspx file on the web server without having to do another rollout.
Pseudo code:
var literals = new List<Literal>() { l1,l2,l3 ...} ;
literals.ForEach(x=>x.Text = "some value");
When faced with the same problem I often use:
litOne.Text = litTwo.Text = litThree.Text = "some value";
It's not perfect but at least it's on one line.
How about this?
foreach (ITextControl textControl in new[] { literal1, literal2, literal3 })
{
textControl.Text = "foo";
}
You could even be fancier and just loop through all controls and check only those that implement the ITextControl interface or so.

Struts2 back button and linking

I am using Struts 2.1.6 with Dojo plugin, whole app has ajax links (sx:a).
Did anybody succeed to implement back button functionality and linking to certain content?
Does anybody have any experience how to implement? I am planning to implement (if there is no good solution already) something like so:
changing address bar link (adding parameters) with js which I can then read and get proper content and then publish it with notifyTopics.
Or should I just change whole app to use jQuery plugin? Do jQuery has good solutions for back button and linking on ajax pages?
I can think of 2 simple ways off the top of my head:
<s:form action="actionName">
<input type="hidden" value="<s:property value="someProperty"/>" name="someProperty"/>
<input type="hidden" value="<s:property value="someProperty2"/>" name="someProperty2"/>
<s:submit value="Back" />
</s:form>
or
<s:url name="backURL" action="actionName">
<s:param name="someProperty" value="someProperty"/>
<s:param name="someProperty2" value="someProperty2"/>
</s:url>
Back
If you already have query string parameters:
Back
or
<input type="button" value="Back" onclick="javascript.window=document.referrer;"/>
I have tried to use Struts 2 with dojo and implement the back button. You are already way over the head of Struts 2's ajax implementation. They mainly used and wrote it to write simple and quick ajax function calls and is not very well suited for more extensive uses. Plus when you do s:head theme='ajax' tag; struts will import every ajax js file you 'may' need which kills load time.
I would suggest either 1. Learn dojo and use the library independent of struts 2. Or 2. Get jQuery, I was able to implement a back button functionality relatively simple (more so then struts 2 theme='ajax').
Don't know Struts, but have you looked at dojo.undo (0.4.3)?
All my links go through one action which looks for a parameter menuId (of course id of a menu which has to be shown).
From this action, before returning response I set one javascript function to be called:
setBackMenuId(menuId,sometext)
MenuId is the id, sometext is a name of that menu, so browser log history better.
function setBackMenuId(id,subtekst) {
window.location.hash = "menuId="+id;
document.title = subtekst;
selectedHash = document.location.hash;
if(intervalHashSearch == '') {
initializeHashSearch();
}
}
Then, other needed js functions:
function publishLinkTarget() {
var param = window.location.hash;
if(param) {
if(param.indexOf("menuId") > 0) {
var id = param.split("=", 2);
if(id[1]) {
setCookie('backMenuId',id[1],1,false);
setTimeout('publishLayoutContent()', 100);
}
}
}
}
var selectedHash = '';
var intervalHashSearch = '';
function initializeHashSearch() {
intervalHashSearch = window.setInterval('checkHash()', 500);
}
function stopHashSearch() {
window.clearInterval(intervalHashSearch);
intervalHashSearch = '';
}
function checkHash() {
var currentHash = document.location.hash;
if(selectedHash != currentHash) {
selectedHash = currentHash;
publishLinkTarget();
}
}
function publishLayoutContent() {
dojo.event.topic.publish("layoutContentTarget");
}
If you look at it you see, that first it is called 'setBackMenuId', which adds hash and parameter to address bar and changes title, and then remembers this hash, so interval hash search can find out the differrence. Then it initializes this hash search.
'checkHash' is running ever 500 miliseconds and is checking if hash has changed (that means, that back button was pressed, and not a new link was clicked (setBackMenuId sets selectedHash). If true (back/forward button was pressed) function 'publishLinkTarget' is called, which reads the parameters from hash, and if they are ok, first I set a cookie, so I can read it from the HttpServletRequest and find out for which menu id link is. If I am here it means that I have to also publish the content which is made with 'publishLayoutContent'.
In action class (this is MenuAction, method view, the same as published in ) only this is important:
Integer menuId = null;
if(request.getParameter("menuId") != null) {
menuId = Integer.valueOf(request.getParameter("menuId"));
} else {
menuId = getIntCookie("hiddenMenuId");
}
So, if I don't get the menu id from the parameter (link clicked) I get from a cookie (back/forward button).
And JSP with this target:
<s:url var="layoutContentUrl" action="Menu-view" namespace="/public" />
<sx:div showLoadingText="false" indicator="ajaxIndicator"
id="layout-content" href="%{layoutContentUrl}" theme="ajax"
listenTopics="layoutContentTarget" preload="false"
afterNotifyTopics="/ajaxAfter">
</sx:div>
NOTE: This is a special case if you have everything connected through one parameter, but it can be easily extended with other parameters which publish other targets. I will try to make it enough generic to publish it somewhere, but this is (I guess) a long way ahead :)
If you have any question, please post it.

Why does document.getElementById('hyperlink_element_id') return the value of the hyperlink's href attribute?

I'm trying to grab the Web.UI.WebControls.HyperLink object itself via javascript so that I can modify its ImageUrl.
Here I'm setting the hyperlink's NavigateUrl to the my javascript function call:
lnkShowHide.NavigateUrl = String.Format(
"javascript:ShowHideElement('{0}');", lnkShowHide.ClientID
)
Here's my javascript function:
function ShowHideElement(img) {
   var ele = document.getElementById(img);
   if(ele != null) {
      // Not sure if this will change the hyperlink's ImageUrl property???
      img.src = 'smallPlus.gif';
   }
}
However, if I check the value of 'ele' after calling getElementById it prints "String.Format("javascript:ShowHideElement....." and doesn't actually get the hyperlink object itself.
Any ideas would be greatly appreciated!
Why does document.getElementById() return the value of the hyperlink's href attribute?
It doesn't. But when you “alert(element)”, alert() calls toString() on the element, and HTMLLinkElement.toString() returns the contents of the href attribute, so “alert(link)” spits out the same results as “alert(link.href)”.
(Which is a bit weird and confusing, but that's how JavaScript 1.0 worked so there's not much can be done about it now.)
I check the value of 'ele' after calling getElementById it prints "String.Format("javascript:ShowHideElement....."
That shouldn't happen with the exact example you've given... there's no way the server-side “String.Format...” code should make its way through to the client side unless you accidentally enclosed it in quotes, eg.:
lnkShowHide.NavigateUrl = "String.Format(...)";
Other problems that spring to mind are that the function changes name (ShowHideElement/ShowHideImage), and you appear to be trying to set ‘.src’ on the link element (<a>). Links don't have .src, only images do.
Anyhow, you probably don't want to do a show/hide widget like this. javascript: URLs are always the wrong thing, and your example involves a lot of nested strings inside each other which is always fragile. You could try an ‘unobtrusive scripting’ approach, generating markup like:
<div class="showhide"> blah blah blah </div>
With JavaScript to add the open/close functionality at the client side (so non-JavaScript UAs and search engines will see the whole page without hiding bits). eg.:
function ShowHider(element) {
var img= document.createElement('img');
element.parentNode.insertBefore(img, element);
function toggle() {
var show= element.style.display=='none';
element.style.display= show? 'block' : 'none';
img.src= '/images/showhide/'+(show? 'open' : 'closed')+'.gif';
img.alt= show? '-' : '+';
img.title= 'Click to '+(show? 'close' : 'open');
}
img.onclick= toggle;
toggle();
}
// Apply ShowHider to all divs with className showhide
//
var divs= document.getElementsByTagName('div');
for (var i= divs.length; i-->0;)
if (divs[i].className=='showhide')
ShowHider(divs[i]);

Resources