HTML Javascripts in OBIEE


     Writing   HTML   Everywhere   
     
        Using HTML in all Answers & Dashboards GUI components  

 

 

 

    Introduction

 

When OBIEE’s default functionality is too inflexible to format row data in the manner required, we’re used to embedding HTML within a column formula and setting field “Treat Text As” to “HTML” on the “Data Format” tab.

 

However, what about all those other Answers and Dashboards components where we would like to enter HTML, such as column headers, report titles, and prompt labels?  For every component, apart from the column formula, OBIEE provides no means that allows us to enter HTML in the same manner as in a column formula.  Instead, we are restricted to using CSS styles, and even here the styles only apply to the entire text entered into a component, and cannot be applied selectively to particular parts of the text.

 

End users shake their heads in disbelief when told that OBIEE can’t implement the very simple functionality that they have requested.  In this article we’ll see how to overcome these limitations, how to provide the functionality that users expect from an expensive BI tool.  We’ll learn how to “write HTML everywhere”.

 

 

    A Reasonable Request

 

Let’s start with a simple example.  We’re creating a prototype for a user.  We’ve got this far:

* 
Where we are

 

The user takes one look at it and asks us, not unreasonably, to:

 

*  Split the column headings over two lines;

 

*  Add a hyperlink under “Old Catalog” to link to the catalog page; and

 

*  Emphasize “Reclassified” by putting it in a 10 point font, in an italic style, and in a red colour.

 

In other words, what the user wants to see is:

* 
Where we want to be

 

 

    Adding HTML

 

In order to fulfil these modest requirements, in the “Label” field of the prompt we need to enter:

 

Products (<span style="font-size:10pt;font-style:italic;color:red;">Reclassified</span>)

 

like so:

* 
HTML formatted Prompt Label

 

In the “Column Heading” field on the “Column Format” tab we need to enter:

 

Material<br>Category

 

like so:

* 
HTML formatted Column Heading

 

(and the same for “Standard Finish”).  In the “Title” field for the request we need to enter:

 

Products (<a href="http://mycompany.com/oldcatalog.htm">Old Catalog</a>)

 

like so:

* 
HTML formatted Title

 

 

    Not what we want!

 

When we drag the prompt and request to a dashboard section and display the dashboard we see:

* 
Dashboard with unrendered HTML

 

Time to start thinking about a workaround!

 

 

    Advanced Tab

 

The problem we have here is that unlike the case of a column formula other OBIEE components do not have a “Treat Text As HTML” option.

 

Our first thought when we find that the default OBIEE functionality is not fit for purpose is to attempt to hack the XML in the “Advanced" tab.  In this case, the XML is:

* 
Advanced Tab XML for Column Header

 

Now we can see why the HTML is not being rendered.  OBIEE has converted the “<” and “>” characters to the corresponding HTML entities:

 

Material&lt;br&gt;Category

 

Our first thought might be convert the HTML entities back to “<” and “>”.  But then we realize why OBIEE has made the conversion in the first place.  This is XML, in which “<” and “>” are proprietary symbols, so converting the HTML entities back to “>” and “<” would corrupt the XML request definition.

 

In the case of embedded HTML in a column formula, OBIEE also does the same conversion to HTML entities, but the Presentation Server reverses the process when it generates the HTML page if “Treat Text As” is set to “HTML”.

 

 

    Web Page Post-Processing

 

So, since we can’t implement a workaround before the web page is generated by the Presentation Server, we must do so afterwards, when the web page has arrived in the user’s web browser.

 

What we want to do is to change occurrences of “&lt;” and “&gt;” back to “<” and “>” respectively.  However, as there may be some occurrences of “&lt;” and “&gt;” that need to be displayed as “<” and “>” we must be selective when it comes to making this conversion.  The simplest solution is to add beginning and end delimiter tags to each section of the web page to be converted.  For example, let’s add “-=#B#=-“ as the beginning tag and “-=#E#=-“ as the end tag.  So our custom HTML becomes:

 

-=#B#=-Products (<span style="font-size:10pt;
   font-style:italic;color:red;">Reclassified</span>)-=#E#=-
-=#B#=-Material<br>Category-=#E#=-
-=#B#=-Products (<a href="http://mycompany.com/oldcatalog.htm">
   Old Catalog</a>)-=#E#=-

 

 

    HTML DOM

 

Now we need to parse the web page, identify all code sections that lie between our custom delimiters, remove the delimiters, and convert the HTML entities therein back to their standard character representations.

 

JavaScript and HTML DOM allow a subset of the HTML code within a web page to be manipulated.  The JavaScript statement:

 

v_old_body = document.getElementsByTagName( "body" )[0].innerHTML

 

will extract the entire body element of the HTML page and place it into variable “v_old_body”.  Once we’ve made our changes and copied the results to variable “v_new_body” we can update the body element using the JavaScript statement:

 

document.getElementsByTagName( "body" )[0].innerHTML = v_new_body;

 

The following JavaScript function will perform the required conversions:

 

// =========================================================================== //
//                  CUSTOM JAVASCRIPT - REINSERT AFTER UPGRADES 
// =========================================================================== //

// =========================================================================== //
//                                 HTML EVERYWHERE
// =========================================================================== //
//
//   This function selectively converts the HTML entities "&lt;" and "&gt;"
//   to the characters "<" and ">" respectively, allowing HTML to be entered
//   into any OBIEE screen component (such as a column header or a prompt label).
//
//   HTML to be converted should be preceded by "-=#B#=-" and suceeded by
//   "-=#E#=-" when entered into an OBIEE screen component.
//
//   The HTML page has the following structure:
//
//      <page> ::= [ <component> <end delimiter> | * ] <postfix>
//      <component> ::= <prefix> <begin delimiter> <text to decode> 
//
//   This function should be called from the "onload()" event handler.
//
// =========================================================================== //

   function cs_html_everywhere(){

      // DECLARATIONS
         var c_begin_del = "-=#B#=-";
         var c_end_del = "-=#E#=-";
         var v_old_body = "";
         var v_new_body = "";
         var v_body_components = new Array();

      // GET OLD BODY 
         v_old_body = document.getElementsByTagName( "body" )[0].innerHTML;

      // SPLIT OLD BODY INTO COMPONENTS PLUS POSTFIX
         v_body_components = v_old_body.split( c_end_del );

      // EXAMINE OLD BODY COMPONENTS [IGNORING POSTFIX]
         for( i = 0; i < v_body_components.length - 1; i++ ){
            // GET START OF TEXT AFTER PREFIX
               v_start = v_body_components[i].indexOf( c_begin_del );
            // APPEND PREFIX PLUS DECODED TEXT TO NEW BODY
               v_new_body += 
                  v_body_components[i].substring( 0, v_start ) + 
                     v_body_components[i].
                     substring( v_start + c_begin_del.length ).
                     replace( /&lt;/g, "<" ).replace( /&gt;/g, ">" );
         }

      // APPEND POSTFIX
         v_new_body += v_body_components[ v_body_components.length - 1 ];

      // REPLACE BODY
         document.getElementsByTagName( "body" )[0].innerHTML = v_new_body;
   }

 

 

    Including JavaScript

 

How do we include this JavaScript function within every dashboard page?  If we look towards the beginning of the HTML code for a dashboard page:

* 
Dashboard Page HTML - common.js

 

we can see that an external JavaScript file, “common.js”, is referenced.  This file is included within every dashboard page.  This file can be found in directory:

 

<OracleBI>\oc4j_bi\j2ee\home\applications\analytics\
   analytics\res\b_mozilla

 

for a J2EE implementation of OBIEE.  If we add our function code to this file, then it will be included by default within every dashboard page.  Note, it may be necessary to be add it again after an OBIEE upgrade, so a master copy should reside in version control.

 

 

    Running JavaScript on Page Loads

 

How do we ensure that our JavaScript function will be run from every page immediately after the page load has been completed, and does so without interfering with other OBIEE functionality?

 

If we look at the HTML for a dashboard page, just before the “body” tag, we find:

* 
Dashboard Page HTML - window.onload

 

The “onload” event handler defines what functionality to perform once a web page has been loaded.  We can see that this functionality is contained in JavaScript function “NQOnLoadEvent”, which in turn calls JavaScript functions “NQOnWindowLoadsaw_300_1” and “NQOnWindowLoadsaw_300_2”.  Looking at the last of these functions we can see that it calls JavaScript function “saw.dashboard.reload”.  This is a key OBIEE function that is called whenever the dashboard is loaded or reloaded.  So if we add our call to “cs_html_everywhere” at the end of this function, then our web page manipulations will be made after OBIEE has done all its work in formatting the web page.

 

Note, we can often add JavaScript to manipulate the HTML DOM model in a text section or a narrative view that is the last on a dashboard page.  However, this won’t work with HTML “body” replacements.  In particular, only the part of the body prior to the manipulating JavaScript will have been loaded when such a script runs.  And OBIEE places many lines of code implementing key functionality between the last user-accessible location (accessible in terms of custom dashboard code) and the end of the body section.

 

Function “saw.dashboard.reload” can be found in script “portalscript.js", in folder:

 

<OracleBI>\oc4j_bi\j2ee\home\applications\analytics\
   analytics\res\b_mozilla\dashboards

 

Note, there are two exits from this function so our call to “cs_html_everywhere” must be placed just before the “return” statement as well as at the end of the function (adding a suitable moniker makes it easy to locate all custom script locations):

* 
Modified Function saw.dashboard.reload

 

 

    Summary

 

So now all we have to do is open our dashboard page to see:

* 
HTML Everywhere

 

just as our user requested.  The advantage of this approach is that once the supporting functions are in place, the only extra effort required in writing HTML everywhere is to add the prefix and postfix delimiter tags.

 

Of course, with this structural support in place it’s easy to include many kinds of generic functionality by adding more code to function “cs_html_everywhere”.  In particular, it’s possible to do so retrospectively for an existing OBIEE application.

 

How stable will this solution be to future OBIEE upgrades?  Well, in the absence of “common.js” and a call to “windows.onload” we could have just added a call to a JavaScript function on each dashboard page to include two external functions, one which defines the function that updates the HTML DOM model, and another that defines the event handler.  However, in practice, it’s very unlikely that Oracle will dispense with (1) a common set of JavaScript functionality that is loaded on all dashboard pages, and (2) a single function that is called at the end of all load/reload processes.  So at worst it’s only likely that the function names will change with an upgrade (this is also unlikely given the frequent references to “NQ” – initials of the company that was purchased by Siebel before it was, in turn, purchased by Oracle).

 

Perhaps the most surprising issue to ponder upon is why Oracle, and Siebel before them, did not make this generic functionality available – a check box to “Treat Text As HTML” for all the relevant GUI components.  Given the frequency with which users request functionality that cannot be directly implemented using the GUI, we must conclude that the galaxy in which “planet BI tool vendor” is to be found lies many light-years distance from that occupied by “planet user”!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章