Showing posts with label Challenge. Show all posts
Showing posts with label Challenge. Show all posts

Cornelius' Applet Set Focus Challenge

This article continues on from the guest article on Siebel Essentials - Set Focus on an Applet by Cornelius.

When I read the article by Cornelius, and saw the ~85 lines of code, I fainted (possibly due to the heat wave on the day) and when I came to, I wondered if this solution can be made leaner?

Querying the repository is sometimes necessary, when you need to achieve non-standard functionality, but in this case I felt there had to be a better way. Using SWEApplets only works in SI, but in HI, it should be possible to read the DOM and find the first visible applet and pass it to HandleAppletClick.

I did a quick POC using the IE DTB, and got a working solution with 5 lines of code. But 5 lines was too much in my opinion, so with a re-think of the problem, I by passed HandleAppletClick, and got the solution leaner.

The result is 3 lines of code. Heres how I did it.

Before we jump into the solution, ensure you have jQuery installed on your top object. This can be done via the web templates

Insert the following line of code in a common template such as your PageContainer

<script src="<your scripts folder>jquery.min.js"></script>
<script src="<your scripts folder>common_1.00.js"></script>

Next assign the jQuery object to your top object as so in your common JS file
top.$=$;

Now you'll have access to this magic everywhere in your application.

[Solution]

Cornelius separated his solution into two parts

1. Setting focus on the applet using "HandleAppletClick"
2. Using Browser/Server script to retrieve the applet sequence from the repository

This solutions just entails 1 part

1. Goto the DOM behind the current view and click the first applet that we find =)

Line 1:

var iRows = top.$("frameset",top.SWEFindFrame(top,"_sweview").document).attr("rows");

The Siebel thin client has an array of 10 cached view frames, and randomly picks a frame to render the next view upon Application Navigate. This happens behind the scenes and is not exposed or documented. Although the frame reference is random, and the next view frame is not known, we can check to see which of the current 10 frames is visible through the "rows" attribute on the frame container.

The above line just returns a reference to the current frame index.

Line 2:

var fDoc = top.SWEFindFrame(top,"_svf"+top.$.inArray("*",iRows.split(","))).document;

With the frame index, we can grab a hold of the actual frame document, using "top.SWEFindFrame". This is an undocumented Siebel browser framework function, if you are uncomfortable using it, you can roll your own, just write a recursive function that iterates through the frames and match on the frame name or just copy the Siebel function into your own library.

Line 3:

top.$("div[onclick*='HandleAppletClick']",fDoc).first().click();

As Cornelius has discovered, Siebel uses a function called "HandleAppletClick" on the onclick handlers for its applets. My original 5 line solution involved scraping the Applet name from the DOM, and passing it to "HandleAppletClick". In this solution, I just look for the first element that has the onclick handler that fires "HandleAppletClick", and click it programmatically.

[Conclusion]

Although its not necessary to use jQuery, having it makes our solution more concise, and readable. A similiar browser script function could have been implemented, but you would be spending a lot of time performing the low level DOM work.

Applet Toggles, Personalization, and Display Visibility all affect the run time visibility of the Applet. This technique allows us to determine dynamic UI behaviour that is not available when querying the repository.

The solution is lightweight, fast and best of all, we performed a beat down of ~85 lines of browser/server script with 3 lines of "Black Magic Do" (Translation: Way of the black magic). For the non initiated, in martial arts Do, means way or road =)

Solution - Popup Applet "X" button

This is the long awaited solution to the Popup Applet X button challenge, which was solved by Master configurator Michael Feng.

[Background]

Siebel provides us with two events on popup applets, represented by the buttons "Ok" and "Cancel" which provides the neccessary hooks to capture most business requirements around closing of popup applets.

But the "X" button is an exception case, where the user forced closed the applet without completing the required interaction. In these cases, you might want to rollback any changes that were made since the applet was opened, or popup an alert to educate the user of the consequences of not closing the Applet properly.

[Siebel popup applets]

It is important to understand what happens when we click on the "X" on a popup applet in Siebel. The developer who requested help from the Oracle forums, tried attaching a custom method on window.onunload, which is a native browser event for when the current view has been navigated away from or closed.

This is the right line of thinking, and isnt far off from Michael Fengs solution below. This would normally work for traditional web apps, but Siebel dosnt close the popup applet when you click "X", it just minimizes it and hides it under your taskbar, which is why the window.unload event never fires.

The way to see this in action, is to set your taskbar to auto hide, watch what happens when you click "X" on a popup applet. You'll see it minimized to a short title bar on the bottom left of your screen, underneath where the taskbar would normally sit when displayed.

[Usability]

The reason why Siebel does this is for usability. When you log into your Siebel application, the first time you open any popup applet will always be the slowest, thats because Siebel has to spawn a new instance of an IE window. When you click "X", siebel will minimise and hide the window. The next time when you open another popup applet, Siebel will re-display and re-use this same popup window.

Re-displaying an existing window is in order or magnitudes faster than opening a brand new window, and greatly enhances the user experience in HI applications.

[Solution]

As mentioned in the original post, there are various solutions to this problem. When the popup applet is closed, focus will return back to the control/applet that invoked the popup applet, and you could, pop up a confirmation at this point, but it is ugly, if the popup applet is used in many places then you would have code on a lot of base applets.

Since the Popup applet is never closed, another idea is to set a looping timer to determine the position of the applet, and if it disappears below the taskbar then we know it has been closed. Its not a desirable solution as polling adds overhead. So the ideal solution is to trap the X event on the popup applet itself.

One alternative is to attach a custom function to the window.onmove event of the Popup applet which would give us a real time notification everytime the applet gets moved, and if it moves to the taskbar position, we know the user clicked X.

Or we could do better by detecting when the physical dimensions of the Popup applet has been shrunk by monitoring the window.onresize event.

Heres how it can be done, the following code is provided by courtesy of Michael Feng.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

An interesting question is, what happens to the UnloadTrigger that is attached to our first popup window, when a second popup is called after the first? Does it still linger around, even when if its unwanted on the second window? Siebel re-renders the entire contents of the applet everytime it is "re-used", but keeps a cache of the last applet.

Base applet --> Popup Applet A --> Popup Applet B

Siebel will cache the contents of Popup Applet A when it is opened, Siebel re-uses the popup window, and renders the HTML for Popup applet B when it is opened.

When Popup Applet B is closed, Siebel will reuse the popup window, and restore Popup Applet A from its cache, therefore restoring our UnloadTrigger.

So we have to modify the solution to deal with the fact that popups can spawn other popups.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}


The above code uses and undocumented function Top().SWEPopupGainFocus() to determine if a popup is in focus or not. We only want to display a message when there is no popup open.

The last piece to this puzzle is to handle the positive events when the user click on "Ok" and "Cancel", in which event we do not want to display our message. You'll need to set profile attributes, or view variables to indicate that the applet was closed properly, and check for these variables in the unload function.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()&&App().GetProfileAttr('ProperlyClosed')!='Y'){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

Thanks to Michael for providing this solution, and for helping solve another impossible problem and breaking new grounds on creativity =).

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.

Reader Challenge - Popup Applet "X" button

[Requirement]

"How to show alert to user after closing a Pick Applet from the "X" button [top right corner]. I want to show the alert or confirm(yes/no) box just after closing the pickapplet.

I tried using the window.onunload event in browser script of pickapplet, but it didn't worked.

please help"

Source: Oracle Forums
Link: http://forums.oracle.com/forums/thread.jspa?threadID=924827&tstart=195

[Challenge]

To clarify, the developer wants to display a confirmation dialog after the applet has been closed, and not to prevent the applet from being closed.

There are a few solutions that come to mind.

1. Put some code on the applet that invokes the popup applet, when focus returns to the first applet, pop up the dialog.

This is ugly because you need to put code on all the base applets across the application that use this popup applet.

2. OnLoad of the pop up applet, create a looping mechanism to check the name of the active applet, when the active applet is no longer the active popup applet, pop up the dialog.

This solution dosnt provide a real time notification, and creates un-neccessary load on the application and browser.

So your challenge is to find an alternative solution, which should be pretty tough ruling out the above possibilities.

To test the water, I seeked opinion from Michael Feng, of scriptless VBC fame, who initially dismissed it as impossible, but when I said, there is a solution.

He came up with a concept and a working solution in a few days. His solution allowed an alert to be displayed in REAL TIME when the X was clicked on a popup applet.

Its been a year since the above requirement was posted to the Oracle forums, if you are the author of the above post, or you are a customer who needs the solution, send me a message on LinkedIn, and i'll gladly fill you in.

To keep you entertained until then, heres a flash back to the 80s, and an introduction to "Joy", the greatest band to come out of Austria.



Joy enjoyed success across Europe and East Asia, with numerous hits such as Touch by touch, Hey Hello, and Valerie.

Trap submit button in TBUI

In my last article, we encountered a new behaviour in Siebel that allows TBUI to re-use its buttons and dynamically generate different button labels depending on what view the user is on.

For example, you have 5 views in your TBUI task, on the first 4 views, this button would read "Next", but as you navigate to the final view, this button dynamically changes to "Submit", click "Previous" and it turns to "Next" again.

Image of TBUI Playbar


This behaviour is activated by the following control user property.

DynamicLabel Y

If you are curious enough to look at the web template to see how this works, here is the corresponding section with some cues on how to configure it.

<swe:control id="152">
<!-- Next Button -->
<!-- If of "DynamicLabel" is "Y", it shows "Next"/"Submit"/"Finish" based on -->
<!-- <forward button type> in task step -->
<td class="AppletButtons" nowrap>
<swe:this property="FormattedHtml" hintText="Next" hintMapType="Control"/>//Our magic button
</td>
</swe:control>

As magical as it may be, it causes a problem for anyone who wants to trap the event of a click on the "Submit" button, since the "Next", "Submit" buttons are the same physical button, on the same applet, and fire the same methods, so it makes it quite tricky to detect which "buttons" have been clicked.

The key to this problem is reading the button text when the user clicks on the button and then determine the next course of action. This can be done by trapping the PreInvokemethod, and using browser script to read the button label.

The following code shows how this can be done:


function Applet_PreInvokeMethod (name, inputPropSet)
{
if(name=="NavigateNext"){
sCurrentControlName=getControlLabel(this,"ButtonNext");
}
return ("ContinueOperation");
}

function getControlLabel(that, ControlName)
{
var objControl;
var sControlLabel = "";
try{
objControl = that.FindActiveXControl(ControlName);
sControlLabel = objControl.getElementsByTagName("A")[0].innerHTML;
} catch(e){
alert(e.toString());
}
return sControlLabel;

}


To make things a little more interesting, the final button can have other labels such as "Complete", "Done", "Finalize" and other custom values, and you'll also need to consider what happens when the user cancels or Pauses, in your design.

If you need to trap the "Submit" in TBUI for purposes other than this hack, keep in mind the alternative solution of cloning the applets, as mentioned in the previous article, which will allow you to stay away from the dark side.

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.

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.

Reader Challenge - Display a popup applet from inside a Shuttle Applet

This article is a break from the usual style of where i state the problem and provide the solution.

You are encouraged to try and work out this problem for yourself, it will take < 5 minutes to prototype. This gives the reader an opportunity to solve a tricky problem, and learn a few things along the way.

To start with, this challenge is almost impossible (this adds to the fun), there is a Siebel product defect on this issue. You can view the details of this on Metalink (Bug ID 12-KIGMEO).


This is a horrible defect, basically the behaviour is that you can use ShowPoup to display an applet anywhere in the Application, except inside Shuttle applets.


If you try to use Showpop inside a Shuttle, the popup appear appears in base mode and all the buttons are greyed out.


and when you close it, the shuttle applet re-appears but gets re-arranged like a picasso painting.

There are actually other ways of achieving the same behaviour, for example, you can close the shuttle and open up another applet from the base applet or you can open up a custom IE window that looks like an applet.

But this is a purely technical challenge, and the requirement here is to display a Siebel popup applet from inside a Shuttle Applet, it sounds simple enough.

As always there is more than one solution, so its not entirely impossible, we'll revisit this article again in a several weeks.