Siebel Open UI: See-Through Applets (Part 1) Have you ever asked yourself: “Wouldn’t it be nice to be able to inspect an applet so that it reveals the underlying business component fields or even the tables and columns where the data is stored?” You haven’t? Well, I know, I have. I believe every determined Siebel developer or analyst gets a bit weary over time with the limited amount of information in the About View dialog box. Of course, we can always use Siebel Tools and navigate through the layers to retrieve the information. But this is a bit time consuming. What I am talking about is something similar to the following scenario. Here is a typical Siebel form applet (in all its Open UI glory, needless to say): Click to enlarge Now, let’s imagine you can double-click anywhere in the applet to make it “see-through”. The labels now display field name, type, length and whether they are calculated and/or required. A see-through applet, kinda NSFW. Click to enlarge. Let’s drive our imagination further into the wild and doubleclick the applet again. Now the labels display the tables and columns where the data comes from. The naked truth. Click to enlarge if you dare. And just for the sake of usability, another double-click restores the original applet labels (see first screenshot). Of course, all screenshots above are just taken out of my wild imagination. But I have been able – thanks to the new Siebel Open UI scripting framework – to create a prototype which implements this imagination quite nicely. I will tell you a bit about this prototype in this and the next post. In the first part, I will introduce how to capture the double-click on any given applet and how to display the field information instead of the label. The next post will discuss how to retrieve and display the physical database information. Let’s start with the recipe: 1. Capturing double-clicks on all form applets 2. Creating a custom global utility function 3. Get field data from the presentation model and toggle labels 1. Capturing double-clicks on all form applets Please note: The following prototype has been implemented with the sole purpose of demonstrating the capabilities of Siebel Open UI. It is NOT (repeat: “NOT”) intended for use in production systems and brainless copying/pasting of code is strongly discouraged. Having said that, we must find a way to tell all (form) applets to “listen” for double-clicks. Thanks to jQuery, we can use the dblclick event handler similar to the following: $(selector).dblclick(function() { //some clever code goes here }); Since Open UI has been released last December, a lot of examples have been written which demonstrate customizing a single applet using a custom presentation model and/or physical renderer. But this time we want to change the behavior of all form applets at once. I found only one way to accomplish this, which is by customizing the Oracle-provided phyrenderer.js file. Knowing that this is a non-standard customization, I fight an internal struggle to publish the prototype like this. If any of the astute readers can share some more insight how to customize all applets, please find the comments section quickly. So, keeping in mind that we are on thin ice here, here is the code I added to the OOB phyrenderer.js file Click to enlarge As you see, I modified the ShowUI method which is responsible of rendering the UI for form applets. Here are the key lines of code I added: var myPM = this.GetPM(); This is just customary as I like to have a handy variable instead of calling the GetPM() function over and over. The GetPM() function is a physical renderer function and returns the presentation model object. target.dblclick( function ()… I use the OOB jQuery target variable which is initialized by the Oracle-provided code earlier. It represents the entire applet DIV layer using the applet’s unique Id. Using the jQuery dblclick() event handler I can now define what happens at a double-click. As you can see in the code snippet, I use the presentation model’s Get() function to “get” the value of a property named SE_ToggleCycle which is a custom property I intend to use to determine the current toggle cycle (“Display Labels”, “Show BC Fields”, “Show Tables and Columns”). There might be more elegant ways to accomplish this but a simple switch always does the trick for me. So for example when the property SE_ToggleCycle is undefined (which it is at the time of the first double-click), I set the cycle variable to “ShowBCFields“. So at the next double-click, the cycle variable is set “ShowTableColumns“, etc… After leaving the switch, we can set the property to the current cycle code using the PM’s SetProperty() function myPM.SetProperty(“SE_ToggleCycle”,cycle); So now we have a globally accessible property we can use to determine the current toggle cycle. The logic of retrieving metadata and actually toggling the display labels is done in a custom function which we call as follows: SiebelApp.CustomUtils.ToggleLabels(cycle, myPM); The function accepts the cycle variable and the current PM object as input and we will have a look at it in a few moments. Before we leave the custom code we could trace the cycle variable to the JavaScript console using a line similar to this: SiebelJS.Log(“Current double click cycle: ” + cycle); SiebelJS.Log() is a function provided by the Open UI framework and should be used instead of the native console.log() function. Of course this is optional, but a bit of tracing should always be done in a prototype for the sake of easier debugging. For now, when we save the file and restart the Siebel application, we can actually double-click anywhere in the applet (preferably the title bar) and inspect the console log: Click to enlarge 2. Creating a custom global utility function As the requirement for our prototype is to provide global behavior, we also must implement the logic on a global scale. When you take a few minutes to inspect the Oracle-provided JavaScript files you will stumble upon a utils.js file which obviously contains a lot of utility functions. I thought it would be a good idea to mimic this approach and created my own custom_utils.js file (of course in the custom folder). Before we forget, let’s ensure that this file is always loaded by adding it to the <ROOT><COMMON> section of the custom_manifest.xml file. Click to enlarge Here is a screenshot of the custom code and I will explain the key lines below. Click to enlarge As is customary for good citizens in the Open UI framework, this code adds our CustomUtils namespace to the SiebelApp realm. if(typeof (SiebelApp.CustomUtils) === “undefined”){ Namespace(“SiebelApp.CustomUtils”); } Now we can declare the ToggleLabels() function in the new namespace SiebelApp.CustomUtils.ToggleLabels = function(cycle, myPM){}; After declaring some variables we use the current applet’s presentation model (passed by the myPM variable to get the array of controls for the applet. var arrControls = myPM.Get(“GetControls”); Let’s spend a minute on the topic of object arrays within Open UI. If you inspect the above code in the browser’s developer tools, you can see the content of the arrControls variable. The below screenshot is taken in Google Chrome but in other browsers it might be similar. Click to enlarge In the screenshot I have expanded the Account control. For each control of the current applet you can clearly see the available methods such as GetFieldName or GetDisplayName. Inspecting object arrays using the browser’s developer tools provides deep insight into the Open UI framework, a little bit deeper than the documentation writers would probably like… The next part of the code is similar to what we have seen in the phyrenderer.js file customization. Depending on the value of the cycle variable (passed to the custom function) we call different local functions. In today’s post I will further explain the first one, namely ShowBCFields(). 3. Get field data from the presentation model and toggle labels As discussed above, the goal of the prototype is to demonstrate that – with Siebel Open UI – it is fairly easy to accomplish a “see-through” applet. So the ShowBCFields() function should retrieve BC level metadata from the presentation model and manipulate the browser’s DOM (Document Object Model) so that the labels for each control display the underlying BC field name, logical type, length and whether it is required or calculated. We might first be tempted to retrieve that information from the repository but that would require a server round-trip. Good to know that the presentation model can provide us with all this information, so we can reduce load on the server. Here is the code for the ShowBCFields() function. I will discuss the key lines below. Click to enlarge The first two lines actually show how to get BC level information. If you pass “GetBusComp” to the PM’s Get() function, it will return the current applet’s underlying business component as an object. var oBC = myPM.Get(“GetBusComp”); We can use the GetFieldMap() function of the BC object to retrieve an object array which contains each field used in the current applet (so its comparatively small). var oBCFieldMap = oBC.GetFieldMap(); Again, inspecting the object arrays in the browser’s developer tools provides us with a lot of insight. Because we have to manipulate each control’s label, we must implement a for loop for each control in the controls array: for(sControlName in arrControls){} This will populate the sControlName variable with the name of the current control in the loop. After checking that the control is really a member of the array, we can instantiate the current control as an object by accessing it by name in the controls array: oControl = arrControls[sControlName]; Now we can retrieve the name of the underlying BC field: sNewLabel = oControl.GetFieldName(); If the control is a button, there is no underlying BC field, so we should exclude those: if (sNewLabel != “”){} Now we can use the field map array to retrieve the desired information. The following lines get the field’s logical data type, its length and in addition we inspect whether the field is required and/or calculated oField = oBCFieldMap[sNewLabel]; sDataType = oField.GetDataType(); sLength = oField.GetLength(); sReq = oField.IsRequired() ? “*” : “”; sCalc = oField.IsCalc() ? “C” : “”; Open UI renders control labels by replacing characters such as spaces with underscores and appending “_Label“. So in order to be able to target the label using jQuery we must do something like the following, showing off our regexp skills with the replace() function. sLabelName = sControlName.replace(/ /g,”_”) + “_Label”; This works for most of the labels, but not for those with brackets or hash (#) in the name BTW. Labels are rendered as <span> elements, so we must create a similar element but with different enclosed text. sLabelHTML = “<span id='” + sLabelName + “‘>” + sNewLabel + ” (” + sDataType + “/” + sLength + “)” + sReq + sCalc + “</span>”; As you see, we concatenate the variables collected above to a new label which looks like this for a calculated field: BCFieldName (type/length)C Now we are ready to swipe the jQuery magic wand. We declare the parent element of the label the current target: target = $(“span#” + sLabelName).parent(); then we replace the HTML with our concoction: target.html(sLabelHTML); and finally (just for the sake of demo) apply some makeup. In a real life implementation, please do not use hard-coded styles, instead use proper CSS classes. target.css({‘font-style’: ‘italic’, ‘color’: ‘#FF0000’}); And that’s it! We already know how the result looks like but it’s really stunning that it works on almost every form applet and is super-fast thanks to the Open UI framework. Click to enlarge Summary In today’s part of a two-post mini-series we explored how to teach all form applets at once to capture double-clicks. Furthermore, we introduced the comfort zone of the presentation model which allows us to retrieve all kinds of useful metadata such as BC field properties without a server round-trip. Again, please understand that all examples and code that I present on this blog are solely for illustrative purposes and that it has NOT been tested against a production system. So I hold absolutely no liability for any issues or damage should you decide to use the code presented in this blog. In the next part, we will explore how to actually do a server round-trip in order to retrieve repository metadata which is not available via the presentation model such as table and column names. have a nice day @lex