Wednesday, August 29, 2007

Manage Publishing Page Nodes in Site Navigation

Hi all,
What I am publishing here is some undocumented issues
involving navigation items in publishing enabled sites.

When you have publishing feature enabled in MOSS sites publishing
pages from “pages” library automatically set to be displayed in navigation. So far
– nothing is new.

What you didn’t know is that when you try to access these
items in the site’s navigation in order to perform a simple task such as hiding
a page from navigation, changing a page’s display order and other tasks
you are in to a nasty surprise!

What you want to do is to:

A: Get an instance of the current web site (SPWeb web = SPControl.GetContextWeb(Context) from within a web part.

B: Get the left navigation nodes collection (using web.Navigation.QuickLaunch)

C: Loop over navigation items and move/hide/rename etc… (foreach(SPNavigationNode node in web.Navigation.QuickLaunch))

But wait –

If you just created the site and added some pages to it you
are in to a nasty surprise as I promised. You will notice that
none of your
pages
that are displayed in the navigation are in that collection!

Actually the collection should be empty unless you added
some other items to it manually.

You will also notice a very weird behavior of
SharePoint that as soon as you open the “Navigation” page in the UI of
that site and make any change and save it – since that change all items
suddenly
appear in the navigation collection
as you expected them to from the
beginning!

My customer and I had to create pages and sites by code and
change their ordering by the same code. Of course we didn’t plan on browsing
each site and making a change manually – so we had to find a solution for that
issue.

The following code fixes that “problem”. It goes over a publishing
site pages library and make sure that all pages navigation nodes were created
and available for change using your code.

This took me quite a lot of time to investigate and find
this solution since it is not documented anywhere!!! So enjoy…

SPWeb curWeb = GetWeb();
PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(curWeb);
//Get existing links in navigation
//(so we know if to create new or move existing link)
List<string> existing = new List<string>();
foreach(SPNavigationNode node in curWeb.Navigation.QuickLaunch)
existing.Add(node.Url.ToLower());
//Loop for each page in pages library
foreach(SPListItem item in pWeb.PagesList.Items)
{
//Get a fresh copy of web – curWeb =
//new SPSite(curWeb.Site.ID).OpenWeb(curWeb.ID);...
curWeb = Utilities.Refresh(curWeb);

PublishingPage pp = PublishingPage.GetPublishingPage(item);
SPNavigationNode nn = null;
string ppUrl = pp.Uri.AbsolutePath.ToLower();
//check if exists in navigation
if (existing.Contains(ppUrl))
{
continue;
}
else//add a new navigation item
{
//not? add it.
nn = new SPNavigationNode(pp.Title, ppUrl);
nn = curWeb.Navigation.QuickLaunch.AddAsFirst(nn);
//here is the trick –
//We mark the navigation item as type “Page”.
nn.Properties["NodeType"] = "Page";
nn.Update();
}
curWeb.Update();
}

Wednesday, August 15, 2007

Managing Field Control Visibility - a step towards field level security and much more

Hi all,
Many times I face the same problems with almost all my customers.
In some point it seems they all want more controls over fields in the “edit” and “new” item form.
Some want to hide it from unauthorized users; others want to give a field a default value that changes according to the current user, and even some more interesting things like filtering values in choice fields to answer some complicated logic.
So one way to support all these whims is to develop new field types with field controls to mach – you can find plenty examples for that on the web (like our soon-to-be-released tags field type).
Here I want to show a simpler solution that involves only editing the edit/view form of the list and make use of very simple javascript code to get control over the client-side HTML element of each field.
One more thing – although we can create a custom list form using the SharePoint designer to hide controls there is a major disadvantage in using such a custom list form. If your user will add a new field in the future it will not show automatically in the edited form and you will have to edit these forms every time your user changes the list.
This code I wrote with the help of Sveta (thanks) expects the field display name and look for it in the HTML while it assumes a comment tag with the field name will exist right above the field itself.
Here is the code:
var ctrl = null;
//Place this code right AFTER the list view web part.
//To go into edit mode of the page,
//in case you dont have the edit page menu paste this in the browser's address bar:
//javascript:MSOLayout_ChangeLayoutMode(false)
function foo()
{
var ctrl = null;

var arr = document.getElementsByTagName('!');//get all comments

for(var i=0;i<arr.length;i++)
{
try
{
var html = arr[i].innerHTML;

if(
html.indexOf("field to hide 1") > 0 ||
html.indexOf("field to hide 2") > 0
)
{
ctrl = arr[i].parentElement.parentElement;
ctrl.style.display="none";
}

}
catch(e){alert(e.description);}
}
}
foo();




Doing this allows you to keep the default list form and still get some control of the desired field element. I usually wrap this code in a custom control that analyzes on the server side what needs to be done (hide element, replace with another or filter a combo box) and make use of the code above to complete the job on the client site. For example if I want to achieve a field level security for any SharePoint list field my server control will test the user permissions and will hide the control if the current user does not have enough permissions.
Hope this could help some of you guys,
Shai Petel.

Wednesday, August 1, 2007

Variations Menu - switching between a page variations

Hi all,

I got to do quite a lot of work using MOSS WCM variations for creating translations of pages and sites to different languages.

Having the microsoft VM i noticed that whenever I created a new variation to a page a manu would show at the top right of the page and allow me to switch between all variations of that page.

To my (rather big) surprise I found out that when I did the very same procedure on my customer's production server variations did work ok and translated my pages but I did not see the variations menu and could not navigate from one variation of the page to another.

Looking at the master page I did see the variations menu control (<PublishingVariations:VariationsLabelMenu id="labelmenu1" runat="server"/>) was in place but it did not render any HMTL...

After some googling me and shlomy (my customer from IDC) did we learned that the variations menu control uses a user control (ascx file) to display the items, and that by default this control is commented out inside the ascx (?!?!?!?)

What I had to do in order to make the variations label menu visible is to open "VariationsLabelMenu.ascx" that is in "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES\" and remove the comment text wrapping the control <%!-- and --%>

Now everything works!

Why is it turned off by default? Have no idea. But in 2-3 minutes you'll have your site's variations labe up and running and your users will be surfing between page translations in no time!

Hope this helps, will update if I find a reason to turn it off since I didnt find one yet.

Shai Ben Shooshan