Thursday, July 25, 2019

Fluid Navigation Collection - Adding Icons to links in Folders

While configuring Navigation Collections we have the option of setting an icon for each link/folder.

For example:



Let us say, that we add override images for all links and folders in the following Nav Collection which contains links, a folder and links within the folder.


Results

Before adding override images (Default icons)


After adding override images (Custom Icons)


Notice how links in the folder do not have any override images/icons? This is because the delivered code only includes the override images on the first level links and folders. Also, as we all know, Fluid Nav Collections only allow (display) one level of folders. That is, we cannot have a folder within a folder as we could with Classic Nav Collections.

How do we add icons to links in a Fluid Nav Collection Folder?

This seems to be a common requirement that I have run into in many forums. For example:
https://community.oracle.com/message/15394690

As mentioned earlier, this is not available by default for Fluid Nav Collection. The only workaround I could find is to add a small snippet of custom code to apply the image overrides for links within the Folders.


Results

After adding custom code


Note

To avoid this customization, I considered using Event Mapping App Package PeopleCode that could potentially be hooked to PT_AGSTARTPAGE_NUI component. But I did not find an easy way to replicate the code after the fact that the delivered code executed. I found that it is much easier to simply add this custom code in the delivered event.

PeopleCode for Reference

Customized App Class: PTGP_GUIDED_PROCESS.DataSources.NavigationCollectionDataSource.OnExecute
Customized Method: populateGuidedProcessObject

/**
* Populate Guided Process object for Activity Guide
*
* @return BaseGuidedProcess
*
*/
method populateGuidedProcessObject
/+ Returns PTGP_GUIDED_PROCESS:GuidedProcesses:BaseGuidedProcess +/
/+ Extends/implements PTGP_GUIDED_PROCESS:DataSources:ActivityGuideDataSource.populateGuidedProcessObject +/
Local string &text, &iconUrl, &msgNode, &stepId;
Local string &defaultFolderIconUrl, &defaultCollectionIconUrl, &defaultContentIconUrl;
Local boolean &succeeded;
Local Record &rec;
Local PTGP_GUIDED_PROCESS:GuidedProcesses:BaseGuidedProcess &thisProcess;
Local PTGP_GUIDED_PROCESS:Elements:StepElement &thisStep;
Local PTGP_GUIDED_PROCESS:Elements:StepGroupElement &thisStepGroup, &theRootStep;
Local PTGP_GUIDED_PROCESS:Elements:ContextTextElement &headerText;
Local PTGP_GUIDED_PROCESS:Elements:ButtonElement &thisButton;
Local PTPP_COLLECTIONS:NavigationCollection &thisNavColl;
Local PTPP_COLLECTIONS:Folder &thisFolder;
Local PTPP_COLLECTIONS:Shortcut &thisShortcut;
&thisProcess = create PTGP_GUIDED_PROCESS:GuidedProcesses:BaseGuidedProcess("PTGPTester");
&theRootStep = &thisProcess.RootStep;
Evaluate %This.RenderType
When %This.RENDER_TYPE_HORIZONTAL
When %This.RENDER_TYPE_VERTICAL_OPTIMIZED_SEQUENTIAL
When %This.RENDER_TYPE_VERTICAL_NONOPTIMIZED_SEQUENTIAL
&thisProcess.IsSequential = False;
Break;
When %This.RENDER_TYPE_VERTICAL_OPTIMIZED
When %This.RENDER_TYPE_VERTICAL_NONOPTIMIZED
When %This.RENDER_TYPE_NONGUIDED_OPTIMIZED
When %This.RENDER_TYPE_NONGUIDED_NONOPTIMIZED
Break;
End-Evaluate;
/* Default icons */
&defaultFolderIconUrl = %Response.GetImageURL(Image.PTPP_FN_FOLDER_ICN_FL);
&defaultCollectionIconUrl = %Response.GetImageURL(Image.PTPP_FN_COLLECTION_ICN_FL);
&defaultContentIconUrl = %Response.GetImageURL(Image.PTPP_FN_CONTENT_ICN_FL);
/* Get the Collection */
try
&thisNavColl = create PTPP_COLLECTIONS:NavigationCollection(%This.PortalName, %This.CollName);
catch Exception &ex
Error &ex.ToString( False);
end-try;
/* Generate the list */
If ((&thisNavColl <> Null) And
&thisNavColl.Authorized And
&thisNavColl.IsValid) Then
&theRootStep.Label = &thisNavColl.Label;
&ShowIcons = &thisNavColl.ShowIcons;
/* Root steps */
If (&thisNavColl.Shortcuts <> Null) Then
&thisShortcut = &thisNavColl.Shortcuts.First();
While (&thisShortcut <> Null)
/* Create the step */
&thisStep = create PTGP_GUIDED_PROCESS:Elements:StepElement(&thisShortcut.Name);
&thisStep.Label = UnEscapeHTML(&thisShortcut.Label);
&thisStep.URL = &thisShortcut.AbsoluteContentURL;
&thisStep.SequenceNumber = &thisShortcut.SequenceNumber;
&thisStep.IsFluid = &thisShortcut.IsFluid;
If (&thisShortcut.IsNewWindow) Then
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsolutePortalURLnewWin), "%25", "%") | "', 1);";
End-If;
If (&thisShortcut.IsTopWindow Or
%This.JumpPageMode) Then
If (&thisShortcut.IsFluid) Then
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsoluteContentURL), "%25", "%") | "', 4);";
Else
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsolutePortalURL), "%25", "%") | "', 4);";
End-If;
End-If;
&iconUrl = &thisShortcut.ImageURL;
If (All(&iconUrl)) Then
&thisStep.IconUrl = &iconUrl;
Else
If (&thisShortcut.TargetIsCollection) Then
&thisStep.IconUrl = &defaultCollectionIconUrl;
Else
&thisStep.IconUrl = &defaultContentIconUrl;
End-If;
End-If;
&theRootStep.addChildStep(&thisStep);
/* Next shortcut */
&thisShortcut = &thisNavColl.Shortcuts.Next();
End-While;
End-If;
/* Root folders */
If (&thisNavColl.Folders <> Null) Then
&thisFolder = &thisNavColl.Folders.First();
While (&thisFolder <> Null)
/* Create the step group */
&thisStepGroup = create PTGP_GUIDED_PROCESS:Elements:StepGroupElement(&thisFolder.Name);
&thisStepGroup.Label = UnEscapeHTML(&thisFolder.Label);
&thisStepGroup.SequenceNumber = &thisFolder.SequenceNumber;
&iconUrl = &thisFolder.ImageURL;
If (All(&iconUrl)) Then
&thisStepGroup.IconUrl = &iconUrl;
Else
&thisStepGroup.IconUrl = &defaultFolderIconUrl;
End-If;
/* First level child steps */
If (&thisFolder.Shortcuts <> Null) Then
&thisShortcut = &thisFolder.Shortcuts.First();
While (&thisShortcut <> Null)
/* Create the step */
&thisStep = create PTGP_GUIDED_PROCESS:Elements:StepElement(&thisShortcut.Name);
&thisStep.Label = UnEscapeHTML(&thisShortcut.Label);
&thisStep.URL = &thisShortcut.AbsoluteContentURL;
&thisStep.SequenceNumber = &thisShortcut.SequenceNumber;
&thisStep.IsFluid = &thisShortcut.IsFluid;
&thisStepGroup.addChildStep(&thisStep);
If (&thisShortcut.IsNewWindow) Then
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsolutePortalURLnewWin), "%25", "%") | "', 1);";
End-If;
If (&thisShortcut.IsTopWindow Or
%This.JumpPageMode) Then
If (&thisShortcut.IsFluid) Then
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsoluteContentURL), "%25", "%") | "', 4);";
Else
&thisStep.OnClick = "LaunchURL(null, '" | Substitute(EncodeURL(&thisShortcut.AbsolutePortalURL), "%25", "%") | "', 4);";
End-If;
End-If;
/* SV Custom Code - Start */
&iconUrl = &thisShortcut.ImageURL;
If (All(&iconUrl)) Then
&thisStep.IconUrl = &iconUrl;
Else
If (&thisShortcut.TargetIsCollection) Then
&thisStep.IconUrl = &defaultCollectionIconUrl;
Else
&thisStep.IconUrl = &defaultContentIconUrl;
End-If;
End-If;
/* SV Custom Code - End */
/* Next shortcut */
&thisShortcut = &thisFolder.Shortcuts.Next();
End-While;
End-If;
/* Sort and add the step group when it's not empty */
If (&thisStepGroup.ChildSteps.Count > 0) Then
&succeeded = &thisStepGroup.ChildSteps.sort(&cstSEQ_NUMBER, True);
&theRootStep.addChildStep(&thisStepGroup);
End-If;
/* Next folder */
&thisFolder = &thisNavColl.Folders.Next();
End-While;
End-If;
/* Sort the root list */
&succeeded = &theRootStep.ChildSteps.sort(&cstSEQ_NUMBER, True);
/* Set the current step id */
&stepId = %This.ItemName;
&thisStep = Null;
If ( Not %This.JumpPageMode) Then
If (All(&stepId)) Then
If (&stepId <> &cstBLANK_PAGE) Then
/* non-blank page, find the step */
&thisStep = &theRootStep.getChildStepById(&stepId);
End-If;
Else
/* Set the current step id to the first item */
&thisStep = &theRootStep.ChildSteps.get(1);
End-If;
End-If;
If (All(&thisStep)) Then
&thisStepGroup = (&thisStep As PTGP_GUIDED_PROCESS:Elements:StepGroupElement);
If (All(&thisStepGroup)) Then
&thisProcess.CurrentStepId = &thisStepGroup.ChildSteps.get(1).ID;
Else
&thisProcess.CurrentStepId = &thisStep.ID;
End-If;
End-If;
/* Header texts */
&headerText = create PTGP_GUIDED_PROCESS:Elements:ContextTextElement("label");
&headerText.StyleClass = "ps_ag-header-context-title";
&headerText.Text = &thisNavColl.Label;
&thisProcess.addHeaderText(&headerText);
&text = &thisNavColl.Description;
If (All(&text)) Then
&headerText = create PTGP_GUIDED_PROCESS:Elements:ContextTextElement("description");
&headerText.StyleClass = "ps_ag-header-context-text";
&headerText.Text = &text;
&thisProcess.addHeaderText(&headerText);
End-If;
/* Header buttons */
&thisButton = create PTGP_GUIDED_PROCESS:Buttons:ExitButton(&thisProcess.ID | "-ExitButton");
&thisProcess.addHeaderButton(&thisButton);
&thisButton = create PTGP_GUIDED_PROCESS:Buttons:PreviousButton(&thisProcess.ID | "-PreviousButton");
&thisProcess.addHeaderButton(&thisButton);
&thisButton = create PTGP_GUIDED_PROCESS:Buttons:NextButton(&thisProcess.ID | "-NextButton");
&thisProcess.addHeaderButton(&thisButton);
Else
Error MsgGetText(219, 1051, "Message Not Found - Invalid Nav Coll");
End-If;
Return &thisProcess;
end-method;