Friday, May 27, 2016

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

If you followed some of my previous posts related to Fluid Branding, you would have noticed that I complained a fair bit about 8.54 and 8.55 not delivering jQuery by default for Fluid UI. Although, I still think that it is a missing feature in 8.54, I found that Oracle has delivered something better in 8.55. This is not really mentioned in great detail anywhere, but if you look on the web server, you will find that Oracle JET (Oracle JavaScript Extension Toolkit) is available. For those who are not aware, it is like a package of all the commonly used open-source js and css libraries put together. In addition to the open-source libraries, Oracle JET also contains a set of Oracle contributed js libraries.

Web Server:


Oracle JET usage in charts:

I also noticed this in a few Fluid pages containing charts, when I inspected the DOM elements. I have not seen widespread usage in other areas.


If you have read some of my previous Fluid Branding posts (Part 5B and Part 5C) where I described how I created a Fluid JavaScript Injection Bootstrap and few other advanced Branding topics using JavaScript and JQuery, you would notice that I hacked (for lack of a better term) my way through the requirements. I will admit that my js code was probably not the most efficient. In this post and perhaps other follow up posts (Part 2 and Part 3), I plan to revisit some of the javascript and rewrite the logic using Oracle JET (e.g.: Fluid JavaScript Injection Bootstrap and Environment Specific Header for Non-Prod databases).

In the following sections, I intend to cover the topic of using JQuery and JQueryUI libraries safely in conjunction with requireJS - available in Oracle JET on PeopleTools 8.55+ applications. When I say 'safely', I mean to safely manage dependencies using requireJS. Jim Marion has already written about how to achieve this in an 8.54 environment (and probably in several other posts on his blog where he covered the usage in previous tools versions as well).

If you are a fan and a follower of Jim Marion's PeopleSoft Journal blog (like myself) and if you are wondering why he has been relatively quiet (for his standards) in the past few months, he has been blogging all along at a ferocious pace and putting out some great content on Oracle JET in his new blog Jim's JavaScript Journal - tailored for javascript and Oracle JET applicable to all users and not specific to PeopleSoft!!! :)

Global JavaScript Injection Bootstrap for Fluid UI:

My requirements for this bootstrap are still the same as in 8.54. Since there was and still is no way to inject custom javascripts globally in Fluid, I want to create a least intrusive and highly configurable bootstrap to easily inject javascripts on the fly.

Step 1: Create a custom javascript object for the Bootstrap code

Navigation: Navigator > PeopleTools > Portal > Branding > Branding Objects (JavaScript Tab)

Note: This javascript object needs to be added online so that it provides a configuration to inject additional javascript objects.

Object Name: CSK_FL_BOOTSTRAP_JS


- This javascript object might seem a lot lengthier than my previous version but it should be cleaner and a lot more efficient.
- getScriptUrl: I borrowed this function from Jim Marion's post. It provides a nice and clean way to derive the URL for a javascript object.
- cskLoadJS: I improvised this function from the delivered loadScript function (PT_CHART_LOAD). It helps with adding a javascript (with URL to the source code) as a script element to the DOM - head section.
- cskInjectJS: I created this function just to separate the actual configuration to add/load a list of custom javascripts. Right now it only has one custom javascript.
- Immediately invoked javascript code:
  1.  Load requireJS: The first thing I do is to load requireJS. You will notice that I am not referencing any object from the database (as a javascript object) and instead I am pointing directly to the require.js library on the web server where Oracle JET resides. Much easier to render directly from the web server!
  2. Load CSK_REQUIRE_CFG_JS: Next I load a custom javascript object (again added online so it can be updated in the future). My requirejs.config is very simple at this stage and I only included couple of library paths (JQuery and JQueryUI). We could configure additional paths in the future based on other requirements.
  3. You will notice that I am passing cskInjectJS as a callback function parameter to cskLoadJS function when I load the CSK_REQUIRE_CFG_JS object. This would ensure that cskInjectJS would get fired after the CSK_REQUIRE_CFG_JS javascript is loaded.
Object Name: CSK_REQUIRE_CFG_JS


Step 2: Add custom code to PT_HEADERPAGE.Activate (Page Activate PeopleCode)

This step is the same as what I did in 8.54. PT_HEADERPAGE is a header page that is part of all Fluid UI components and is mainly used for navigation purposes. We will be adding a line of code to inject our bootstrap javascript using peoplecode.


Custom PeopleCode:

/* CSK Custom Javascript Bootstrap for Fluid - Start */
AddJavaScript(HTML.CSK_FL_BOOTSTRAP_JS);
/* CSK Custom Javascript Bootstrap for Fluid - End */


Step 3: Add CSK_FL_BOOTSTRAP_JS to the custom Homepage Header (Classic)

Step 2 takes care of the Fluid UI and associated components. Although, in 8.55, the navigation header is unified and consistent across Classic and Fluid, the way Classic and Fluid get rendered are slightly different. The PT_HEADER page object is not used in Classic. This means that step 2 would have no effect in the Classic homepages and components. We could just add CSK_FL_BOOTSTRAP_JS to the Branding System Options (as I previously showed in my Branding 8.55 post). But I want to avoid that because I found that adding scripts to Branding System Options could invoke them more than once which is not desired in this case (I will write about this topic in a separate post later). Alternatively, I simply add CSK_FL_BOOTSTRAP_JS to my custom homepage header configured on my theme (refer: Branding 8.55 - Part 1).


Step 4: Inject Javascript

Now that we have our custom javascript object (CSK_FL_BOOTSTRAP_JS) injected into all Fluid UI and Classic homepages and components, we can use that as a configuration to further inject other javascript objects.

 
Right now, I only added one javascript object CSK_FL_DBNAME_JS (which I will describe in the next section) to cskInjectJS. But you can see how we can easily inject additional javascript objects as needed.

Creating an environment specific header for Non-Production databases:

In the previous section, I described how to create a javascript injection bootstrap for Fluid. I used Oracle JET to load JQuery and JQueryUI while managing dependencies using requireJS. Now, let us see an example of how we can inject a custom javascript using the bootstrap. The custom javascript is a rewrite of my previous javascript (created for 8.54 and extended for 8.55), to create an environment specific header for Non-Production databases.

Object Name: CSK_FL_DATABASE_JS


You can see how I used requireJS to take care of loading JQuery for me. All I am doing is mentioning the libraries that I need and let requireJS do the dependency management! A lot cleaner!

Note: Please remember to add the custom styles to both the Classic - Theme Style Sheet (CSK_BRAND_CLASSIC_TEMPL_FLUID) and the Global Override Style Sheet for Fluid (CSK_BRAND_FLUID_TEMPLATE). Refer Branding PT 8.55 - Part III for more details.

Results:

Classic:


Fluid:


Notes:

  1. Details of the environment used for this post: HCM 9.2 - PUM Image 17 - PeopleTools 8.55.03.
  2. If you find any inconsistent results while going through any of the steps detailed in this post then please make sure you bounce your web and app servers and purge the cache.

18 comments:

  1. Hi Sasank, I am trying to replicate the same in PUM Image 21 environment and I am having a hard time replicating this. If possible, could you please create a project with the objects and share the package?

    ReplyDelete
    Replies
    1. See if this helps. I will try to create a project when I get a chance.

      Delete
    2. I meant if this page helps clarify the injection framework:
      https://pe0ples0ft.blogspot.com/p/javascript-injection-framework.html

      Delete
  2. Thank you!! I am able to replicate it.. Time to tweak it now :)

    ReplyDelete
    Replies
    1. Great. Thanks for letting me know. All the best! :)

      Delete
  3. Trying to get this started ... so Something shows up..
    But get nothing.... Noticed your directoy structure is ends with ps while I see a dbnamid... Or are you assuming dbname
    /psoft/ptcfg855/webserv/fndev/applications/peoplesoft/PORTAL.war/fndev/oraclejet/

    ReplyDelete
    Replies
    1. The path will not be the same for all environments. My PUM image has ps as the web domain name. In your case, it appears to be fndev. So you will have to adjust the URL according to your environment.

      Delete
  4. Sasank, the bootstrap doesn't seem to work with Peopletools 8.56. we now get the following errors:
    [Violation] Avoid using document.write().

    ReplyDelete
    Replies
    1. I tested this in 8.56 and did not encounter any issues with the JS Injection Framework.

      Are you sure you are using my latest code from this post:
      https://pe0ples0ft.blogspot.com/p/javascript-injection-framework.html

      Also, I don't recall using document.write in any of JS injection framework (bootstrap) code. Where exactly do you have document.write? Is that part of your custom javascript code that you are injecting? If so, I would encourage you to avoid document.write if possible and use DOM to manipulate the HTML.

      Delete
    2. Hi Sasank- I just tested on 8.56.03. had to update library names to jquery-3.1.0.min.js & jqueryui-amd-1.12.0.min

      Other than both above, Everything worked flawless. Thank you.

      Delete
    3. @Ravi Indela -Great to hear! Thank you for letting us know.

      That was my experience in 8.56 as well which I mentioned in this blog post.
      https://pe0ples0ft.blogspot.com/2017/08/peopletools-856-branding-part-1.html

      Delete
  5. Hi Sasank..thanks!! Its a great blog and it saved me a lot of time.

    Just a quick question, in addition to adding a database name on the header, how can I get a date from the custom database table which stores the refresh date.
    so it should display like
    "FSDEV: Refresh date '01/01/2018'.

    Thanks a lot in advance
    Kris

    ReplyDelete
    Replies
    1. Hi Kris - Someone asked a similar question in another post. Here is one option to include the refresh date on the header:
      https://pe0ples0ft.blogspot.com/2017/08/peopletools-856-branding-part-1.html#c6077381674964784189

      Delete
    2. thanks a lot Sasank. It's working.

      Delete
    3. Hi Sasank, if I update the message catalog with a new data it is not being updated on the fluid header. I think it's picking up the message from cache..

      Do we need to force the script to pick up the message from message catalog?

      My code



      Thanks,
      Kris

      Delete
  6. Thanks a lot Sasank. It's working with %message.

    but if I update the message catalog with a new data it is not being updated on the fluid header. I think it's picking up the message from cache..

    Do we need to force the script to pick up the message from message catalog everytime?

    ReplyDelete
  7. Sasank, Hello, I am having a similar issue to Kris. You Oracle JET code is working perfect, except my client wants to display the UserId as well. But it seems that the JS is cached on the web server, and so it will always display the UserID of the first person who logged in and cache was created. Any idea how to fix this without a drastically different approach? Thanks!

    ReplyDelete