- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
01-01-2023 02:22 AM - edited 01-25-2024 07:53 PM
Let's assume there is a requirement to offer users in your ServiceNow instance with activated Next Experience UI a quick link to any already existing information page outside your ServiceNow instance.
The most prominent place for such a link would be the header bar, where we already find central functionalities like the combined Application & Update Set picker (globe icon) or the notification display (bell icon).
Unfortunately, there is no OOTB configuration available to inject another icon into the header bar. So the only way is extending the HTML code manually. And the only approach to implement something like this is creating a global UI script which waits until finished page loading to inject the required HTML code accordingly.
But first you have to decide for a certain icon. You can choose one at at https://developer.servicenow.com/dev.do#!/reference/next-experience/vancouver/now-components/now-ico...
Please note the corresponding ID of the icon (see red rectangle in the above screenshot) to insert it into the code (at number 1) I have provided below.
Then create a UI Script with the following properties:
API Name
(give any name)
UI Type
Desktop
Global
(checked)
Script
var injectCustomIcon = function (strIconId, strHtmlId, strHtmlTitle, strOnClick) {
try {
//is Next Experience UI loaded?
if (!(top.NOW && top.NOW.isPolarisWrapper === "true")) {
return;
}
//is the icon already injected?
if (typeof window.top.custom_icon_injected !== 'undefined') {
return;
}
var objElement = window.top.document;
//search for the DOM element for the icon bar
[
'macroponent-f51912f4c700201072b211d4d8c26010', 'shadowRoot',
'sn-polaris-layout', 'shadowRoot',
'sn-polaris-header', 'shadowRoot',
'.utility-menu'
].forEach(function (strId) {
if (!objElement) {
return;
}
objElement = strId === 'shadowRoot' ? objElement.shadowRoot : objElement.querySelector(strId);
});
//inject HTML code for the custom icon
if (objElement) {
jQuery(objElement).prepend(
'<span role="button" tabindex="0" class="contextual-zone-button polaris-enabled" ' +
'id="' + strHtmlId + '" aria-label="' + strHtmlTitle + '" ' +
'onclick="' + strOnClick + '" ' +
'title="' + strHtmlTitle + '" ' +
'aria-describedby="contextual_zone_' + strHtmlId + '_button" ' +
'aria-expanded="false"' +
'>' +
'<now-icon class="contextual-zone-icon" icon="' + strIconId + '" dir="ltr"></now-icon>' +
'<now-tooltip ' +
'id="' + strHtmlId + '-tooltip" ' +
'aria-label="' + strHtmlTitle + '" ' +
'role="tooltip" dir="ltr" aria-hidden="true">' +
'</now-tooltip>' +
'</span>'
);
top.custom_icon_injected = true;
}
}
catch (e) {
console.error(e);
}
}
//after finished loading the page inject custom icon
if (typeof jQuery === 'function') {
jQuery(document).ready(
injectCustomIcon(
/* (1) ad the ID of the chosen icon */
'circle-info-outline',
/* (2) HTML ID of the created icon */
'my_custom_icon',
/* (3) text to display when hovering over the icon */
'My custom icon. Click to action!',
/* (4) performed action when clicking on the icon */
'window.open(\'https://www.servicenow.com\', \'_blank\');'
)
);
}
At the end of the above script, you can see four parameters for the method injectCustomIcon() you have to adapt to your needs.
- 4,562 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for this Maik. I'm curious as to how you recommend running the script.
Should the script run...
- from a form
- call it in the HTML
- or call the script from client side code?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
you just create the UI Script as described by me. ServiceNow will then execute that UI Script each time you open any page.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for the quick response @Maik Skoddow but unfortunately that didn't work for me.
I wrote the code by hand initially and pasted what you wrote after that didn't work. I put an alert() in the function and did a search for the classes of the element in the DOM. Neither worked.
I'll keep at it and post what I find. Thanks again for posting this. Very cool!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@Maik Skoddow thank you for your great content but I have a question, how can we make it work for pages like "pa_dashboards_overview", those pages are rendered in an iframe, and UI scripts don't look like running in there.
"/now/nav/ui/classic/params/target/%24pa_dashboards_overview.do"
"/now/nav/ui/classic/params/target/%24ciModel.do"
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I am in the Tokyo release, and i literally copied your code and pasted it into a UI Script, and it doesnt show anything. am i doing something wrong?
once i get it to work ill customize those last 4 lines, but no point in doing that if i cant get it to work..
EDIT:
after playing with alerts, this is kicking me out:
if (!(top.NOW && top.NOW.isUsingPolaris && top.NOW.isPolarisWrapper === "true")) {
return;
}
i am on the new next experience, why would that be kicking me out?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Many thanks for this find. It seems that
top.NOW.isUsingPolaris
doesn't exist anymore.
Therefore, I have removed it from the code and also enclosed everything in a try-catch-block because a broken UI Script can prevent you from logging into your instance.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Yes this is right. If you enter the instance via a deep link to a Dashboard then the UI Script is not triggered. Only when opening a list or form view the UI Script will kick in. This cannot be changed and other extensions like "XPlore" have the same issue.
The only workaround I can imagine is placing a static HTML block on your dashboard that executes the given code.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
i got around the check for next experience ui by using the user preferences to see if they are on the new experience:
var ga2 = new GlideAjax("CheckUser");
ga2.addParam('sysparm_name', 'u_NextExperience');
ga2.getXMLWait();
var Experience = ga2.getAnswer();
//is Next Experience UI loaded?
if (!(Experience === "true")) {
return;
}
CheckUser SI: (Client Callable, global, all application scopes)
var CheckUser = Class.create();
CheckUser.prototype = Object.extendsObject(AbstractAjaxProcessor, {
u_user: function() {
return gs.getUserID();
},
u_userName: function(){
return gs.getUserName();
},
u_hasRole: function(role) {
if(role == undefined || role=="")role = this.getParameter("sysparm_role");
return gs.hasRole(role);
},
u_NextExperience: function(){
var userPreference = gs.getUser().getPreference('glide.ui.polaris.use');
return userPreference;
},
type: 'CheckUser'
});
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
Somebody know how to, still add an icon, but at another place? because if you try to replace "prepend" by "append"
jQuery(objElement).append( ..... )
all sub-menus are shifted to the top arrow (in this example, when i click on the "user" icon, the arrow is shifter)
My try is to add a new icon, between the "notification" icon and the "user" icon
Thanks
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@Maik Skoddow, I truly appreciate the helpful script you provided! I’m excited to see more like this in the future. Thank you!.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@Maik Skoddow This script is causing overflow menu issues and profile icon visibility issue on the global header if the screen resolution is small like in laptop screens.
I understand DOM manipulation is not supported by ServiceNow.
is there any way we can fix the issues?