Disclaimers and Background

Yes, there are several examples of OPA controls in javascript this post.  But, my pure "dev days" have been replaced by policy discussions.

 

Disclaimer #1: Forgive my javascript coding if it isn't up to par.

Disclaimer #2: I expect to upgrade this blog post content in the future.

Disclaimer #3: As always, I am not an Oracle employee, so use advice in this blog at your own risk.

 

As an architect, I am well aware that for the end user, the interface is the system.

 

To have a good interface, you must control styling and control the controls themselves.  However, OPA is about policy, not styling.  Lucky for us, OPA interviews are so dang easy to create!  For a "human interface" channel, OPA interview screens are extremely quick and good for the average person.

 

However, I have seen OPA interviews moved to PHP (instead of running in OPA) just due to styling.  Really I have, and I am not just saying that.

 

I have noticed that what every project asks on day 1 is "How do I put our organization's custom CSS for those menus and labels?"

 

Historically, what hasn't been great for OPA presentation UX is this following process:

 

In the old days, OPA modelers presented some finished OPA interview screens in a web browser.  Then the presentation designers ran the interview, parsed the HTML using browser developer tools and created the following (not-opa-recommended) types of jQuery:

 

$(document).on("click",function(event){

 

    if(!($(event.target).is("div.arrow_box") || $(event.target).is(".list-input")|| $(event.target).is(".ui-button-icon-primary") || $(event.target).is(".owd-input")))

        $('.arrow_box').addClass( "my-control-hidden" ); });

 

After that, the reverse engineered CSS was applied.  OPA would be upgraded a few years or months later, and styling things would break.

 

So, what is the OPA recommended UX styling (as of 2018) and how do we give designers more control?  How do designers learn to design to it???

 

On of my proposed solutions: Give your presentation team an OPA style playground project at the beginning of development.

 

May I suggest starting out with a playground OPA project for testing UI controls and styling?  I attached an example style playground.  Download the example and play with it, then hopefully your presentation team can avoid the whole "let's use PHP." 

 

Here are the steps I followed to create my presentation style playground project.

 

Step 1:  Read (and share) the documentation

Bookmark the following after reading them and share them for reference:

 

1) the Web Interview Developement Documentation for CSS/Javascript integration: Oracle Policy Automation Documentation Library

2) the Design Interviews Documentation for the in-program styling: Oracle Policy Automation Documentation Library

 

Note, I am on 18c.  In my experience, it isn't enough to just point designers at documentation, they need to be shown OPA.  Sit down with them for a few hours.

 

Step 2: Add the "custom files" directory to the project

Let OPA know you are going to use custom files.  Go to Interview->styles and click the "Custom Files" button.

 

Agree to the warning...

The directory will appear like magic.

 

Step 3: add jQuery, and other .js script libraries etc...

(Be aware, there are limitations.  Don't expect a full framework to be able to be included.)

jQuery is fine. I like to put my own jQuery, popper, and tooltip .js files into the project, although I think OPA already comes with some of this. 

 

 

Step 4: Get the organization's color palette from your design team and apply it to the "styles"

If your design team is not picky, and you are not a design guy, go to a site like Color Safe - accessible web color combinations or like https://flatuicolors.com/ and pick colors that look good together.  Make a "best guess" and give yourself a basic screen.  Really, I just changed the navigation bar and called it a day.

 

Note: picking colors that are WCAG compliant is really frustrating, but think of how frustrating it is to have trouble seeing...  Keep at it and never let the colors be anything but WCAG compliant. Hopefully you can get a palette from your design team that already covers WCAG.

 

Step 5: Figure out a "strategy" to style individual OPA controls, add your own .js and ask presentation guys for a .css file.

 

Strategy??? One possible "strategy" is to use control "properties" to identify a className for any "special control."  See Oracle Policy Automation Documentation Library Once a className is identified, the presentation guru's have a field day with CSS!

 

The presentation team and the policy team agree on properties that the controls should have for certain behaviors.  For example, here are custom properties on a label that gives a className of interview if my javascript is included.

 

Here is an example javascript to add classNames to my controls for CSS usage:  Note that I use a broad brush and make it possible to add a class to basically any control.  I do wonder if there is a more concise way to write this in javascript, but this works.

 

Eventually the javascript and CSS files should be turned over to the proper teams after they understand what is happening.  Policy folk shouldn't worry about javascript / CSS in my opinion.

 

//

// First, I make it possible to use CSS styling on any basic type of control

// Just add 2 properties to the control in the OPA interview:

// type : CSS

// className : <<class name to use in the CSS>>

//

OraclePolicyAutomation.AddExtension({

   style: {

        question: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

         },

       label: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        textInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        textAreaInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        calendarInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

             }

        },

        dropDownInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        filterDropDownInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        listInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        radioInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        checkboxInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        captchaInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

        },

        signatureInput: function(control, interview){

             if (control.getProperty("type") == "CSS" ) {

                  return { className: control.getProperty("className") }

            }

       }

  }

});

 

 

Step 6: Add any known necessary custom controls to a project.

I "cheat".  I add ability to turn a label into an html object and vice-versa early in my projects, even if it doesn't get used.  That provides flexibility.  Oracle, please don't crucify me...  As such, I can display videos inline, pdf files, get around the html restrictions, etc...

 

After our designers / developers get a look at my code, they can then modify it accordingly.

 

These are all examples.  I will let you guys mull over the examples and change them as you see fit.

 

My first custom control example is a label that when clicked can hide other labels of a specific class on the interview screen.  Why not use OPA hide/show functionality?  You could use OPA and I recommend OPA logic as a default.  In this case, we have screen "instruction text" that really is not part of an interview but is presented in one or more labels.  The help text is not used for any other interview channel and the help text contains html formatting, etc.  In other words, the help text is not part of the interview proper and we just want to be able to show/hide labels with the click of a label for instructional purposes on the screen.  tooltip.js is also good for this.

 

//

 

// Second, I need some way to show/hide sections...

// Just add 3 properties to a label in the OPA interview:

// type : Reveal

// target : <<class name of whatever we want to show/hide>>

// className : <<class name to use in the CSS>>

//

OraclePolicyAutomation.AddExtension({

   customLabel: function(control, interview) {

     if (control.getProperty("type") == "Reveal" ) {

       return {

         mount : function(el){

           var x = document.createElement("H2");

           var t = document.createTextNode(control.getCaption());

           x.className = control.getProperty("className");

           x.onclick = function() {

             $( "." + control.getProperty("target") ).toggle("slow"); 

           };

           x.appendChild(t);

           $(function(){

             el.appendChild(x);

             $("." + control.getProperty("className")).parent().parent().next('.opa-container-vertical').addClass(control.getProperty("target")); 

           });

         }

       }

     }

  }

});


//

// Third, I need some way to show pdfs, word docs and video on screen...

// Just add 4-5 properties to a label in the OPA interview:

// type : Object

// data : <<url of the media>>

// className : <<class name to use in the CSS>>

// localResource : true | false

// mediaType : <<IANA Media Type>>

//

OraclePolicyAutomation.AddExtension({

   customLabel: function(control, interview) {

     if (control.getProperty("type") == "Object" ) {

       return {

         mount : function(el){

           var x = document.createElement("OBJECT");

           var tx = document.createTextNode("alt : ");

           var a = document.createElement("A");

           var ta = document.createTextNode(control.getCaption());

           x.className = control.getProperty("className");

           if (control.getProperty("localResource") == "true") {

             x.data = "${resources-root}" + control.getProperty("data");

           } else {

             x.data = control.getProperty("data");

           };

           a.href = control.getProperty("data");

           if (control.getProperty("mediaType")) {

             x.type = control.getProperty("mediaType")

           };

           a.appendChild(ta);

           x.appendChild(a);

           x.appendChild(tx);

           el.appendChild(x);

         }

       }

     }

  }

});


//

// Fourth, I need some way to manage images, funny enough...

// Just add 3-5 properties to a label in the OPA interview: (height and width both optional)

// type : imgCSS

// src : <<the source link>>

// localResource : true | false

// alt : <<alt text for image>>

// className : <<class name to use in the CSS>>

// width : <<optional pixels>>

// height : <<optional pixels>>

//

OraclePolicyAutomation.AddExtension({

   customLabel: function(control, interview) {

     if (control.getProperty("type") == "imgCSS" ) {

       return {

         mount : function(el){

           var x = document.createElement("IMG");

           x.className = control.getProperty("className");

           if (control.getProperty("width")) {

             x.width = control.getProperty("width");

           };

           if (control.getProperty("height")) {

             x.height = control.getProperty("height");

           };

           x.alt = control.getProperty("alt");

           if (control.getProperty("localResource") == "true") {

             x.src = "${resources-root}" + control.getProperty("src");

           } else {

             x.src = control.getProperty("src");

          }

         el.appendChild(x);

         }

       }

     }

  }

});


//

// Fifth, I need some way to show html that has been embedded inside of an OPA attribute...

// Oracle will not like this.  It gets around their general html restrictions...

// Just add 1-2 properties to a label in the OPA interview:

// type : Attribute

// className : <<optional class name to use in the CSS>>

//

OraclePolicyAutomation.AddExtension({

   customLabel: function(control, interview) {

     if (control.getProperty("type") == "Attribute" ) {

       return {

         mount : function(el){

           var x = document.createElement("SPAN");

           let fragmentFromString = function (strHTML) {

             return document.createRange().createContextualFragment(strHTML);

           }

           let s = fragmentFromString(htmlDecode(control.getCaption()));

           if (control.getProperty("className")) {

             x.className = control.getProperty("className");

           }

           x.appendChild(s)

           el.appendChild(x);

         }

       }

     }

  }

});


// Helper functions to decode and encode html as provided by OPA

//

function htmlDecode(value) {

   return $("<textarea/>").html(value).text();

}

function htmlEncode(value) {

   return $('<textarea/>').text(value).html();

}

 

 

Step 7: Add every control / option to a project and let the designers mull it out and test the results.  The designers are involved from Day 1 on any project I work with.

 

This may confuse some of you, but the idea is actually simple.  I put every combination of control onto interview screens, so we could see how the styling "worked".

The menus can be examined, the entities, relating entities, every type of input and output is on interview screens for UX examination and alteration.

 

The net result is that someone should go through every screen of the playground interview and approve of the styling.  If that is done, 90% of a production project based on (or including) this project for styling should style correctly.

 

Final, after the styling is done, you can include this project as a base project for others.  You can delete all the screens, rules, and attributes, and keep the rest.  Feel free to ask questions or give suggestions in comments.

 

Again, I may update this blog post with a newer / better version in the future.

 

Enough Talk... sample style playground project is included.