Where in the Fluid Am I?

When navigating in a PeopleSoft system that uses Fluid Navigation, it can be easy to lose your bearings in terms of where you actually are in the Portal Registry.  Knowing the exact Content Reference (and how to get to it) in Structure and Content is sometimes crucial when troubleshooting issues.  The problem is that the new Fluid Navigation does not directly correlate to the structure of the Portal Registry like it used to in Classic (breadcrumb) Navigation.  This results in there being no easy way to determine where a given Fluid page is in Structure and Content.  I have recently found that using the combination of a simple Bookmarklet and IScript to be sufficient enough to reveal the Portal Registry path for the pages that I navigate to.  In this post, I will share the implementation details of this helpful utility.

CLICK HERE to download the app designer project.  Unzip the project from the downloaded file and import the project from file in App Designer.

There is a Permission List in the project named PSM_YAH.  This Permission List has access to the IScript that provides the Portal Registry path for a given page.  Assign the PSM_YAH Permission List to a Role that you want to have this functionality enabled for.

Assign Permission List

Now you should be able to invoke the IScript without receiving an authorization error.  You can call the IScript by pasting in the following value into your web browser after authenticating into the application.

<domain>/psc/ps/<portal>/<node>/s/WEBLIB_PSM_YAH.ISCRIPT1.FieldFormula.IScript_YouAreHere

You should receive a response that states “Current Page Information Not Provided”.

To test the IScript with actual values, you can provide the menu and component URL query parameters to fetch the Portal Registry path for the values.  Below is an example call for the User Profiles Portal Registry path.

<domain>/psc/ps/<portal>/<node>/s/WEBLIB_PSM_YAH.ISCRIPT1.FieldFormula.IScript_YouAreHere?menu=MAINTAIN_SECURITY&component=USERMAINT

The script’s response in this case should be “Root > PeopleTools > Security > User Profiles > User Profiles”.

Alternatively, you can provide the url to a given Content Reference as a query parameter and the script will respond with the Portal Registry path to the Content Reference. Here is an example to get the Portal Registry path for the “User Profiles” Content Reference via its URL:

<domain>/psc/ps/<portal>/<node>/s/WEBLIB_PSM_YAH.ISCRIPT1.FieldFormula.IScript_YouAreHere?url=http://<domain>/psc/ps/<portal>/<node>/c/MAINTAIN_SECURITY.USERMAINT.GBL

The functionality provided by the IScript is helpful, but the call to the IScript needs to be made more functional.  To achieve this, I took some pointers from Jim Marion’s blog posts on bookmarklets and PeopleSoft JavaScript development techniques, and created a “You Are Here” bookmarklet.  I think exposing the Portal Registry path information for a PeopleSoft page through a bookmarklet provides an acceptable level of usability.  To make use of the bookmarklet, drag the link below into your browser’s bookmark bar.

PS You Are Here

Now when you are on a PeopleSoft page and you have access to the IScript mentioned above, you can click the bookmarklet to get a div element injected into the page that contains the Portal Registry path information for the current page.  Here is an example of when I invoke the script on the Fluid Addresses page:

Fluid Addresses

And here is the script’s output for the Fluid Homepage:

Fluid Home

As you can see, each breadcrumb in the outputted Portal Registry path is clickable.  Clicking the breadcrumb will take you to the corresponding Content Reference in Structure and Content.  When I click the Fluid Homepage breadcrumb, I am taken to the Structure and Content for the Fluid Homepage Content Reference.

Fluid Home CREF

The script is also capable of giving the Portal Registry path for non-Menu/Component based Content References.  For example, my online PeopleCode editor is an IScript based Content Reference.  When I invoke the bookmarkelt on this particular page, the script responds with the correct Portal Registry path.

IScript CREF

I will admit that there are some rough edges with this utility, but I have found it to be very useful for the most part. While this tool is helpful in determining how to get to a particular Content Reference in Structure and Content, it fails to provide the actual path that a user took to get to the given page. For example: Which homepage the user came from, which tile the user clicked on, etc. Dan Iverson has an idea in the My Oracle Support Community PeopleTools idea space that seems to propose this functionality. I think having this sort of tracking functionality baked into the application could be useful in troubleshooting and replicating issues.

Code References

Bookmarklet JavaScript:

(function() {
 var xhttp = new XMLHttpRequest();
 
 xhttp.onreadystatechange = function() {
 if (this.readyState == 4 && this.status == 200) {
 var yah = (doc.getElementById('youarehere') ? doc.getElementById('youarehere') : doc.createElement('div'));
 yah.id = 'youarehere';
 yah.style = 'text-align: center; border:solid black 1px;';
 yah.innerHTML = this.responseText;
 var bodyEl = doc.getElementsByTagName('BODY')[0];
 bodyEl.insertBefore(yah, bodyEl.firstChild);
 }
 };

 var currUrl = (!!frames['TargetContent'] ? !!frames['TargetContent'].strCurrUrl ? frames['TargetContent'].strCurrUrl : window.location.href : window.location.href);
 var parts = currUrl.match(/ps[pc]\/(.+?)(?:_(\d+))*?\/(.+?)\/(.+?)\/[chs]\//);
 var doc = (frames['TargetContent'] ? frames['TargetContent'].document : document);
 var divId = (doc.getElementById('pt_pageinfo') ? 'pt_pageinfo' : parts[2] ? 'pt_pageinfo_win' + parts[2] : 'pt_pageinfo_win0');
 var pageInfo = doc.getElementById(divId);
 var menu = (pageInfo ? pageInfo.getAttribute('menu') : '');
 var component = (pageInfo ? pageInfo.getAttribute('component') : '');
 var mode = (pageInfo ? pageInfo.getAttribute('mode') : '');
 var portalNeeded = (frames['TargetContent'] ? 'n' : 'y');
 var scriptUrl = window.location.origin + '/psc/' + parts[1] + '/' + parts[3] + '/' + parts[4] + '/s/WEBLIB_PSM_YAH.ISCRIPT1.FieldFormula.IScript_YouAreHere?url=' + encodeURIComponent(currUrl) + '&menu=' + encodeURIComponent(menu) + '&component=' + encodeURIComponent(component) + '&p=' + portalNeeded;

 xhttp.open('GET', scriptUrl, true);
 xhttp.send();
}())

IScript PeopleCode:

Declare Function PortalOpen PeopleCode FUNCLIB_PORTAL.PORTAL_GEN_FUNC FieldFormula;

Function IScript_YouAreHere()
 Local string &sUrlParam = Unencode(%Request.GetParameter("url"));
 Local string &sMenu = Unencode(%Request.GetParameter("menu"));
 Local string &sComponent = Unencode(%Request.GetParameter("component"));
 Local string &sPortalNeeded = %Request.GetParameter("p");
 
 /* If the required parameters are not provided, then output a message */
 If (None(&sMenu) Or
 None(&sComponent)) And
 None(&sUrlParam) Then
 %Response.Write("Current Page Information Not Provided");
 Return;
 End-If;
 
 Local ApiObject &portal = PortalOpen();
 Local ApiObject &sCurrCref;
 
 /* First, try to find the CREF by using the provided Menu and Component */
 If &portal.FindCRefByURL(GenerateComponentContentURL(%Portal, %Node, @("Menuname." | &sMenu), "GBL", @("Component." | &sComponent), "", "")) <> Null Then
 &sCurrCref = &portal.FindCRefByURL(GenerateComponentContentURL(%Portal, %Node, @("Menuname." | &sMenu), "GBL", @("Component." | &sComponent), "", ""));
 Else
 /* Second, try to find the CREF by using the provided url (including url query parameters) */
 If (&portal.FindCRefByURL(&sUrlParam) <> Null) Then
 &sCurrCref = &portal.FindCRefByURL(&sUrlParam);
 Else
 /* Third, try to find the CREF by using the provided url (Excluding url query parameters) */
 If (&portal.FindCRefByURL(Split(&sUrlParam, "?")[1]) <> Null) Then
 &sCurrCref = &portal.FindCRefByURL(Split(&sUrlParam, "?")[1]);
 Else
 /* If all three attempts of getting the current CREF fail, then output a message */
 %Response.Write("No Content Reference Exists for the Provided Page Information (URL = " | &sUrlParam | ", " | "Menu = " | &sMenu | ", " | "Component = " | &sComponent | ")");
 Return;
 End-If;
 End-If;
 End-If;
 
 /* Check if portal wrapper is needed */
 Local string &sSCCrefLinkBase;
 Local string &sSCFldrLinkBase;
 If &sPortalNeeded = "y" Then
 &sSCCrefLinkBase = GenerateComponentPortalURL(%Portal, %Node, MenuName.PORTAL_ADMIN, "GBL", Component.PORTAL_CREF_ADM, "", "");
 &sSCFldrLinkBase = GenerateComponentPortalURL(%Portal, %Node, MenuName.PORTAL_ADMIN, "GBL", Component.PORTAL_OBJ_LIST, "", "");
 Else
 &sSCCrefLinkBase = GenerateComponentContentURL(%Portal, %Node, MenuName.PORTAL_ADMIN, "GBL", Component.PORTAL_CREF_ADM, "", "");
 &sSCFldrLinkBase = GenerateComponentContentURL(%Portal, %Node, MenuName.PORTAL_ADMIN, "GBL", Component.PORTAL_OBJ_LIST, "", "");
 End-If;
 
 /* Get the current CREF's parent folder */
 Local ApiObject &sParentFolder = &portal.FindFolderByName(&sCurrCref.ParentName);
 
 /* Get the link to the CREF in Structure and Content */
 Local string &sSCLink = &sSCCrefLinkBase | "?PORTALPARAM_PNAME=" | &sParentFolder.Name | "&PORTALPARAM_CNAME=" | &sCurrCref.Name;
 Local string &sYouAreHere = "<a href=" | &sSCLink | ">" | &sCurrCref.Label | "</a>";
 
 While (&sParentFolder <> Null)
 /* Get a link to the parent folder in Structure and Content */
 &sSCLink = &sSCFldrLinkBase | "?PORTAL_NAME=" | %Portal | "&PORTALPARAM_FNAME=" | &sParentFolder.Name;
 &sYouAreHere = "<a href=" | &sSCLink | ">" | &sParentFolder.Label | "</a>" | " > " | &sYouAreHere;
 /* Get the parent folder */
 &sParentFolder = &portal.FindFolderByName(&sParentFolder.ParentName);
 End-While;
 
 %Response.Write(&sYouAreHere);
 
 &portal.close();
 
End-Function;

Leave a Reply

Your email address will not be published.