Showing posts with label Config. Show all posts
Showing posts with label Config. Show all posts

EAI Phone Format Challenge feat. BRP

Over two years ago, I issued a challenge to the Siebel community, through the EAI Scriptless phone number challenge.

The original challenge was started by a reader from Siebel Essentials's scriptless challenge, which was to find a scriptless solution to strip off the formatting from a DTYPE_PHONE, and leave the raw phone number.

The challenge that I subsequently issued to the community was to find go further and find a solution which applies the format mask to the phone number without any scripting.

At the conclusion of the challenge, I presented a 35 line recursive XSLT template that demonstrated that while it is possible to go to the end of the earth to find a scriptless solution, a 10 liner business service would have between more maintainable, given that most Siebel professionals don't spend their time swimming in stylesheets.

I know that our conservative Siebel readership wont sleep well with the scripted solution, so I've been working hard on an alternate solution that will please all our declarative readers out there, and also impress the eScript Jedi's and hopefully convert them back to the light side.

Here is the challenge outlined again.

"+610212345678[LF](00) 0000 0000"

The system must take the above DTYPE_PHONE value and convert it to (02) 1234 5678 without any scripting.

Note that the DTYPE_PHONE consists of the raw number + a line feed character + a format mask with the zeros representing the position of the number, any non zero characters represent a formatting character that must also be applied to the formatted string.

[Business Rules Processor]

This requirement can be achieved by using Business Rules Processsor (BRP).

BRP was introduced to Siebel as a FINS module around v7.8. It provides a fully declarative means of processing complex business logic.

This is an except from bookshelf about the capabilities of the BRP engine.

"The Business Rule Processor features include:

* Business logic administration through the application user interface.

* Appropriate for complex business logic; supports procedure, loops, if-then-else and switch-case constructs.

* Appropriate for business logic that changes frequently. You can modify business logic without deploying a new SRF.

* Query, read, and write access to business components.

* Error handling.

* Support logging at multiple levels for easy testing and debugging.

* Can potentially replace large amounts of custom scripts."

That list is pretty impressive, but is it up to our challenge?

Here is the psuedo code for rule that we are going to implement.

1. Separate the DTYPE_PHONE into separate PHONE and FORMAT components

2. Start at the last character of the FORMAT component

3. If the character is a Zero, then take the corresponding character in the PHONE component and store it in RESULT

4. If the character is non-Zero then take the current FORMAT character and store it in RESULT

5. Move to the next preceding character and continue processing until no FORMAT characters are left

[Solution]

1. Goto the Business Rule Processor Screen

a. Create a new process called "EAI Phone Format"
b. Create the variables for our rule as shown in the screenshot below


2. Goto the Procedure view

a. Create a procedure called "DeterminePhoneString"
b. Create a procedure called "Main" and set this as the Entry procedure into this rule.
c. Create 4 steps as shown


3. 1st Step - Get CRLF character

Here we call the SSE Address Parser BS to get our CRLF character and assign it to the sCRLFChar property.


4. 2nd Step - Init variables

We initialise and setup all the variables before we start our routine.


5. 3rd Step - Loop through pattern

We define a loop that iterates through the pattern backwards, until our cursor reaches the beginning. On each iteration, it will call "DeterminePhoneString".


6. 4th Step - Set remainder of the string to the final output (Optional)



7. Define the "DeterminePhoneString" procedure

Create a switch statement with the following logic


8. Create a default branch for our switch statement



9. Activate your rule, and test it in BS simulator using "FINS CAP Processor Service"



[Conclusion]

I've only scratched the surface of BRPs features here with this example, but amongst some of the more interesting features, BRP introduces a new property type called 'Vectors" which provides quick access to a hash table like reference, which is populated directly from a BC.

Is BRP the holy grail of declarative configuration?, In my opinion no. When used badly, the problems associated with scripting will only be shifted to a declarative interface. As with scripting, BRP can be the source of duplication and spaghetti procedures.

BRP is also limited by its expressions, and does not support custom functions, so you will still need script to provide a wholistic solution. Eg. Regex is not supported, so performing email validation still requires you to call a business service.

Scripting can be used for good, but too often it falls in the hands of in-experienced developers, which is why I really like BRP. It can be picked up really quickly by beginners, as it utilises the Siebel Query Language, and provides the flexibility of eScript through declarative loops, if/else/switch conditional statements and procedures. It also forces developers to break down their routines to manageble statements that improve readability of the design.

Where BRP really shines, is the capability it provides to developers to implement the majority of requirements with programming constructs but in a declarative interface, and more importantly since the logic is outside the SRF, changes to business logic can be made outside of releases.

Funky Town: Inline Field Validation

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

In this article, I look at another outrageous business requirement - Inline field validation.

Imagine typing in an email address, and as soon as you step off, the field turns red, and a tooltip style message appears, stating that your input does not meet the proper standard for an email address.



Inline field validation provides many benefits

1. Immediate help for the user
2. Affirmation that the user is doing the right thing
3. Assists complex data input requirements
4. Improves user experience
5. No server round trip required
6. Makes Siebel a joy to work with!

This is the sort of thing you see on fancy web forms, and only BA's will dream this requirement up because Siebel is a simple web application right?. Lets see how we can provide this functionality for them.

[Solution]

This solution will only work for form applets, so open up any form applet, and designate a field that will act as your "email address", for this exercise your field dosnt actually be an email field.

1. Put the following code in your email field control OnBlur handler
validateEmail(applet,id);

2. Add the following browser script to your applet
function validateEmail(applet,id){
    try{
        var sValue = applet.FindControl(id).GetValue();
        var oDoc = applet.FindActiveXControl(id).document;
   var oToolTip = oDoc.getElementById("Tooltip");
        if(sValue.length>0&&sValue.indexOf("@")==-1){//insert fancy email validation routine here
       if(!oToolTip){
           var oToolTip=oDoc.createElement("div");
           oToolTip.innerHTML=" Please enter a valid Email address eg. Jason@EuroDiscoFan.com";
           oToolTip.id="Tooltip";
           oToolTip.style.backgroundColor="#fff";
           oToolTip.style.color="#000";
           oToolTip.style.padding="10px 40px";
           oToolTip.style.borderStyle="solid";
oToolTip.style.borderColor="#bbb";
oToolTip.style.borderWidth="10px";
           var oHeader = oDoc.getElementById("SectionHeaderId");
           if(oHeader) {
                oHeader.parentNode.parentNode.appendChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ff0000");
            }
         }
        }else{
            if(oToolTip){
                oToolTip.parentNode.removeChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ffffff");
            }

        }
    }catch(e){
    }

}

3. Create a section header for your form, add the following in the caption override
<span id="SectionHeaderId">My Funky Form</span>

Re-compile your applet, and type in some junk in your email field. As soon as you step off, your field will turn red, and a message will appear to notify of the error.

Suffice to say, the email routine that I used above is not foolproof ^_*, but you get the idea. A more wholistic solution would look at validation from a general perspective, but that is left to the reader to run with.

[Conclusion]

1. Will it perform well?
Yes, there are no server calls.

2. Is it maintainable?
Yes, if the code is made production ready, and all the validation routines are centralised.

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and

4. Is it sexy?
Yes, its a BA's dream come true

Funky Town: Sexy Salutation

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Background]

On the Application Home page screen, Siebel provides us with the ability to close individual Applets, and hide them from the home page. Applets can also be hidden by default in the View definition, and users can display the applets again through the Edit Layout view.

This is actually what a home page actually looks like when you hide all the applets.

To the uninitiated, it looks like the data has disappeared or deleted! Surely this cant pass UAT, yes laugh it off, give your users some training and tell them not to party on the weekends and come to work switched off. However you may take an important design principle to heart - Design for the lowest denominator.

How about we give our users a friendly message that reminds them their data is not goneski, its just not visible.

This message will dynamically appear when there are no applets displayed, and slide down smoothly like an accordian, just to give your users that feelgood feeling, and make them wonder why other parts of Siebel is not sexy like this view.

This solutions relies on a Javascript library called jQuery, which allows the developer to easily select and manipulate DOM elements. Never heard of jQuery? You are probably one of those people who are stuck in a web time warp from early 2000s. Circa 2003, there was an explosion of JS frameworks, that provided web developers a new level of abstraction on JS which provided developers with the tools to achieve easy cross browser compatability, stream line their code, and focus on functionality.

Is it production ready? Dont worry, you'll be in good company. Dont hesitate, get it now, and learn it.

Implementation

1. Download jQuery, and include it into your top object

This can be done in application start or a common Page container web template. If you are taking the latter approach back this file up.

2. Identify the web template that your Home Page View is based on

I should now stress that you should not put any javascript logic in your web templates. Any javascript logic should be offloaded into an external file for performance, maintainability and upgrade reasons (In this case the latter is more important than the rest). Plan this out carefully before you attempt to implement this solution.

3. Put the following code in the external file that handles all your home page behaviour

function j(expr){
return top.$(expr,document);//references the top.$ that was loaded in step 1.
}
j(document).ready(function(){//waits for the home page document to finish loading
try{
if(j("[class*='AppletStyle']").length===1){//if the number of applets rendered is 1 (ie Only the Edit Layout Applet is shown), display our fancy message.
var sText = "Your Home Page data is currently on holidays.

"+
"If you would like to see your data, click on the 'Edit Layout' button, then click ";
var sDiv="

";
j("div.Welcome").append(sDiv);//attach a fancy message
j("div#Msg").slideToggle();//use some jQuery magic to make the message animate by sliding down.
}
}catch(e){
}
});

If you loaded jQuery from your Application, you'll have to re-compile, otherwise, if the library is loaded from your web template, you'll just need to re-start your dedicated client, or restart the server, if you are implementing this on the server.

The "beauty" of this solution is that there is no clunky server side co-ordination, and all the logic is performed client side, so it performance translates to a silky smooth experience.

Conclusion

1. Will it perform well?
Yes, no server side components were abused to deliver this functionality

2. Is it maintainable?
Yes, just like web templates, images and other external configuration

3. Can it be upgraded?
Yes. Dont put your code in your templates. Make the effort to offload this to an external file, otherwise dont do it at all.

and

4. Is it sexy?
It is fun and sexy.

Funky Town: Custom UI Extension

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Background]

I was commissioned to design a custom Integration framework for a client. As part of this framework, the client needed to have a test harness that allows:

1. The developer to generate a pre-populated SOAP request for any predefined Siebel Web Service, with run time data and authentication headers.

2. Allow the developer to send the request and see the SOAP response in real time in the UI

3. They should also be able to modify the SOAP request on the fly and re-submit the message

4. and all of the above for XML over MQ as well

The design needed to load a run time data into the request, but the test data itself was transient and did'nt need to be saved. The size of the payloads are always unknown, especially when dealing with binary encoded data, the response would be massive, so I needed a way of storing unlimited data on the UI.

The closest thing that resembled what i wanted is the Script Editor Applet (Business Service Script Editor Applet2) under Business Service - Administration. Its just an applet with a massive text area, however the field that it maps to has a physical limit.

The idea was to design a custom IE window that could load the request message based on some predefined integration settings, allow the user to modify the request through a text area field, submit it to the transport, read the response and display it on the custom UI window.

This article will focus on how to build a custom window and handle the two way communication between the custom client and Siebel server. Details around integration points in Siebel will be glossed over.

[Design]

This is what the finished product looks like.



1. The chain of events starts when the user clicks on a button called "Launch Harness" which invokes "TestIntegrationCall" to launch our custom window.

a) On WebApplet_PreInvokeMethod of "TestIntegrationCall", we call a process that Generates Request message

In code it would look like this

switch(MethodName){
case "TestIntegrationCall":
//Generate a sample request XML and store it in a Profile Attribute that can be access by the browser
TheApplication().SetProfileAttr("REQUEST_MSG",[Your Request Msg]);
break;
}


b) On Applet_InvokeMethod TestIntegrationCall, we create an IE Window with the following code

//Browser Declarations
var results;

//Applet_InvokeMethod

switch(name){
case "TestIntegrationCall":
results=window.open('','Test Harness','height=600,width=900,scrollbar=yes,resizeable=yes');
var sendButton = "<input type='button' value='Send Request' onclick='opener.sendServerRequest(this)' /><br />";
var requestXML = "<textarea id='request' name='request' rows='30' cols='50'>"+ theApplication().GetProfileAttr("REQUEST_MSG")+"</textarea>";
var responseXML = "<textarea id='response' name='response' rows='30' cols='50'>"+ theApplication().GetProfileAttr("RESPONSE_MSG")+"</textarea>";

var html = "<title>Test Harness</title>"+
"<body style='background-color:#bbbbbb'>"+info+"<table><tr><td>"+requestButton+requestXML+"</td>"+
"<td>"+responseButton+responseXML+"</td></tr></table><br />"+sendButton+"</body>";
results.document.write(html);
results.focus();
results.document.close();
theApplication().SetProfileAttr("REQUEST_MSG","");
theApplication().SetProfileAttr("RESPONSE_MSG","");
break;
}


2. Using the "requestXML" variable in the step above, the Request message is injected into the 1st text area as part of the IE window creation process.

3. Applet_PreInvokeMethod SendRequest
Do nothing.

4. Applet_InvokeMethod SendRequest
Invoke a browser function that will invoke a server method that will initiate the integration call

This is initiated, from the "Send Request" button on our new created UI, which was created in Step 1b.

var sendButton = "<input type='button' value='Send Request' onclick='opener.sendServerRequest(this)' /><br />";

When the user clicks on "Send Request", it will use the "opener" method to lookup the parent window, which is the Form Applet and call the
sendServerRequest
browser function which is defined on the Form Applet as so.

function sendServerRequest(win)
{
var requestXMLStr = win.document.getElementById("request").value;
theApplication().SetProfileAttr("REQUEST_MSG",requestXMLStr);
applet.InvokeMethod("SendRequest");
theApplication().SetProfileAttr("REQUEST_MSG","");
}

Notice that we pass in "this", which is the handle to our custom IE window, this lets us read the values from our custom window.
The first line grabs the XML request from our text area, and calls a server side event.

case "SendRequest":
//Get Request String from our custom IE window
//Convert to correct format and calls the interface

5. The above code will make the interface call and return the results back to our Form Applet, which will convert the Output to a string and store it in a ProfileAttribute which will be accessed by browser script to inject back into our custom IE window as shown in the next step.

6. Get the handle for the IE window, and inject the results into the 2nd text area

case "SendRequest":
var responseXMLStr = theApplication().GetProfileAttr("RESPONSE_MSG");
results.document.getElementById("response").value = responseXMLStr;
theApplication().SetProfileAttr("RESPONSE_MSG", "");
break;


Here are the sequence of events again

Open test harness

1. Browser PreInvoke TestIntegrationCall - Do nothing
2. Server PreInvoke TestIntegrationCall - Generate Request message and convert to string
3. Browser Invoke TestIntegrationCall - Construct IE window and Request message
4. Server Invoke TestIntegrationCall - Do nothing

Send request

1. Browser PreInvoke SendRequest - Do nothing
2. Server PreInvoke SendRequest - Call interface
3. Browser Invoke SendRequest - Injects the response into our Custom IE window
4. Server Invoke SendRequest - Do nothing

[Conclusion]

We have just designed a complex, yet highly unique and functional test harness to assist developers in their day to day jobs, however the concept of a custom UI window can be extended to any part of the application that requires features that are not available out of the box.

Lets look at our criteria again

1. Will it perform well?
N/A. It is a fit for purpose utility

2. Is it maintainable?
Yes, if the code is made production ready

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and

4. Is it sexy?
It is a no contest, it is like beauty and the beast.

Funky Town: Friendly Siebel Applets

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

[Scenario]

The business wanted yet another button on a common applet, but the applet was already crowded with buttons (pictured below). The plan was to consolidate the functionality behind the different buttons, and reduce the clutter on this applet, as it was becoming a real eye sore.



I advised on removing the last two buttons, as they were too specific and its appropriateness was questionable, but i was told that users loved those buttons as they are the two most heavily used buttons in the application! Since the client was paying my wages, who am I to argue?

The second idea was to combine the 3 search buttons into one, since they all perform the same basic functionality "Search"

"Search Client Id"
"Search Client Name"
"Search Client Address"

The problem was, in the current design, the above buttons each invoked a separate VBC Search applet which called an external interface that only allowed mutually exclusive queries by Id, Name or Address, which is why they were designed separately in the beginning.

The agreed design going forward, was to combine all the fields of the above 3 applets into one super search applet, but we needed a way of preventing the user from entering data into different search categories on the same interface call.

The standard approach is to use validation to return an error message when the user hit the "Submit" button. This option achieves the requirement, but it provides a horrible user experience. Imagine the user filling in every section of the form, because it allowed them to, but when they click "Submit", an error pops up, the form is returned to the user, and they have to go through and re-fill the form correctly.

We should aim to design our application to be more intuitive (take inspiration from what Apple did with the Smart phone market =), so the proposed design was to have the fields in the relevant section dynamically became read only or read write as the user typed, this will block out fields that cannot not be filled in.

[Requirement]

a) There are 3 sections, A, B & C on a Search applet.

When the user begins typing in any one section, all the fields in the other two sections should be disabled.



Eg.
If a user types something in a field under section A, all the fields in section B&C would be disabled.

If a user types something in a field under section B, all the fields in section A&C would be disabled.

If a user types something in a field under section C, all the fields in section A&B would be disabled.

b) When the user clears the all field values from any section, all the fields in the entire applet should be re-enabled again.

[Solution]

In HI, there are two control events that are usable on form applets.

onBlur
onFocus

We will use onBlur, because when the user moves from one field to the next, we can implement logic to dynamically enable or disable the rest of the fields on the applet.

Firstly put in our trigger on each control that is editable by the user, put the following code in the onBlur handler

setSectionReadOnly( [section id] );

[section id] is a predefined identifier that you assign to each section in the form. It can be called anything. In our form applet, there are 3 sections, which we'll call a, b, c.

So for all the fields under section "a", you would put the following in each fields onBlur handler

setSectionReadOnly("a");

For every field under section "b", you would put

setSectionReadOnly("b");

and so on.. what this does, is tell our yet to be created function, that every time the user leaves an editable field, send the current field section to our function to determine the UI behaviour.

Now we define the function that is responsible fore enabling/disabling the fields dynamically.

declarations()
var thisApplet = this;

function setSectionReadOnly(sSection)
{
//control object defining allowable applet search sections
var oCTRL = {};
oCTRL.a = ["Id Type","Id Num"];
oCTRL.b = ["Family Name","Given Name"];
oCTRL.c = ["Address Line 1","Address Line 2","Address Line 3", "Address Line 4"];
var bNotEmpty = false;
try {
//check current search section for existence of a search value
for (var i=0;oCTRL[sSection].length>i;i++){
if (thisApplet.FindControl(oCTRL[sSection][i]).GetProperty("ReadOnly")=="true")
return;//abort if active field is RO
if (ctrl.GetValue().length>0){
bNotEmpty=true;//flag first non empty field
break;
}
}

//if current search section has a search value make every other section RO
if (bNotEmpty){
for (var key in oCTRL){
if (sSection!==key){
for (var i=0;oCTRL[key].length>i;i++){
thisApplet.FindControl(oCTRL[key][i]).SetProperty("ReadOnly", "TRUE");
}
}
}
} else {//if current search section is empty then make the whole applet RW
for (var key in oCTRL){
for (var i=0;oCTRL[key].length>i;i++){
thisApplet.FindControl(oCTRL[key][i]).SetProperty("ReadOnly", "FALSE");
}
}
}
}
catch(e) {
//handle error
}
}


Compile your super friendly search applet, and watch your users frustration disappear =). I'm sure you'll agree that dynamically disabling irrelevant fields, and preventing users from entering invalid data is much more friendly, than allowing them to enter invalid data, and complain that the user got it wrong afterwards.

The implementation in this example, was used to illustrate a working concept, there are numerous ways of optimizing this code to perform better, so it should not be copy and pasted across your application.

[Conclusion]

1. Will it perform well?
Yes, there are no server calls, and all the magic happens client side, saving a round trip to the server.

2. Is it maintainable?
Yes, if the logic is made production ready

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and finally the litmus test

4. Is it sexy?
Yes, and it is also very intuitive

Server Confirm dialog (Scriptless)

[Background]

Every Siebel professional knows that its impossible to get input from the user using Server script. The rationale is that server script runs on the server, and theres no way that it can pop something up on the client. Whats more ludicrous is to do it without any script.

Google for "Siebel Confirm" and you'll get a bunch of results stating that this is only possible using Browser Script.

Search in support web and you'll probably end up with these documents

1. How Should You Implement Message and Input Boxes in Siebel 7 and Siebel 8? [ID 476612.1]

2. How Can You Display a Message from a Server Script on the Browser? [ID 477323.1]

The conclusion is the same:

"Interactive dialog boxes are features that belong to the JavaScript language and can only be launched from browser script"

That sounds like solid advice, so would you believe me, if i told you that its possible to invoke a Confirm dialog from the server, using out of the box functionality?

Did i hear someone say "NO"!? Okay, that might have been my sub conscious.

If you are not convinced, let me introduce you to an undocumented business service that does just this.

[Confirm Dialog Business Service]

Business Service: LS Pharma Signature UI Service
Method Name:
ShowConfirmDialog

Open up Siebel and goto your business service simulator, and load up the following values

Inputs:
Cancel Method Name:
MyCustomMethod1
Confirm Text:
Winona, will you marry me?
OK Method Name:MyCustomMethod2

Your view should look like this.



Click run, and VOILA.



This produces an Ok,Cancel dialog that can be used across the application, but best of all, it is scriptless.

Now click either button, and you should get an error.


This happens because we havnt configured the application to handle these custom events, but lets try to invoke methods that we do know exist, and we'll perform some real configuration instead of basing our results off the simulator.

[Configuration]


Find your favourite BC and add the following user property, this will enable a custom method, and call the business service to display our Confirm Dialog.

Named Method

"InvokeAction", "INVOKESVC", "WS Transaction Settings", "LS Pharma Signature UI Service", "ShowConfirmDialog", "'Cancel Method Name'", "'NewRecord'", "'Confirm Text'", "'Hello'", "'OK Method Name'", "'DeleteRecord'"

Next find your favourite applet, and add a new button and set the following property:

Method Invoked: InvokeAction

The Ok and Cancel method definitions, will fire the respective events from the Applet to the BC, and from Browser to the Server, just like normal events, which you can subsequently trap and perform the intended action, based on the user response.

[Results]

NewRecord
This creates a new record in the applet

NewQuery This toggles the applet into Query mode

DeleteRecord
Interestingly, this brings up another confirm dialog. Infact, it looks damn similiar my own confirm dialog, except for the question text.

[Conclusion]


If you look hard enough, you'll find examples of this all over the application, heres another business service that does the same thing, except the message, and return codes are hard coded

Business Service: LS SubjectVisits Service
Method Name: ShowConfirmationDlg

This raises a few questions in my mind

1. Why isnt this documented?
2. Can we have control over how the dialogs are presented?
3. Can we display a message or prompt dialog in the same manner?

Maybe someone from Oracle engineering can answer this, but suffice to say, this is a great little nugget for Impossible Siebel readers.

On a closing note, if you would like more pizazz in your popups, change the buttons or add an icon, have a read of Alex's UMF Series, on Siebel Essentials. It should cover my requirements above.

Siebel Unified Messaging Framework - Part 1

Siebel Unified Messaging Framework - Part 2

Solution - Mouseover Tooltips (Scriptless) Part 1

I've been receiving a lot of requests from Siebel professionals to provide the solution to the tooltips challenge, and though i've provided the solution privately to needing customers, i've realised that implementing it can be tricky, so in this article so i'll provide a walkthrough of the fundamental configuration needed to achieve a basic solution.

[Background]

To provide some perspective on this problem, lets have a look at a real life scenario from a customer on the Oracle forums.

"We have been struggling with a user request:

The users have requested that we change default Siebel Tooltip behavior so that if we hover the mouse over some select fields(In this case a credit code, among others) that the tooltip contain information that can help the user to understand the value. Whether this is the definition of the actual value or a short list of actual values is still up for debate. Alternate approaches like populating the status bar with a value, theoretically the definition of the current value, and providing a help icon with a tooltip or message that contains reference info for the column below, have been discussed, but these are not preferred.

So has anyone ever tried to highjack the tooltip functionality? I'm not going to say that the existing functionality (Displaying the full value of the current field) isn't useful in many cases, but that functionality is useful for the codes that we are looking at(WHich are typically smaller then the existing field) and this would be a far better use of the functionality.
"

source: http://forums.oracle.com/forums/thread.jspa?threadID=577955&tstart=525

[Million dollar system]

The Siebel UI can be quite overwhelming, so its understandable that business want to implement tooltips, to provide its users with visual clues and help the user perform their duties. This is the one requirement that every BA has asked once in their Siebel career.

But when the business ask for a simple feature such as floating tooltips, and we say its not possible. It becomes a little embarasing, when they ask why a system, they've spent millions of dollars on, cant offer tooltips, which have been around since the beginning of the web.

[Workaround]

A primitive technical solution to this, is to utilise the caption override on the label, and hard code text into the alt or title attributes.
<span alt='Disco Forever'>Disco</a>

This dosnt meet the requirement of the impossible challenge, but it also has an annoying side effect, in that the tooltip vanishes too soon. So if you want to provide a few lines of text for the user to read, they'll have roughly 5 seconds to read it all, before it disappears.

Some readers have reasonably guessed that we need to use the onmouseover and onmouseout events in browser script control events to deliver this solution, as it is the most obvious mechanism to create a floating dialog, however the only problem is, these browser events are not available in HI environments, and it also involves scripting.

But read on, and i'll show you how to bypass these obstacles.

[Solution]

To get around the HI browser events limitation, we can inject custom onmouseover and onmouseout events on the label caption as so.
<p onmouseover='<Show our tooltip>' onmouseout='<Hide our tooltip>'>Disco</p>

This lays the foundation for the rest of the challenge, and offers us the launchpad to use some HTML magic to display our tooltips.

Here is the caption override that is needed to display a tooltip.
<p onmouseover='var d=document.createElement("div");d.id="t";d.innerHTML="yeah";this.appendChild(d);' onmouseout='var d = document.getElementById("t");d.parentNode.removeChild(d);'>Disco</p>

What the above syntax does, is creates a DIV element on the fly and injects it underneath the current object, which in this case is our field label object.

Our label now has two custom events that will fire off code to display and hide the tooltip accordingly. The tooltip will hang around as long as the mouse cursor is hovered over the label, and disappear swiftly when the mouse moves away.

But lets not celebrate so soon, because this solution has the following draw backs, the tooltip text is limited by the repository length of the caption field, our creativity with the tooltips is also severely limited by the caption length, and hard coding the text here would make it difficult to maintain.

We can dress it up by adding a little style
<p onmouseover='var d=document.createElement("div");d.id="t";d.innerHTML="yeah";d.style.backgroundColor="red";d.style.borderColor="black";this.appendChild(d);' onmouseout='var d=document.getElementById("t");d.parentNode.removeChild(d);'>Disco</p>

This looks a little better, but uses it up every (255) valuable character, and leaves no room for a useful tooltip.

This is the most "vanilla" result, and is not very useful, but it does provide the basic framework for others wishing to get further with this challenge.

[Until next week]

The most important hurdles have been taken away

1) Mechanism to Display/hide a persistent floating tooltip
2) Achieved by using a caption "expression" and hence Scriptless

But the following aspects of the challenge remain un-met

3) Unlimited text
4) Dynamic text

In the next article, i'll provide the full solution and bust the myth that Siebel cant do tooltips.

Reader Challenge - Mouseover Tooltips (Scriptless)

[Requirement]

Display a floating tool tip with dynamic text, when a user hovers over a form applet label or image in High Interactivity.



[The challenge]

Our earliest followers will remember this requirement as one of the Impossible tasks on our first poll (which was won by the Scriptless VBC).

I'm sure veteran configuraters, get asked this requirement all the time from green BAs.

Does it sound impossible? It should, because mouseover interactions are not supported in HI, and to make this more interesting, lets add a condition to make this a scriptless challenge. We havnt had a scriptless challege since the "EAI Phone format challenge"

By scriptless, i'm going to borrow @lex's definition:

"I define 'scripting' as the attempt to solve requirements such as automation, validation or integration in Siebel CRM by inserting custom code into the event handlers exposed by the Siebel application.

As we all know, Siebel CRM has four object types that expose event handlers:

* Applet
* Application
* Business Component
* Business Service
"


I should also mention that, there should be no scripting or CSS changes to the Siebel browser framework, everything should be configured inside of tools.

The following screenshot shows an example of an advanced tooltip, that i configured earlier.



[Update]

This tooltip should not dissapear after 5 seconds. ie, if there is paragraph of text, it should allow the user ample time to read the tooltip!

Have fun.

User Question: How to use an OR condition in a WF decision step

[Possible Siebel?]



A reader from Texas, US, asked "How to use an OR condition in Siebel workflow decision point".

[Answer]
By default, every WF condition is binded to the 'AND' operator.

To perform an 'OR' condition, compose a condition using the following values

Compare To: Expression
Operation: <Use the default>
Object: <Blank>
Field: <Blank>
Values: Enter your 'OR' expression in here

Eg.

Suppress menu item across the entire application

Requirement

Remove the "Save Target List", "Applet Target List", "Apply List" and "Save List" options from the applet menu.

These options are on the Siebel 8 menus and enabled by default, the problem is that there are 500+ applets, and we needed a global solution to remove them from the entire application.



A SR was lodged and the solution from Siebel was simple, go into the 500+ applets and disable the menu items individually. This was not exactly the practicle solution that we were after.

For customers out there who have similiar requirements to remove items from the menu. Here are 2 alternative global configuration options that allow us to achieve the above requirement.

1. PreCanInvoke on Command Object

Co-incidently Alex from Siebel Essentials has highlighted this behaviour in his recent post.

We can disable or enable a menu command by configuring the PreCanInvoke of the Business Service that the command calls. This is what the command object for our menu item looks like.



We can see that "Apply Target List", "Save Target List" and "Save List" call methods on the Business Service "SLM Save List Service". To disable both of these menu items, we can use the following PreCanInvoke code to grey out these options in the menu.

function Service_PreCanInvokeMethod (MethodName, &CanInvoke)
{
var iOperation = ContinueOperation;

switch(MethodName)
{
case "CreateSaveListPopup":
case "CreateApplyListPopup":
CanInvoke = false;
iOperation = CancelOperation;
break;
}

return (iOperation);
}


"Apply List" seem little tricker because it dosnt call a Business Service, instead it calls a class method. Since we dont need this command anymore, we can just override the Method and Arguments with the Business Service and Method that we have just disabled.



This allows the command to utilize the PreCanInvoke powers of the Business Service to grey our desired menu items. If you are concerned that the business service you are disabling is used elsewhere in the Application. You can always substitute it with a dummy Business Service with disabled methods.

2. Supress Menu Item from Applet Class

This option was provided by JM, an ever resourceful colleague. This technique entails that we go directly to the class object that all list applets inherit, and disable the menu item from there.

Simple and elegant!

Navigate to the Class "CSSSWEFrameList", and goto the Class Method Menu Item object, you will see the following options.



Click the "Supress Menu Item" option for these menu items, and re-compile. You will notice that instead of being greyed out, the menu items have dissppeared.

Remember that this technique hides the menu item, it dosnt disable them. So if you have keyboard accelerators for your commands, the user can still invoke the action using the shortcuts, unless those are disabled as well.

To finish the job, we need to also disable the options from the Application Menu, this can be done by disabling the menu item from the Menu "Generic Web".




Conclusion

Both these solutions allow you to disable the menu items globally in the application.

The first option has the advantage that you can conditionally enable and disable these commands based on condition, while the second option is nicer if you dont need the menu item at all.

Solution - Show creator full name on 'About Record Applet'

Impossible reader Sajan, has responded to the 'About Record Applet' Challenge.

The solution Sajan shares, higlights the use of ShowControl.

The WebApplet_ShowControl event is only supported in Standard interactivity, and allows us to modify a control as it is being rendered to the user.

By trapping this event, Sajan can intercept the rendering of the Created By and Last Updated By fields, send the login Id off to a server script function to resolve it to a persons name, then inject the value back into the HTML stream on the fly.

Sajan's solution

//Object: Applet
//Object Name: About Record Applet
//Event: WebApplet_ShowControl
//Script: Server Side

function WebApplet_ShowControl (ControlName, Property, Mode, &HTML)
{
if ((ControlName == "CreatedBy") && (Property == "FormattedHtml"))
{

var temp =HTML;

//Capture the LOGIN only
var temp1=temp.substring(temp.indexOf(">"));
loginid= temp1.substring(1,temp1.indexOf("<"));

//Method to pull Full Name based on the Login
HTML = fetchfullname(loginid);
}
}

This technique is useful for tricky client automation problems, and can be used to perform more complex logic, by injecting javascript into the HTML, which executes when it loads in the users browser.

Why would we want to do this?

  • Auto-completing fields
  • Auto submitting a form
  • Scrolling to a desired position in the view
  • Changing the look and feel of an applet dynamically


What if the business insisted that we change the background image of the 'About Record Applet', and have a different picture displayed every time it is opened?

We never say no around here =).






387uh4ap2x

Reader Challenge - Show creator full name on 'About Record Applet'

This is our second reader challenge, and i've come up with something more achievable, but still impossible (our definition of impossible is when Siebel says it can't be done).

As usual, this will take under 5 < minutes to prototype, and will be fun to try.

Requirement
When the user clicks on About Record, display the actual First Name + Last Name, instead of the Login Id next to the 'Created By' and 'Updated By' labels.

Before


After


Why its impossible
1. It runs from class code and the available fields are hard coded
2. There is no underlying BC

Some people will find the above challenge too simple, so have a go at the first reader challenge which is a lot tougher.

Selectively enable/disable multiple buttons based on ShowPopup

Second place in our Impossible Siebel Poll results was a requirement to have two buttons on an applet, that call two different popup applets.

The challenge was to selectively enable/disable these buttons, this is not possible using orthordox config methods, because the buttons are based on the same method.

In this article i'll go through 3 solutions that enables us to control these buttons individually.

Solution 1 - Browser Script hack

The basis around this solution is really a DOM hack, and is implemented as follows.

We take a handle on the control, and change the class from minibuttonOn to minibuttonOf, this causes the button to be styled as an disabled button.

This allows us to control multiple showpopup buttons based on the control name.

The disadvantage of this trick, is that you cannot do complex PreCanInvoke logic, outside of the current UI active fields, without doing a round server trip.

function Applet_Load ()
{
if (theApplication().GetProfileAttr("InvButton1") == "Y" )
{
var btn1 = this.FindActiveXControl("Button1");
btn1.innerHTML = "Button1";
}

if (theApplication().GetProfileAttr("InvButton2") == "Y" )
{
var btn2 = this.FindActiveXControl("Button2");
btn2.innerHTML = "Button2";
}
}


Solution 2 - Server Script + Browser Script

This solution puts our PreCanInvoke logic in server script which offers more flexibility, and should be used over the DOM hack when possible.


  1. Configure your button as follows



    You will notice that instead of using the method ShowPopup, we are using custom methods for our buttons.



    But we still configure the user properties as normal, remember to replace the applet and desired mode with your own.



  2. Put the following code in the Applet_PreInvokeMethod section under browser scripts

    function Applet_PreInvokeMethod (name, inputPropSet)
    {
    var iOperation = "ContinueOperation";
    try
    {
    switch(name)
    {
    case "EventMethodButton1":
    case "EventMethodButton2":
    iOperation = "CancelOperation";
    inputPropSet.SetProperty("SWEMethod","ShowPopup");
    this.InvokeMethod("ShowPopup",inputPropSet);
    break;
    }
    }
    catch(e)
    {
    theApplication().SWEAlert(e.toString());
    }
    finally
    {
    }
    return (iOperation);
    }

    What this does is redirect our custom methods to a generic ShowPoup method, that is interpreted by the class code to display our popup applets, that we configured in the control user properties.

  3. Because we have configured our buttons to invoke different custom methods, we can use normal PreCanInvokeMethod logic to selectively enable/disable our controls.

    function WebApplet_PreCanInvokeMethod (MethodName, &CanInvoke)
    {
    var iOperation = ContinueOperation;

    try
    {
    switch (MethodName)
    {
    case "EventMethodButton1":
    case "EventMethodButton2":
    if (TheApplication().GetProfileAttr("InvButton1") == "Y" )
    {
    CanInvoke = "FALSE";
    iOperation = CancelOperation;
    }
    else
    {
    CanInvoke = "TRUE";
    iOperation = CancelOperation;
    }
    break;

    }
    }
    catch(e)
    {
    //error handling goes here
    }
    finally
    {
    return (iOperation);
    }
    }

  4. If you have already attempted the above instructions and have found that it doesnt work, there is a very obscure trick that enables the entire solution to work.

    You need to enable the ShowPopup property for the control

    How this works is not clear, because if you look at the help files, this is the description of this property

    • This property should not be set to TRUE on a button if there is underlying script that uses the application object method, GotoView.

      If this property is set to TRUE and TheApplication.GotoView is used, this causes the view to be opened in a new browser window. The Siebel client UI does not support a Multiple Document Interface (MDI) architecture, so this combination is not supported


    This has vague if any reference to what we are doing, but it serves our very exact purpose. Thanks to DMc for this trick.


Solution 3 - Server Script + Browser script + Accelerators

This solution was provided by one of our readers Dos and he/she donst use any tricks, just really creative thinking.

This solution is based of a SR "How to launch a popup applet via an applet menu? (Doc ID 762230.1)", which shows us how to use commands to display popup applets.

We are going to take advantage of this behaviour and use some browser script to call our commands.


  1. Configure some commands to display our popup applets



  2. Define the keyboard accelerator to invoke these commands.



  3. Configure hidden applet menus that invoke our commands



  4. Configure some buttons on our applets to trigger a virtual click on our invisible applet menus



  5. Put the follow browser script in your applet, to send keys to the UI, corresponding to our keyboard accelerators


    function Applet_PreInvokeMethod (name, inputPropSet)
    {
    var iOperation = "ContinueOperation";
    try
    {
    switch(name)
    {
    case "EventMethodButton1":
    var WshShell = new ActiveXObject("WScript.Shell") ;
    WshShell.SendKeys("^1");
    WshShell = null;
    iOperation = "CancelOperation";
    break;

    case "EventMethodButton2":
    var WshShell = new ActiveXObject("WScript.Shell") ;
    WshShell.SendKeys("^2");
    WshShell = null;
    iOperation = "CancelOperation";
    break;
    }

    }
    catch(e)
    {
    theApplication().SWEAlert(e.toString());
    }
    finally
    {
    }
    return (iOperation);
    }


  6. Use Serverscript PreCanInvoke to control whether these buttons should be enabled or disabled.

Its encouraging to see so many different solutions for something that is supposedly impossible to achieve. I can imagine all the BAs who are reading this, getting funky ideas on how to use the application.

Because i once told a BA, that doing the above was not possible, i hope that person isnt reading this blog.

Display different Popup applets from a single button click

The frequency of articles on Impossible Siebel has slowed down due to current project responsibilities, but i'd thought i say a quick hello by responding to a reader question.

This article has been requested by our good friend Neel, over at Siebel Unleashed.

Requirement

Display a different popup applet on the same button click depending on certain conditions.

Solution Overview

  1. Create two buttons that will invoke ShowPopup to display our different Popup applets.
  2. The above buttons will be made hidden
  3. Create a master button that will programically click the desired hidden button to display our desired applet


Implementation

Configure two buttons as follows









Control Name: Button1Method Invoked: ShowPopup
User Property NameValue
ModeQuery
PopupPopup Applet 1
Control Name: Button2Method Invoked: ShowPopup
User Property NameValue
ModeQuery
PopupPopup Applet 2


Configure a master button that invokes a custom method and click the above buttons based on a profile attribute.

The following code should be put behind PreInvokeMethod on the applet in browser script


var retOperation = "ContinueOperation";
switch(name)
{
case "EventMethodTest":
retOperation = "CancelOperation";
var oAppl = theApplication().FindApplet("My Applet");

if(theApplication().GetProfileAttr("WhichButton") == "Button1") {
var oCon = oAppl.FindActiveXControl("Button1");
}else{
var oCon = oAppl.FindActiveXControl("Button2");
}
oCon.all[0].all[0].click();
break;
}
return (retOperation);


Once you are happy with the above config, you can make the two ShowPopup buttons hidden.

There are various ways of doing this, you can make the buttons hidden using browser script on applet load.

var ctrl = this.FindActiveXControl("Button1");
ctrl.style.visibility="hidden";
var ctrl = this.FindActiveXControl("Button2");
ctrl.style.visibility="hidden";


Another way is to provide ON and OFF states for the button, and assign it a blank image. Maybe our readers know of better ways to do this, i'll leave this open for comments.

How to make an invisible Screen

Requirement

Restrict users from navigating and browsing through Client information, this information could be classified and access is provided on a need to know basis. The only way Client information can be accessed is through a drilldown from another part of the application.

Problem

Siebel does not provide any obvious mechanism to hide a Screen completely from the Application. When adding Views to Screens, we are given two options

1. Display in Page
2. Display in Sitemap

The first option, determines wether a view should be displayed when navigating to a Screen, while the later determines wether this view will be show under the Screen link under SiteMap.

But there is no similiar options for a Screen, the best you can do is make the Screen hidden from the page tabs, but this will still show up in the SiteMap.

Solution

Under Application/Screen Menu Item, just blank out the screen name text for the Screen you want to hide. Siebel has some internal logic to prevent screens with empty names to be displayed in SiteMap. Obscure? Absolutely!

PreCanInvoke on Siebel 7.8 (No Script)

It is a little known fact that there is support for a special (undocumented) property that allows one to get rid of the scripting normally used to do PreCanInvoke for methods on applets.

It was recommended in one of our ES reviews, but i do not use it all the time. Why?

Because it dosnt work on every applet, so you still need to script this behaviour on most applets.

Although you do get a special feeling when it does work, knowing that you saved the application some scripting.

For those who want to give it a try, this is the syntax (your mileage will vary):

Property: CanInvokeMethod: <MethodName>
Value: <Expression>

Note: This user property supposedly only works in FrameBase or FrameListBase class applets, but i've found this isnt the case, however this method is documented in Siebel 8.0, so expect it to be more reliable from this version onwards.

Predefault on an Applet (No Script)

There are times when its handy to predefault a field on an applet rather than a BC. This sounds impossible with normal config, there is a way but its really obscure.

Most people would resort to scripting to perform this task, but that path leads to the dark side.

Scenario
In the application, we have the Action BC that is used by normal users to create activites for their day to day work.

There is a new requirement from business, to build a special activites view for a new user group. These people are front line staff, and spend most of their time with the customer so the requirement is to predefault everything for this user base and all they have to fill in are minimal pieces of information.

There are a few ways to meet this requirement.

  1. If users are in a seperate division, then we can use a predefault expression based on their division (dosnt work if users are in one division)
  2. We can get the active view name in a calculated field and predefault based on that (if there are multiple views, then it becomes a very ugly expression)
  3. We can create a brand new BC for this particular group (this would seperate any logic already in Action, and has to be reimplemented in this new BC, and it is extra overhead in the repository)
  4. We can use applet user properties to predefault the field values.

This can be configured as follows:
Property: PostInvokeMethod
Value: NewRecord:SetFieldValue:Contact Id:LoginId()

The trigger is NewRecord, which will fire SetFieldValue on Contact Id field setting the value to LoginId(), the logic is pretty straightforward.