“Any sufficiently advanced technology is indistinguishable from magic.”
— Arthur C. Clarke
In the upper right-hand corner of the ServiceNow UI, you can click on your name and a little menu will drop down with a series of choices:
There is something similar on a ServiceNow Portal, with similar options. To easily move back and forth between the main Portal and the primary UI, I wanted to add an option to each environment’s User Menu to navigate to the other environment. On the Portal, this was easy enough to do by editing the HTML on the Stock Header. In the primary UI, however, this was not quite so easy.
The content of the drop-down User Menu is yet another one of those things that is not stored in the system database, but is rather an integral part of the product itself. As far as I can tell, there is no place to go where you can edit these options. But you know how that goes: if you can’t change what gets sent to the page, that doesn’t mean you can’t alter what is on the page once the page has been delivered. With a little View Source investigating, we can see that the menu is an HTML unordered list (<ul>) with a class of dropdown-menu. That’s enough to get a handle on things and build a quick little UI Script:
addLoadEvent(function() {
try {
var ssp = (window.top.$j("#self_service_link").length == 0);
if (ssp) {
var sspItem = "<li><a href='/sp' id='self_service_link'>" + getMessage("Self Service Portal") + "</a></li>";
var menuList = window.top.$j("ul.dropdown-menu");
if (menuList.length > 0) {
menuList.prepend(sspItem);
}
}
} catch(e) {
//
}
});
The script is pretty straightforward. First we check to make sure that we haven’t already stuffed the extra item out there (sometimes these things have a way of running more than one time), and if we haven’t, then we create the new menu item, locate the existing list, and prepend the new item to the existing list. After this has been activated, the menu now looks like this:
I was really quite proud of myself there for a while, and then I realized that on the Portal, the Profile option was still the first option and the ServiceNow option was the second option. By using the prepend function to insert the new menu item, I made it the first item on the menu instead of the second. That really disturbs my sense of The Way Things Ought To Be, so I needed to figure out how to make it the second option and not the first.
It’s true that I could have just reversed things on the Portal side of the house, which is much easier to manipulate, but that disturbs my sense of The Way Things Ought To Be as well. On a User Menu, the Profile link should always be the first and the Logout link should always be the last. Always. I can’t explain it, but that’s just The Way Things Ought To Be. Period.
I’m not going to reveal how many different things that I tried in an effort to insert the new item into the second slot, but let’s just say it’s more than I’d really care to discuss. In the end, I was able to cut and paste some code that I found out on the Interwebs and it did the trick, so that was good enough for me. Don’t ask me to explain how it works, because I haven’t a clue. Although I am pretty handy with Javascript, I don’t know much about AngularJS and I know even less about jQuery. This line of code is pure jQuery voodoo magic as far as I can tell, but it does satisfy rule #1: it works. Yes, that’s unquestionably Cargo Cult Coding, but I’ve never been too proud to leverage someone else’s code, even when I can’t possibly begin to fully understand it myself. You can see the updated script here:
addLoadEvent(function() {
try {
var ssp = (window.top.$j("#self_service_link").length == 0);
if (ssp) {
var sspItem = "<li><a href='/sp' id='self_service_link'>" + getMessage("Self Service Portal") + "</a></li>";
var menuList = window.top.$j("ul.dropdown-menu");
if (menuList.length > 0) {
window.top.$j("ul.dropdown-menu li:eq(0)").after(sspItem);
}
}
} catch(e) {
//
}
});
Now, I can actually look at the menu again without those uncomfortable Rain Man impulses to set things right:
Well, that’s it for today. If you want a copy to play around with, you can get one here.