Monday, June 13, 2016

PeopleTools 8.55 - Oracle JET - Using ACE Editor for Online Branding Objects (HTML, JavaScript, Style Sheets)

Have you ever wondered if there is a better way to edit the "Branding Objects" that are available online (PeopleTools > Portal > Branding > Branding Objects)?

If you have managed Branding Objects (JavaScript, HTML and CSS) online, you would have noticed that the editor is a simple 'textarea'. It is not a great UI and it makes it really difficult to manage/write anything more than a few lines.


Although it is great that, starting with PeopleTools 8.53, we now have the ability to manipulate javascript, html and css objects online (instead of using App Designer), the major part of reading/understanding/writing the code probably needs to be done outside on a text editor which has better support for the markup/syntax.

Why not a code editor for the web?

If you attended Jim Marion's popular session 'PeopleTools Tips and Techniques' either at Oracle OpenWorld 2015 conference or HEUG - Alliance 2016 conference, you might have seen him show us how he created a custom page to manage javascript content using ACE Editor. When I asked him how he built something like that, he mentioned that he used AJAX to marshal the content and the page itself is fronted by a component for searching, but is really an iScript for display and an iScript for saving. It was a brilliant idea to use a high performance code editor to manage such objects (some features/benefits include auto complete, syntax highlighter for over 100 languages, better maintenance/display of indending/outdending, folding function/code modules and overall better readability).

Jim's approach involved storing the javascript contents in a custom table and then referencing them as needed. I wanted to take the same idea and create a mechanism to integrate ACE Editor with any page field (textarea). At the same time, I did not want to customize anything. So, I want my approach to be very similar to creating/enabling Rich Text page fields but instead of using App Designer, I want to simply inject a custom javascript to the page and enable the ACE Editor. Another difference with my approach is that I want to use JavaScript and the component processor to take care of marshaling and saving the data instead of using the AJAX/IScripts option.

Do any challenges come to mind?

- How do we replace the existing 'textarea' on the page with the ACE Editor?
- Next, how do we transfer the contents of the ACE Editor to the page field 'textarea'?
- Next, how do we make the component processor accept and honor this change made to the buffer via JavaScript (especially because we are not customizing the page and the page field may not have the 'Modifiable by JavaScript' setting enabled)?

Here are steps I went through to integrate ACE Editor with the PeopleTools - Branding Objects Page. If you like this idea and implementation, then please click here to vote for it on My Oracle Support Community.

  1. A similar approach could be used to extend the ACE Editor functionality to any other page field - textarea.
  2. I used the latest version of my 'Global JavaScript/Style Sheet Injection Bootstrap' (using Oracle JET and more importantly requireJS) to inject a custom javascript into the 'Branding Objects' page. If you choose not to use this approach, then you will need to find an alternative way to inject the custom javascript but the core functionality of the js code should work as described. (Refer: 'Using Oracle JET' series - Part 1, Part 2, Part 3 and Part 4).
Step 1: Download the ACE Editor library and store it locally on the web server

I downloaded the ACE Editor library from the following github URL and placed it on my web server:

Web Server:

Just to show the library folder structure, here is a screenshot highlighting the path to the ace.js file.

Step 2: Add new function cskGetFormName() to our JS Bootstrap (CSK_FL_BOOTSTRAP_JS)

Function Name: cskGetFormName

This function helps us resolve the %FormName meta-html which is not available currently for client side javascript. So, we cannot use it, for example, as submitAction_%FormName in a client side javascript. The expectation is that it would resolve itself to submitAction_win0, submitAction_win1 or submitAction_winN depending on the current window. So, I wrote this function to determine the %FormName portion as a string, which I will be using in the next step as part of FSU_ACE_CFG_JS javascript code.

Step 3: Create Custom JavaScript Object (CSK_ACE_CFG_JS) to configure the ACE Editor on the desired page

JavaScript Object: CSK_ACE_CFG_JS

Explaining the Script:
  • First, you will notice that I am adding the ACE Editor library path to the requireJS configuration locally instead of using the requireJS configuration script object (CSK_REQUIIRE_CFG_JS). The reason I am appending to the requireJS paths locally is because, we don't want this library to get loaded for the entire application, rather just conditionally to a specific page. In step 4, I will detail how to achieve that using the Global Injection Bootstrap (CSK_FL_BOOTSTRAP_JS).
  • Next, I am defining jquery, ace.js and jqueryui as dependencies for the function execution using requireJS.
  • Inside the function execution, I included BOOTSTRAP 3.0.0 (which was downloaded from this link and stored in a custom object) and JQUERY 1.8.17 (delivered object) CSS. I am using the custom function cskLoadCSS to take care of the CSS loading.
  • Next, I search for the textarea (id="PTBR_MGOBJ_WRK_PTBR_HTMLAREA1"), hide it and replace it with the ACE Editor div.
  • Now the delivered textarea is hidden and our custom ACE Editor is in the DOM. Further, I used a basic set of configuration options for the Editor which we can certainly expand depending on our use case (ACE Editor is highly configurable). Also, I am dynamically setting the mode of the Editor to either html, javascript or css depending on the object type that we are updating. As part of the Editor configuration, I also initialized the contents of the ACE Editor with the contents of textarea.
  • Lastly and most importantly, we update the textarea (now hidden) with the latest contents of the ACE Editor any time there is a change in the editor contents. 
  • addchg_%FormName Function: The trick to make the component buffer accept and honor the changes made to the textarea (PTBR_MGOBJ_WRK_PTBR_HTMLAREA1) - via client side javascript - is to use the addchg_%FormName function. I had no idea about the existence of such a function and its significance. I learned about this gem from Chris Malek while discussing and troubleshooting an unrelated issue with Fluid!

Step 4: Conditionally Load ACE Editor Config JavaScript (CSK_ACE_CFG_JS) using the Global JavaScript Injection Bootstrap

The conditional logic to only load CSK_ACE_CFG_JS on the Secondary Page PTBR_ADDHTML_SEC, can be found in the cskInjectJS function which is part of CSK_FL_BOOTSTRAP_JS object. An updated version of CSK_FL_BOOTSTRAP_JS source code can be found here.





Now we are ready to enjoy the ACE Editor for writing code! Once again, if you like this idea and implementation, then please click here to vote for it on My Oracle Support Community.

Sunday, June 12, 2016

PeopleTools 8.55+ - Using Oracle JET (JQuery, JQueryUI, requireJS and more) - Part 4

This post is a continuation of my 'PeopleTools 8.55+ - Using Oracle JET' series (refer: Part 1, Part 2 and Part 3).

In Part 1 (refer: Global JavaScript Injection Bootstrap for Fluid UI - Step 3), I pointed out that using 'Branding System Options' for injecting javascript in Classic pages would result in them getting invoked more than once (per header, pagelet, target frame, etc.). For most Branding Tasks, this might not be necessary since we are only dealing with the header portion of the HTML and other general styling.

All the topics described so far in this series worked fine with the 'Global JavaScript Injection Bootstrap' getting invoked just once as detailed in Step 2 and Step 3. But there may be some advanced requirements possibly outside the scope of Branding where we may intend to inject the Global JavaScript once per header, pagelet, target frame, etc. in order to manipulate the target content area, form data/component buffer and so on. For such cases (to be detailed in a subsequent post), we could use the following alternative step to include our 'Global JavaScript Injection' Bootstrap JS.

Note: The following step would replace Step 2 and Step 3 (which means we need to revert both those changes).

Add CSK_FL_BOOTSTRAP_JS to Classic and Fluid using PT_UTIL JS object:

PT_UTIL is a delivered javascript object that is included in Fluid (via PT_COMMON_FMODE) and Classic (via PT_COMMON). My thought was to simply include our custom bootstrap javascript object in PT_UTIL (using the %include meta-html).

Additionally, I updated the javascript CSK_FL_DBNAME_JS as follows:


The only change was the window.self == condition to avoid the following 'custom header repetition' problem.

The rest of the javascript objects detailed so far in this series should work as-is without any issues.

Saturday, June 4, 2016

PeopleTools 8.55: What is %include Meta-HTML function?

I found this gem of a Meta-HTML function that has been hiding deep in the bowels of PeopleTools javascript.

I was digging into some of the delivered javascript functions in a HCM 9.2 PUM Image 17 which is on PeopleTools 8.55.03. When I looked in the PT_COMMON HTML object, I almost jumped out of my couch. :)

Just to be sure, I checked if this function exists in 8.54 or prior tools releases. Correction: I found one occurrence in 8.54 (PT_PAGESCRIPT_FMODE) which leads me to believe that this function was probably introduced in PeopleTools 8.54 (so it is not new to 8.55 as I previously thought).

It appears that this undocumented (since it is not referenced anywhere in PeopleBooks) Meta-HTML function can be used to include other javascripts objects inline. This can be very handy!

Let us see how this works.

I created a custom JavaScript object (CSK_TEST) using Branding Objects.

Next, I added this to my Bootstrap JavaScript (CSK_FL_BOOTSTRAP_JS) as follows (Refer: PeopleTools 8.55+ - Using Oracle JET (JQuery, JQueryUI, requireJS and more) - Part 1).

Let us see this in action.

Here is how the %include function gets resolved at runtime:

I can see many great uses for this Meta-HTML function! :)