OpenUI – Single Click Sort (The Sequel)

qsRead my post, from two days back? I left the Single Click Sort solution at a point where it was functional, but at the same time introduced a significant limitation. Limitation such, that the Column Lock/Unlock feature would be put at stake.

In the mean time, collaborating with my colleague Pedro Melo we tweaked the initial solution a bit. The setTimeout() function existing in the initial solution, had a wait of zero (0) milliseconds. That basically means, the call to the function() will be postponed until the browser is done, essentially to the point that there are no further function calls stacked in the browser’s message loop. An interesting Stackoverflow thread on this topic can be found here.  I typically set the timeout to zero, to force execution to wait until the browser is done. Often solves hard-to-tackle issues related with event bubbling. Like to learn more? Check this.

Well, we changed the setTimeout() to wait for 200 milliseconds. Why 200 milliseconds, you might ask? That will be the maximum time-span in which we will capture a ‘double click’ event. More that 200 milliseconds, and we will treat those mouse clicks as two individual clicks.

Added a dblclick event handler, and the sole thing it’s bound to do, is set a local ‘dblclick’ variable to true. After the 200 milliseconds have passed, the ‘stacked’ function will execute. Why? Because the browser also captured the click event. A true/native double-click will trigger both ‘click’ and ‘dblclick’ events. First the ‘click’ event will fire, second the ‘dblclick’. It’s kind of a hack, but it’s functional.

On touch devices, default functionality should prevail – the condition IsTouch() got added to by-pass the custom code conditionally. Alternatively, the same could have been done using a Manifest Administration expression – preventing the QuickSortPR.js to download at all.

What does the complete solution look like?

if (typeof(SiebelAppFacade.QuickSortPR) === "undefined") {
SiebelJS.Namespace("SiebelAppFacade.QuickSortPR");

define("siebel/custom/QuickSortPR", ["siebel/jqgridrenderer"],
function () {
SiebelAppFacade.QuickSortPR = (function () {

function QuickSortPR(pm) {
SiebelAppFacade.QuickSortPR.superclass.constructor.apply(this, arguments);
}

SiebelJS.Extend(QuickSortPR, SiebelAppFacade.JQGridRenderer);

QuickSortPR.prototype.ShowUI = function () {
SiebelAppFacade.QuickSortPR.superclass.ShowUI.apply(this, arguments);

if (!SiebelAppFacade.DecisionManager.IsTouch()) {
var dblclick = false;
var placeHolder = "s_" + this.GetPM().Get("GetFullId") + "_div";
var elSortable = $("#" + placeHolder).find(".ui-jqgrid-sortable");
var sort = $("li[data-caption='Sort']");

elSortable.on("click", function () {
sort.parent().css("visibility", "hidden");

setTimeout(function () {

if (!dblclick)
sort.click();
else
$("li[data-caption='Lock']").click();

dblclick = false;
}, 200);
});

elSortable.on("dblclick", function () {
dblclick = true;
});
}
}

return QuickSortPR;
}());
return "SiebelAppFacade.QuickSortPR";
})
}

Can grab the code from here also.

– Jeroen

 

Advertisements

Siebel Fluid Form Applets

Making Siebel Form Applets really responsive and fluid, that was Duncan’s goal. Duncan, part of Oracle’s Siebel development team brings solutions to the table that make you think and wonder. Although Siebel OpenUI is said to be responsive, that does not hold very well for form applets. The idea was to maximize the real-estate for form applets based on available screen-width. Fully fluid.

So… say from something like this:

fluid_before

Towards something more like this:

fluid_after

Much cleaner, isn’t it? And fully fluid!

You can find, follow and contribute to his work in progress on the OracleSiebel!

– Jeroen

 

Siebel Pinnable Views Means Productivity

About two weeks back I posted an article on LinkedIn under the same title. It generated a bit off buzz based on feedback I received. The use-cases one could imagine having this feature are endless, if you ask me. If you haven’t seen it yet, check the Youtube footage.

The original idea was drafted by Warren Mull, and I took the raw demo solution to the next step. Why? Because as said, there are endless use-cases and a feature alike has been requested for as long as I have been working with Siebel.

Traditional solution would be to allow multiple Siebel sessions to be opened by end-users, which really, is one of the worst approaches possible for many reasons. The beauty of the Pinnable Views is the fact, that there is no Siebel session tied to it. It acts as a ‘static’ copy or clone if you wish of the original Siebel view. That does mean, the Pinnable View does not allow any further user-interaction (no drill-downs, no navigation, no scrolling). But for the majority of the use-cases, that is no limitation if at all.

So, this post is all about the implementation. Which really, is quite straight-forward. Conceptually it consists of just a few steps:

  1. A postloader injects the necessary code to display the ‘pin’ and ‘unpin’ buttons;
  2. When the ‘pin’ button is clicked, it will traverse the DOM’s <head> to identify all the embedded CSS stylesheets. That would allow, to reference these same stylesheets in the ‘cloned’ page;headcss
  3. Retrieving the view’s current title (from the <head> section);
  4. Create a boiler plate HTML document, referencing the previously collected style sheets and page title;
  5. Generate a new window, which would display as a tab in the browser;
  6. Cloning the existing view’s ‘_swecontent’ into the new window’s document;
  7. Push the new windows handle to an array, within the scope of the Siebel application.

No more, no less.

And sure, a bit of additional styling is requires to visualize the ‘siebel-pin’ and ‘siebel-unpin’ glyphs nicely. And about these glyphs: I desired to have a decent ‘unpin’ glyph. But that is non-existent in the fonts delivered with the application. So I choose to create a separate ‘siebelpins’ font-family for that purpose. In a previous article I explained how to go about, creating a new font-family using icomoon.

But this time, I just wanted to create a custom glyph. Not from scratch, but based on the existing ‘pin’ available in the ‘oracle’ font-family, delivered with the Siebel application. So how to go about?

First, you need to get a decent ‘path’ or ‘polygon’ svg. That is easily done with the Icomoon app. Simply import the ‘oracle.svg’ into Icomoon, select the ‘pin’ glyph and have Icomoon generate your font.

icomoonpin

It will something be alike shown below. But do not worry, you don’t need to understand what SVG is all about 😉

pinsvgpath

Next I turned to Glyphrstudio, which is a really neat tool to create either from scratch or modify any existing font. As long as you have a path or polygon SVG string available, you’re fine. Simply copy/paste your SVG string and voilá – there you go.

glyphrstudio

Glyphrstudio provides a neat editor, so just drawing a diagonal line through the ‘pin’ glyph takes little time.

glyphrstudiomodify

The next step would be exporting your new SVG font. Because we would like to have .svg, .woff, .ttf and .eot representations of the the new font, it’s back to Icomoon again. Import the SVG generated by Glyphrstudio, and save it again. Icomoon will generate a .zip archive with all the goodies inside.

icomoonexport

The resulting files .svg, .ttf, .woff and .eot files you can copy to your Siebel’s /public/<lang>/fonts/custom folder.

icomoonsavedfonts

Alright, so what would need to do code-wise? Let’s walk you through.

It generates a ‘windowsPopups’ array, which will hold any handle to Pinnable Views windows. Why? Well, because otherwise we cannot close them.

Next the buttons get appended to the application menu (if you happen to use the Synergy theme, sure you need to visualize the application menu, or append the buttons to another element).

Forcing to re-paint is required, otherwise the buttons will on initial display be ‘wrapped’ and not shown as a single block.

pinnviewpl1

Next, we define the ‘onclick’ event. The first reference we add is the ‘faviconpin.ico’ which I created. Next it traverses the style sheets, and appends these. Finally the <heads>  title is retrieved. The boiler plate HTML is created, the new window is generated and the boiler plate gets written to it. The ‘_swecontent’ portion of the view is cloned, and finally we push the handle to the earlier mentioned array.

pinnviewpl2

To make things a bit more appealing, adding hover functionality. Implementing the ‘unpin’ is as simple as closing all of the windows while looping through the array.

pinnviewpl3
To suppress any non-sense elements on the pinned view, I added a bit of styling to the pinnable view. Remember, that in the first stage I embedded a popup.css?

pinviewcss

And this is the tiny bit of content.

pinnableviewscss

Lastly, the needed additions to your theme override. First define the new font-famile ‘siebelpins’ (usually on top of your CSS). Beware that the paths are considered relative from where the override CSS is located. That should be in /files/custom – but if you decided otherwise beware of that.

pinviewbuttoncss

That it. And of course, you can grab it all here:

Enjoy!

– Jeroen

 

Catch Those Uncaught Exceptions From Your Browser In Open UI – Part I

bugsnag-logo-1With any web application running tons of Javascript, getting track on what’s happening within the browser can be a true challenge as well as nightmare. And with the ever expanding Javascript frameworks and libraries which see the light every day, more, more and more is going on in the browser. And that is no different for Siebel OpenUI.

Recently, I got in a situation where a customer reported data loss. More specifically when sending an outbound email in reply to an inbound email. Where at the moment the user hit the ‘Send’ button, the actual email composed by the user got lost and instead an empty email was sent. Quite annoying, to say the least. More annoyingly, for the end-user: this event would go completely unnoticed. Not reproducible and with a fairly low frequency, but reported by many different users. Finding a pattern led nowhere. Since Siebel leverages the CKEDITOR library for rich text editing, this was for me one of the suspects.

I implemented a presentation model to catch the EmailSend method on the “Comm Outbound Item Form Applet New” applet, in order to get some grip on the situation. I found that by logging each and every EmailSend event through the central error logging facility exposed as business service in this implementation, that somehow in certain situations truly the data in the CKEDITOR control would be different from the data saved on the business component (and sent…). But still now clue on the “why”.

Typically a situation where you’d want to have an eye on each of the user’s browser consoles to see if any uncaught (or caught) error got reported. And especially that is a problem. Where debugging Siebel traditionally has been pretty much server-centric, the browser plays a huge role these OpenUI days.

I reckoned, I’m surely not the only one facing this challenge! Imagine you run a multi M$ or B$ eCommerce site, you surely want to have comfort and confidence that your platform runs fine on any browser or device. Assume that on Android 3.x using Firefox as browser you cannot conclude a purchase because of some unexpected error happening which no developer nor tester could have foreseen (“who runs Android 3.x with a Firefox browser”)?

It turns out there are quite some error handling frameworks out there: Sentry, Airbrake, Rollbar to name a few. And Bugsnag. Bugsnag seemed to be pretty flexible. Bugsnap is a paid service. Now one issue which might immediately come to mind: can we use such as cloud service? I agree, that might be a showstopper from a data-privacy or company policy point of view. But Bugsnag also allows for an on-premise ‘implementation’. That said, I was interested enough to give it a go. And really, working with Bugsnag is child’s play. After creating a trial account, I got it working in a matter of minutes just by adding the Bugsnag “notifier” library per Siebel manifest administration. Setting the Bugsnap API Key in the browser’s console followed by a call to the notifier’s Bugsnag.notify() and bob’s your uncle.

bugsnagerror

bugsnagerror2

So that worked out pretty fine so far. And that’s interesting too, through the Bugsnag notifier you’d have an alternative for SiebelJS.Log() for situations where it would make sense. But more importantly I needed to verify whether those nasty uncaught exceptions would be be caught by the Bugsnag notifier too, which should be the core reason to use it after all. The Bugsnag notifier hacks into the window.onerror to achieve this. To test this, I just added a throw() to one of my existing customizations to simulate it.

uncaughtexception1

You’d already see the exception’s trace mentions ‘_super.bugsnag’. So something’s going on!

uncaughtexception2

Unfortunately, not too much detail. But at least the Bugsnag notifier logged the exception. In the next post I will explain how to integrate Bugsnag properly into Siebel and how to add more Siebel contextual details whenever an uncaught exception gets logged (or when an error is logged by code per design or for debugging needs). To eventually get something similar to this….

uncaughtexception3

– Jeroen

Firefox To Drop NPAPI Support Late 2016

Firefox-DisabledJavaPluginThe word is out from the Mozilla blog: Firefox will de-support NPAPI Plug-ins late 2016. Mozilla following the same path as Google but with a remaining grace period of about 15 months. Although Mozilla announced it will still support Flash, Java will be a dead-end in the browser. Even though Siebel Open UI does not heavily rely on Java there are some bits and pieces which do. The most important obvious one would be the ‘inline editing’ mode of Siebel attachments. And then obviously there are customers who have resorted to a Java applet for some kind of desktop integration, replacing the traditional HI / ActiveX Web Client Automation Server capabilities to attach to a Siebel web session.

Good to know, with Innovation Pack 2016 there is a planned feature to replace current Java applet based functionality with an open Web Socket framework. Check the Innovation Pack 2016 Statement of Direction to get more details. The Web Socket framework will be open and published as API for customers to take advantage of.

– Jeroen

Keep That Siebel Session Alive

SessionIn a recent article I described a new feature introduced in IP15.3 called ‘white listing’ where one could define invocations which would not lead to a reset of the SessionTimeout timer. Particularly interesting, because one could ‘white list’ the Message bar (or better call it ‘Notifications’), so that your session would nicely time-out after the configured time. Regardless whether or not you are pulling broadcast messages from the server at the fixed interval at which it is configured.

On the other side of the medal, there are these scenario’s where one would like to prevent a session time-out to occur. Typically a session time-out is configured at say 30 minutes or so. But there are always use-cases where 30 minutes in general would apply, but not in 100% of the cases.

Working with a financial services customer, an important group of their end-users complained that while writing call reports, they quite often lost their work due time-outs. How frustrating that would be, is clear. Pulling the cables and throwing your laptop of desktop out of the window (especially if it happens on Friday COB). You could try to train, and tell them to commit once and a while. But that will take a way only a percentage of the pain. And the behavior simply is damaging to the overall UX!

Trying out a simple approach, which would work in both HI and OUI – I came to the following rough-edged solution.

  1. On the Applet_Load (= browser script) call a function “keepAlive()”
  2. This keepAlive() function would, well, keep the session alive.

But how? The bare minimum would be just these few lines of code:

keepalive

There is no magic, just a recursive function call every 5000 milliseconds. During this recursive call, the call to theApplication().GetProfileAttr() forces a server-rountrip. And it keeps your session alive. Of course, 5000 is just a sample figure. Reality, this should be a bit less than the SessionTimeout configured the eapps.cfg.

The beauty of this tiny solution, you can make it very selective. Add some little logic such that the code. Simple as that.

The same would work for both HI and OUI clients. If you have to be in an OpenUI-only environment, I would re-write it as a physical renderer instead. Leading practice: prevent leveraging traditional browser scripts. At some point in time these will be deprecated.

– Jeroen

Patch Set 15.3/14.9 Skyrockets Performance!

This result deserves truly a big applause. Oracle development worked closely together with Microsoft engineers to boost Open UI performance. With IP15.3/14.9 a complete overhaul of the List Applet renderer has been delivered. This went into the release quite silent, with no notice in the patch set’s release notes. The improvements were focused to give a boost for Internet Explorer, but the improvement is evident for Chrome (hence other browsers, including Edge) too!

Without more wording, just have a look at the results! These results are just amazing. We can safely say that Open UI will come close or exceed what you have ever experienced with High Interactivity clients. Think of the improvement it will make on mobile deployments for tablets… Skyrocketing performance.

IP153-149Performance

– Jeroen