First a brief teaser about the subject at hand…
…It came ranking at third position in the infamous Siebel Hub’s Pyramid of Pains. Those Siebel High Interactivity features we are missing so dearly in Open UI. And true, this is one which I too would like to count. Though I understand perfectly fine the Siebel development team is not keen introducing features which do not meet the web standards based approach they remain focused on. Using a context menu is one of those debatable subjects, should a context menu belong to a web application?
That said, I reckoned to give it a shot. Why? Because the vast majority of the existing Siebel customer base are Call Center “type” of implementations. At least running on a desktop of some kind, with a mouse attached :-)
Where did I start? Well, just by fooling around with the Google developer tools. My initial idea was to mimic clicking the menu wheel button. Then trying to move the applet menu which would render to another position. I wasn’t looking forward having to deal with the complexities implementing a custom context menu from scratch. Please no. Why re-invent the wheel?
First of all, would the JQuery trigger() statement work against the menu’s element? Just a random applet on a random view.
Guess what, the applet menu popped up. Hopeful start. Next finding the appropriate mechanism to capture the right-mouse button + some additional key. Just overriding the browser’s context menu by-default did not seem such a good option. Rather have a key-mouse combination instead, to selectively switch between the regular context menu and the Siebel context menu. I opted for the “Alt” key and started off with the following piece of test code:
Also, no problem here. Next step, experimenting with the JQuery’s .animate statement. Googling a bit showed that the usage is dead simple. Obviously I did not want a true animation to appear, rather just take the feature with a sub-second transition time, so the beholder of they eye would not witness any transition.
Well, that was the idea. The .animate routine accepts coordinates to instruct where to animate a certain DOM element towards. Just by inspecting the DOM I found that once clicking the menu button identified in this example by the selector $(“#s_at_m_5″), the actual menu appearing would be identifiable by $(#s_at_m_5-menu”). And the event parameter passed by JQuery would provide using e.pageY and e.PageX the needed target coordinates where the mouse pointer was located at the time the .mousedown event occured. Nice.
So, at the point the context menu started appearing more or less where I expected. More or less because there was a strange Y-axis offset. Interestingly enough when logging the coordinates, these turned out to be correct. But the .animate would give an offset of exact 150px . I can live with that, did not care for now to research this particular point deeper.
Because I want to suppress the default context menu from the browser, some additional logic was needed. Googling a bit revealed the simplicity of the solution.
But what to re-instantiate the default functionality again? Simply the opposite of binding to the “contextmenu” event, unbinding the event.
Things are looking great so far, time to build an actual applet physical renderer. Starting of as always from solid boiler plate code. Really, it saves you loads of time. Much better than copy/pasting from a previous file.
First of all I had to deal with the simple stuff of making use of dynamic selectors instead. Since I found the menu button and the menu itself (which essentially is a list of links) are created by Siebel using the Applet’s Id being respectively $(“#s_at_m_5″) for the button and $(“#s_at_m_5-menu”) for the menu itself.
Using a straight-forward regular expression (straight-forward here means, I Googled it instead of re-inventing it) I was able to substring this number from the applet’s full Id.
While further building the PR and testing it along, I found that it did not work that well. Inconsistent. Sometimes the default context menu did not get suppressed, sometimes the applet menu showed up but did not animate, sometimes the default context menu did not get re-instantiated, sometimes a mix of these… I believed this to be a timing issue. Therefore setTimeout to the rescue. Maybe there is a better alternative like using the stopPropagate to prevent any events from bubbling up the DOM tree. For now I did not really care to research this further, as I found inserting two setTimeouts did the job.
Code wise this became the end result.
For now I just build it as stand-alone physical renderer for list applets. No big deal to create one for form applets too. Obviously if this should be application-wide behavior we would need to override the respective DEFAULT LIST RENDER and DEFAULT FORM RENDERER physical renderer files instead. An interesting previous post on this subject can be found here, while discussing rendering navigation buttons as glyphs instead of the ugly out-of-the-box sprite.
This concludes this post. I am looking forward to comments, suggestions and improvements. An issue I was yet unable to tackle is that the first time I request the Siebel context menu, it shows up in its original location. Doing a second “Alt” + “Right mouse click” fixes that. Other small deficiency is that sometimes you will see the applet menu flickering in its original location before showing up at the cursor’s location.
The complete PR can be grabbed here.