1 Reply Latest reply on May 15, 2019 1:26 PM by RaffyMartin

    Side Navigation Context Menu

    RaffyMartin

      Hello everyone,

       

      I'm trying to implement a "Add to Favorite" / "Remove from Favorite" feature on the Side Navigation t_TreeNav by appending a context menu and it seems this is possible to do just like the context menus on Apex Page Designer, but basically this is not really documented well especially on old versions of Apex (I'm using 5.1.4). I came across a plugin for a tree region that does this, however, I can't implement that since the Side Nav Tree is already defined.

       

      Below you can see the one from Page Designer with all different options, on my Side Nav, I have the first node which is the Favorite which has these options saved on a favorite table by user. The user could then go an option in the other nodes like Accounts Payable, Sales, etc. and right click to "Add to Favorite" and on the action I would need to do an Ajax call to save the node option (href/link) associated to it and save it on the favorite table for that user and maybe even refresh the whole side navigation so the new menu option shows up when going back to favorite. If the user is the Favorites node the action would be "Remove from Favorite" and do the same Ajax call but to delete the option instead.

       

      I would like to implement this as there are many options in the menu and even though I have implemented search capabilities, it's a good thing to have 10 or 15 menu options that you use the most on the favorite node.

       

      Any help on how I could implement this would be appreciated. Thank you in advance.

       

      P.S. I have imported the Apex App Builder to see if could steal the implementation from it, but that's a huge app and looking through it including page 4500, was not able to find what I was looking for.

       

        • 1. Re: Side Navigation Context Menu
          RaffyMartin

          Hello everyone,

           

          I just wanted to let you know that I was able to implement this feature by following along John Snyders blog APEX 5.0 Custom Menus – HardLikeSoftware about custom menus, reviewing the newer documentation of the menu and treeView widgets https://docs.oracle.com/en/database/oracle/application-express/18.2/aexjs/menu.html  and the jquery api https://api.jquery.com/

           

          Here's is my code, sorry is not indented when I copied it over, but basically, you select the target that you right-clicked and if there's no href, then stop processing since it's a parent no that have no page. Then I get the ID of the parent node which for the top level menu options to confirm if it's t_TreeNav_0 (Favorites) or not because based on this value you need to either show "Remove from Favorites" or "Add to Favorites" which is the part at the end to toggle/show menu.

           

          Finally, you can see that within the menu action there's an ajax call to call ADD_FAVORITE and DEL_FAVORITE processes defined at the application level and on success I was reloading the page at first, but looking at the jquery api I was able to just remove the node from favorites or clone/copy and appended at the end of t_TreeNav_0 ul  and so no more reloading the page which is a better experience.

           

          Below what the menu looks like when you right click on one of the menu options to "Add to Favorites" Or "Delete from Favorites" and so this is available for anyone that would like to implement it as a feature on their apps or that would like to enhance the code.

           

          P.S. This code is just a rough implementation and could probably be enhanced. The code is on the Page Load event of the Global Page (Page 0).

           

          contextMenu.png

           

          $( "#t_TreeNav" ).contextmenu(function( event ) {

           

             event.preventDefault();

             // select current node

             $win = $(window);

             var target = document.elementFromPoint(event.pageX - $win.scrollLeft(), event.pageY - $win.scrollTop());

            

             var menuOption = $(target).attr('href');

             if (typeof menuOption === 'undefined') {

             return;

            }

             // select parent node

             var parentNode = $(target).parentsUntil("li.a-TreeView-node a-TreeView-node--topLevel").eq(3).attr("id");

             // select current node

             var currentNode = $(target).parentsUntil("li.a-TreeView-node a-TreeView-node--leaf").eq(1);


             // define menu icon and label

             var menuLabel, menuIcon;

             if (parentNode != "t_TreeNav_0") {

             menuLabel = "Add to Favorites";

             menuIcon = 'fa-heart-o';

            } else {

             menuLabel = "Remove from Favorites";

             menuIcon = "fa-heart-o fam-x fam-is-danger";

            }

             // build menu

             var contextMenu$ = $( "<div style='display:none'></div>" ).appendTo( "body" );

             contextMenu$.menu({

             iconType: "fa",

             items:[

            {

             type:"action",

             icon: menuIcon,

             label: menuLabel,

             action: function() {

             //add to favorites

             if (parentNode != "t_TreeNav_0") {

             apex.server.process(

             'ADD_FAVORITE',

            { x01: menuOption },

            { success: function(data) {

             // clone/copy node to favorites

             $(currentNode).clone().appendTo("#t_TreeNav_0 ul");

            }

            }

            );

            } else {

             // remove from favorites

             apex.server.process(

             'DEL_FAVORITE',

            { x01: menuOption },

            { success: function(data) {

             // remove node

             $(currentNode).remove();

            }

            }

            );

            }

            }

            }

            ]

            });

             // show menu

             contextMenu$.menu( "toggle", event.pageX, event.pageY );

            });