<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2387668883227766307</id><updated>2012-02-16T09:42:44.667-08:00</updated><category term='bike'/><category term='report repository'/><category term='jquery'/><category term='dialog'/><category term='javascript'/><category term='movies'/><category term='beach'/><category term='hikng'/><category term='California'/><category term='peopletools'/><category term='peoplecode peoplesoft'/><category term='peoplesoft'/><category term='bicycling'/><category term='fitness'/><category term='load balancer'/><title type='text'>PeopleSoft Developer Notebook</title><subtitle type='html'>Notes on customizing PeopleSoft applications with PeopleTools, Java, JavaScript and Cloud technologies with occasional adventures into other areas.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-1489850437113195304</id><published>2011-08-26T09:01:00.001-07:00</published><updated>2011-08-26T09:03:06.488-07:00</updated><title type='text'>GenerateComponentContentURL() Fail</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;We have a custom PeopleSoft module that handles requests from another web application. After authentication, this web application initially forwards the request to an iscript that, after identifying the user, redirects her to the appropriate home page. The redirect URL is created using the built-in PeopleCode function,&amp;nbsp;&lt;i&gt;GenerateComponentContentURL()&lt;/i&gt;. Here is an example:&lt;br /&gt;&lt;blockquote&gt;%This.approverHomePage = GenerateComponentContentURL(%Portal, %Node, MenuName.MY_MENU, "GBL", Component.MY_HOME, "", "");&lt;/blockquote&gt;&lt;blockquote&gt;&amp;nbsp;...&lt;br /&gt;%Response.RedirectURL(&amp;amp;userIdentity.getHomePageURL());&lt;/blockquote&gt;&lt;br /&gt;This was working fine until the web application was updated. At that point, the redirect started to fail silently. After a lot of false starts, I determined that&amp;nbsp;&lt;i&gt;GenerateComponentContentURL&lt;/i&gt; was returning an empty string, but I could not figure out why.&lt;br /&gt;&lt;br /&gt;Long story short, the newly-configured web application was using a URL for the iscript that had an invalid node. The url was:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt;"&gt;&lt;a href="https://onlinetime.roberthalf.com/psc/hrfscrp/EMPLOYEE/PSFT/s/WEBLIB_RH_TCAST.NAV_FUNCTIONS.FieldFormula.IScript_Navigation"&gt;&lt;span class="Apple-style-span" style="color: #1f497d;"&gt;https://myapp.com/psc/dbname/EMPLOYEE/&lt;/span&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;PSFT&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #1f497d;"&gt;/s/WEBLIB_CUSTOM.NAV_FUNCTIONS.FieldFormula.IScript_Navigation&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;but should have been:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif; font-size: 15px;"&gt;&lt;a href="https://onlinetime.roberthalf.com/psc/hrfscrp/EMPLOYEE/PSFT/s/WEBLIB_RH_TCAST.NAV_FUNCTIONS.FieldFormula.IScript_Navigation"&gt;&lt;span class="Apple-style-span" style="color: #1f497d;"&gt;https://myapp.com/psc/dbname/EMPLOYEE/&lt;/span&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;PSFT_HR&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #1f497d;"&gt;/s/WEBLIB_CUSTOM.NAV_FUNCTIONS.FieldFormula.IScript_Navigation&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This caused %Node to return PSFT, an invalid node. One would think that&amp;nbsp;&lt;i&gt;GenerateComponentContentURL &lt;/i&gt;would throw an exception in this case, but it just returned an empty string. I also find it interesting that even with an invalid node in the URL, the iscript still ran.&lt;br /&gt;&lt;br /&gt;Thus is life customizing PeopleSoft.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-1489850437113195304?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/1489850437113195304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=1489850437113195304' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1489850437113195304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1489850437113195304'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2011/08/generatecomponentcontenturl-fail.html' title='GenerateComponentContentURL() Fail'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-3756811869024129838</id><published>2011-08-11T11:03:00.000-07:00</published><updated>2011-08-11T11:03:59.145-07:00</updated><title type='text'>Custom Buttons on Modal Pages</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;There are lots of good reasons to use modal pages and components in PeopleSoft. However, one thing you&amp;nbsp;sacrifice&amp;nbsp;is control, especially if you use the delivered Save and&amp;nbsp;Cancel&amp;nbsp;buttons that PeopleTools adds to your pages. There is nothing to stop you from adding your own buttons to the pages, but if you do the delivered buttons are still there, perhaps confusing the user. At least for the modal component, there is a solution. I tried disabling the toolbar in the component internet properties, but the buttons were still there.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wk5fjJa6Ifc/TkQYl-A8bkI/AAAAAAAADpw/cAsPnalBsBs/s1600/properties0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="287" src="http://1.bp.blogspot.com/-wk5fjJa6Ifc/TkQYl-A8bkI/AAAAAAAADpw/cAsPnalBsBs/s320/properties0.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Then a co-worker (thanks Giri) pointed out that if you actually uncheck the Save and Cancel checkboxes, the buttons are not shown. Wow. He's right. Problem solved. Is this a bug? Probably. Btw, we use PeopleTools 8.49.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-_DeOWAEGyMQ/TkQYk4xALOI/AAAAAAAADps/DqWD5uuyBr0/s1600/properties1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="288" src="http://2.bp.blogspot.com/-_DeOWAEGyMQ/TkQYk4xALOI/AAAAAAAADps/DqWD5uuyBr0/s320/properties1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-3756811869024129838?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/3756811869024129838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=3756811869024129838' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3756811869024129838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3756811869024129838'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2011/08/custom-buttons-on-modal-pages.html' title='Custom Buttons on Modal Pages'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-wk5fjJa6Ifc/TkQYl-A8bkI/AAAAAAAADpw/cAsPnalBsBs/s72-c/properties0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-4304399987823969701</id><published>2011-08-08T10:21:00.000-07:00</published><updated>2011-08-11T10:17:09.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='peoplecode peoplesoft'/><title type='text'>Get Rid of Unwanted Save Warning</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-rjcQQxw7Ij0/TkAauEsqGYI/AAAAAAAADpU/eafuT29PRK0/s1600/SaveWarning.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="78" src="http://4.bp.blogspot.com/-rjcQQxw7Ij0/TkAauEsqGYI/AAAAAAAADpU/eafuT29PRK0/s320/SaveWarning.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Have you ever had a&amp;nbsp;component&amp;nbsp;that gave you unwanted Save Warnings. I recently had to deal with this problem on a page that had a custom button that among many other things called doSaveNow() and then a transfer.&amp;nbsp;Despite&amp;nbsp;calling&amp;nbsp;doSaveNow, the transfer resulted in a Save Warning. I traced the PeopleCode, but could not find any&amp;nbsp;change&amp;nbsp;between the save and transfer that should result in the warning. Frustrated, I searched online for a solution. I found an undocumented PeopleCode function designed for this situation -&amp;nbsp;SetSaveWarningFilter( True).&lt;br /&gt;&lt;br /&gt;Calling&amp;nbsp;SetSaveWarningFilter with True input parameter causes the subsequent page to ignore the SaveWarning. It's not perfect because user is shown the page that would display the Save Warning, but then routed to the next page as if the user clicked the cancel button on the Save Warning dialog. In our&amp;nbsp;situation&amp;nbsp;this was good&amp;nbsp;enough.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-4304399987823969701?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/4304399987823969701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=4304399987823969701' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/4304399987823969701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/4304399987823969701'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2011/08/get-rid-of-unwanted-save-warning.html' title='Get Rid of Unwanted Save Warning'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-rjcQQxw7Ij0/TkAauEsqGYI/AAAAAAAADpU/eafuT29PRK0/s72-c/SaveWarning.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-3184562364144587167</id><published>2011-04-12T17:07:00.000-07:00</published><updated>2011-04-12T17:07:48.968-07:00</updated><title type='text'>How Select Options are Set on a PeopleSoft Page</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;I just learned something new about how&amp;nbsp;PeopleSoft&amp;nbsp;pages work. We are using PeopleTools 8.49.29. Your mileage may vary.&lt;br /&gt;&lt;br /&gt;It appears that if more than one Select (dropdown) have the same options, PeopleTools puts the options into a JavaScript&amp;nbsp;array, then populates the options with JavaScript after the page loads. I learned this the hard way because I had a qQuery function that ran on page load and uses the select values. It was not working right because the select values were not set when the script ran.&lt;br /&gt;&lt;br /&gt;The function that populates the options and sets&amp;nbsp;the&amp;nbsp;selected values is&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;setSelectElemOptions_win0()&lt;/span&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;. I solved my problem by creating a proxy for this function and adding a call to my function. This ensures that my function runs after the Select options are set. &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;&lt;a href="http://danielkibler.blogspot.com/2010/11/using-javascript-in-peoplesoft-proxy.html"&gt;See my previous post on how to create a proxy.&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Here's the code.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;  // proxy the setSelectElemOptionsProxied function to ensure Select Options&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;   // are set before totalHours is called on page load&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;   var setSelectElemOptionsProxied;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;    (function() {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;     // proxy setSelectElemOptionsProxied&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;     setSelectElemOptionsProxied = setSelectElemOptions_win0;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;     setSelectElemOptions_win0 = function() {&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;       setSelectElemOptionsProxied(); // call the original function&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;       totalHours(); // my function&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;     };&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="white-space: pre-wrap;"&gt;   })();&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small; white-space: pre-wrap;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-3184562364144587167?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/3184562364144587167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=3184562364144587167' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3184562364144587167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3184562364144587167'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2011/04/how-select-options-are-set-on.html' title='How Select Options are Set on a PeopleSoft Page'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-3362503148011821772</id><published>2011-02-17T13:14:00.000-08:00</published><updated>2011-09-03T14:03:15.719-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='peoplesoft'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='peopletools'/><category scheme='http://www.blogger.com/atom/ns#' term='dialog'/><title type='text'>Using JavaScript in PeopleSoft: Creating your own dialog boxes</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;In previous posts, I've described how I have been using JavaScript to enhance our PeopleTools 8.49&amp;nbsp;application. I've covered calculations and validation, and showed how you can proxy "delivered" PeopleSoft&amp;nbsp;JavaScript&amp;nbsp;to enhance your pages.&lt;br /&gt;&lt;br /&gt;In this post I'll show how we are replacing the Peoplesoft confirmation (Yes/No OK/Cancel) message box with our own slick&amp;nbsp;modal&amp;nbsp;dialog boxes. I'm sure you'll agree with me that the bare, ugly pages produced by using PeopleCode messageBox() for confirmation aren't up to modern web standards. I went searching for a way to replace it. I found jQuery UI dialog.&amp;nbsp;&lt;a href="http://jqueryui.com/"&gt;jQuery UI&lt;/a&gt; is a jQuery plugin designed to provide&amp;nbsp;JavaScript&amp;nbsp;UI elements that complement jQuery. &lt;a href="http://jqueryui.com/demos/dialog/"&gt;Dialog &lt;/a&gt;provides a robust set of tools for creating flexible client-side dialog boxes. Here's an example of a typical OK/Cancel&amp;nbsp;confirmation&amp;nbsp;dialog produced by Dialog.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-6f5V-x5hklQ/TV1-paTzscI/AAAAAAAADWI/SWn_MkwZJxA/s1600/confirm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="225" src="http://2.bp.blogspot.com/-6f5V-x5hklQ/TV1-paTzscI/AAAAAAAADWI/SWn_MkwZJxA/s320/confirm.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Dialogs are typically defined statically and called by dynamic Javascript. I've settled on a pattern that seems to work well with PeopleSoft. I define the dialog based on an empty &amp;lt;div&amp;gt;, but set most of the&amp;nbsp;properties, including the html&amp;nbsp;displayed&amp;nbsp;in the dialog, from the event-driven code and bind variables.&lt;br /&gt;&lt;br /&gt;Here's a typical&amp;nbsp;definition.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; var $confirmDialog = $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;').dialog({&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;title: '%BIND(:10)', &lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;autoOpen: false,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;resizable: false,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;modal: true,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;minHeight: 400,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;minWidth: 350,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;buttons: {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;            &lt;/span&gt;OK: confirmOK,&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;            &lt;/span&gt;Cancel: confirmCancel&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;});&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;A few things to notice. The dialog html is an empty div (&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;). The actually html shown in the dialog is set when it is called from a function. I'm setting the dialog title with a bind variable. autoOpen is set to false; otherwise the dialog would open when the page is loaded. The button actions are defined as named functions. They can be anonymous functions, but I find that using named functions here is cleaner, more flexible and can be reused. In many cases, I replace the actions when I call the dialog.&lt;br /&gt;&lt;br /&gt;Here' s a function that calls the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;$confirmDialog&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;function confirmIt(msg){ //msg must be formated as html&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$confirmDialog.dialog('option' , 'height', 450);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$confirmDialog.dialog('option' , 'width', 400);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$confirmDialog.dialog('option' , 'buttons' , {OK: confirmSubmit, Cancel: closeDialog} );&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$confirmDialog.html(msg);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$confirmDialog.dialog('open');&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In this case, I'm replacing the button functions with:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;// OK button function for confirm dialog&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var confirmSubmit = function() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$(this).dialog('close');&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$('#TC_DERIVED_CONFIRMED').val('Y'); //hidden field&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;return submitProxied.apply(window, localArgs); // continue submit process&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var closeDialog = function(){&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;    &lt;/span&gt;confirmed = false;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;    &lt;/span&gt;$(this).dialog('close');&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;confirmSubmit&lt;/span&gt;:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;closes the dialog box;&amp;nbsp;&lt;/li&gt;&lt;li&gt;sets a hidden field that I've added to the page with JavaScript following the PeopleTools naming convention that I can query in PeopleCode to confirm that the user has confirmed the submit on the client-side;&amp;nbsp;&lt;/li&gt;&lt;li&gt;passes the processing to the standard&amp;nbsp;PeopleTools submit processing JavaScript. (I describe how this works in a previous post.)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;closeDialog&amp;nbsp;sets global confirmed to false and closes the dialog. This, in effect, cancels the submit and leaves the user on the original page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can define as many buttons as you wish, each with its own function.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;&lt;b&gt;The Validation Chain&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This works fine for a single-step confirmation - something like "Submit your timesheet? You will not be able to make further changes. OK Cancel." But when you call a dialog box you are turning over processing to the&amp;nbsp;dialog&amp;nbsp;code. Unlike a PeopleSoft messageBox, it never returns a value to the calling code. So, what if you need to process several validations and confirmations? To handle this, I use a technique I call the validation chain. In the&amp;nbsp;validation chain, each step is a function that can stop the processing or call the next step until the chain is complete.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an example.&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; function myFunction () {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; //validationChain is declared global&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;code&gt; &lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;validationChain = [validateInOut,validateZeroHours,validateTimeOnHoliday,validateSubmit];&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; return nextValidation();&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; // call the next validation in the chain&lt;br /&gt;&amp;nbsp;&amp;nbsp; function nextValidation() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;var next = validationChain.shift();&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;var nextUndefined = next == undefined;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;if (!nextUndefined) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return next()&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;       &lt;/span&gt;};&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;return true;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;}&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;First, we set up a global array of validation/confirmation functions; the validation chain. Then we call &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;nextValidation()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;nextValidation&lt;/span&gt;&amp;nbsp;removes the first function from the chain and stores it in variable &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;next&lt;/span&gt;. Then, if the function is defined, it is called.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now each function can do validation or confirmation including calling a dialog box. To stop the process the function returns false. To continue, the function, or the dialog it calls, calls&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;nextValidation()&lt;/span&gt;. Here's an example validation function that can be added to the validation chain:&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;// User confirms time on holiday &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;function validateTimeOnHoliday() {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;   if (timeOnHoliday()){&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       var msg = '%BIND(:2)'.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       replace('%1',holidayDateString);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       $confirmDialog.dialog('option' , 'buttons' , {OK: confirmContinue, Cancel: closeDialog} );&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       $confirmDialog.html(msg);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       $confirmDialog.dialog('open');&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       return false; // we'll only get here if the user cancels&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;   } else {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;       return nextValidation()&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;   };&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;// Continue button function for validation chain dialog&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var confirmContinue = function() {&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$(this).dialog('close');&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;return nextValidation();&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;// Close the dialog without taking any action - this will end the validation chain&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var closeDialog = function(){&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;     &lt;/span&gt;$(this).dialog('close');&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;}&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Now you can call any number of validations and confirmations before submitting the page to the server.&lt;br /&gt;&lt;br /&gt;I hope you have found my JavaScript blog entries helpful. If you have your own ideas on how to use JavaScript to improve PeopleSoft applications, please let me know.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-3362503148011821772?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/3362503148011821772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=3362503148011821772' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3362503148011821772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3362503148011821772'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2011/02/using-javascript-in-peoplesoft-creating.html' title='Using JavaScript in PeopleSoft: Creating your own dialog boxes'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-6f5V-x5hklQ/TV1-paTzscI/AAAAAAAADWI/SWn_MkwZJxA/s72-c/confirm.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-914636532005128154</id><published>2010-11-17T17:42:00.000-08:00</published><updated>2011-02-17T16:05:52.688-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='peoplesoft'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='peopletools'/><title type='text'>Using JavaScript in PeopleSoft: Proxy PeopleSoft Functions</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;In my last post, I showed you how to do dynamic field level validations in JavaScript with the help of jQuery. In&amp;nbsp;this&amp;nbsp;post we'll take it to the next level by doing validations on submit using a function proxy technique.&lt;br /&gt;&lt;br /&gt;JavaScript is a very flexible language. One aspect that separates it from other languages, such as Java, is that everything is an object. This includes functions. At first glance treating a function as an object doesn't seem very useful, but, in fact, it leads to a number of cool capabilities. One of those capabilities is the ability to proxy a function.&lt;br /&gt;&lt;br /&gt;Here's a non-PeopleSoft example to illustrate this. Let's say you have a vendor-created web page that already has a &lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;validatePage()&lt;/span&gt;&lt;/i&gt;&amp;nbsp;function&amp;nbsp;that is called by the two buttons,&amp;nbsp;mySaveButton&amp;nbsp;and&amp;nbsp;mySubmitButton.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;function validatePage(source) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!validateRequiredFields())&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!validateDates())&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (source == 'mySubmitButton') {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if (!validateTotals())&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;// ...&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We would like to insert another validation step without having to modify the existing code. We can do this by creating a proxy for the original. (This is all standard JavaScript - no jQuery.)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;(function() { &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // proxy validatePage &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var proxied = validatePage; &lt;/span&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;// capture the original function &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; validatePage = function() { &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // replace it with our custom version &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var result = true; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var localArgs = arguments; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var button = arguments[0]; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (source == 'mySubmitButton') { result = validateTotals(); } &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (result) { &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return proxied.apply(this, localArgs); // call the original function. &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } return false; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;})(); &lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;So what's happening here? The first line of our anonymous function gets a reference to the original &lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;validatePage&lt;/span&gt;&lt;/i&gt; function object. Then we replace the validatePage object with our new function. &lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;arguments &lt;/span&gt;&lt;/i&gt;is a special object available in the body of every function. It's an array of the arguments passed to the function. We use it here to access the argument of the original &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;i&gt;validatePage&lt;/i&gt;&lt;/span&gt; function call, in this case the button that called the function. If the calling button was mySubmitButton, my custom validation is run. If the validation passes, the next line calls the proxied function to perform the rest to the validations. There is a lot of flexibility here. We could have executed code after calling the proxied function or not even called it at all. I'll use this later option below when proxying the PeopleSoft &lt;i&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;saveWarning()&lt;/span&gt;&lt;/i&gt; function.&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;How do we apply this to a PeopleSoft page? If you dig around in a typical PeopleSoft page, you'll find that all buttons and links in the main frame that call PeopleCode on the server call the PeopleSoft JavaScript function &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;i&gt;submitAction_win0(document.win0,'CUST_PB_WRK_CUST_CRSPDSEL_PB');&lt;/i&gt;&lt;/span&gt; where the second argument is the id of the button or link field. By proxying this function, we can inject our own validation code that is called whenever a button or link is clicked.&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;// proxy the peoplesoft submitAction_win0() function&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;// Called for all peoplecode buttons and links&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;(function() {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // proxy submitAction_win0&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var submitProxied = submitAction_win0;&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var submitAction_win0 = function() {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var button = arguments[1];&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var msg = "";&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; switch (button) {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case "SAVE_BUTTON": // Save&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (validateForSave()) {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return submitProxied.apply(this, arguments); // call the original function&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case "SUBMIT_BUTTON": // Submit&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (validateForSubmit()) {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; msg = '%BIND(:3)'; // Confirm Submit&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (confirm(msg)) {&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return submitProxied.apply(this, arguments);&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; default: // all other buttons and links&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return submitProxied.apply(this, arguments);&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; };&lt;/code&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;code&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;&lt;/span&gt;})();&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Again our proxy function gets a reference to the original function and then substitutes our new function. The &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;switch&lt;/span&gt; checks which button called the function and runs a custom validation. If the validation passes, the original function is applied which, in this case, continues the PeopleSoft submit process. The default case simply applies the original function for all other buttons and links.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Proxy the&amp;nbsp;saveWarning&amp;nbsp;Function&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To me the standard PeopleSoft save warning is counter-intuitive. I think the OK button should continue the action I originally selected while the Cancel button should cancel that action. Since my pages are exposed to an&amp;nbsp;audience&amp;nbsp;of non-PeopleSoft users, I decided to change it (It's good to be King!). I found that the save warning is&amp;nbsp;raised&amp;nbsp;by, of all things, the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;saveWarning&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;()&lt;/span&gt; function. Here's how I replaced it. Note that I never actually apply the original function, so this proxy completely replaces the&amp;nbsp;it.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var saveWarningURL;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var saveWarningProxied;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;var saveWarningTarget;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;//proxy the peoplesoft saveWarning(frameName,form,target,url) function&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;(function() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;saveWarningProxied = saveWarning; // Not doing anything with this&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;saveWarning = function() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;// console.log("arguments[1]: " + arguments[1]);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;localArgs = arguments;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;var frameName = arguments[0];&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;var form = arguments[1];&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;saveWarningTarget = arguments[2];&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;saveWarningURL = arguments[3];&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;var changed=null;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;if (form)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt; &amp;nbsp;changed = checkFormChanged(form, null);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;if (changed==null &amp;amp;&amp;amp; top.frames &amp;amp;&amp;amp; frameName.length&amp;gt;0 ) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt; &amp;nbsp;objFrame = top.frames[frameName];&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt; &amp;nbsp;if (objFrame)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt; &amp;nbsp; &amp;nbsp;changed=checkFrameChanged(objFrame);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;if ((changed==null) &amp;amp;&amp;amp; top.frames)&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;checkAnyFrameChanged(top.frames);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;if (changed) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;    &lt;/span&gt;if (confirm('%BIND(:7)')) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;    &lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;open(saveWarningURL, saveWarningTarget);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;};&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;})();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what it looks like in action.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VMLuCoZdQIs/TOR_CDt_RpI/AAAAAAAADQs/Vup_EeJbhaE/s1600/saveWarning.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VMLuCoZdQIs/TOR_CDt_RpI/AAAAAAAADQs/Vup_EeJbhaE/s1600/saveWarning.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's it for now. In the next post, I plan to show how to create your own modal&amp;nbsp;dialog&amp;nbsp;boxes to replace the standard alert (error/warning) and confirm (yes/no ok/cancel) messages.&lt;br /&gt;&lt;br /&gt;Happy coding!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-914636532005128154?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/914636532005128154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=914636532005128154' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/914636532005128154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/914636532005128154'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2010/11/using-javascript-in-peoplesoft-proxy.html' title='Using JavaScript in PeopleSoft: Proxy PeopleSoft Functions'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_VMLuCoZdQIs/TOR_CDt_RpI/AAAAAAAADQs/Vup_EeJbhaE/s72-c/saveWarning.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-8505351414340523802</id><published>2010-11-02T10:29:00.000-07:00</published><updated>2010-11-02T10:53:33.386-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='peoplesoft'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='peopletools'/><title type='text'>Using jQuery in PeopleSoft: Validating, Formatting and Totaling</title><content type='html'>In my last entry, I introduced using JavaScript and, specifically, the jQuery library to enhance your PeopleSoft pages. Now we'll take a look at how to apply this to browser-side data validation, formatting and totaling. This is the application that inspired me to look&amp;nbsp;into&amp;nbsp;using&amp;nbsp;JavaScript with PeopleSoft in the first place.&lt;br /&gt;&lt;br /&gt;Experienced PeopleSoft developers (and why would you be reading this if you're not one?) know that in order to force data validation and page update as soon as a user leaves a field, we must deactivate "deferred processing" so that the page will be submitted when the data changes. On pages with many fields, it can be very disruptive to efficient data entry to submit the page on each change. This also increases the load on the server. On the other hand, real-time data validation and page updates provide the user valuable feedback.&lt;br /&gt;&lt;br /&gt;The solution is to do basic data validation, formatting and totaling on the browser-side with JavaScript.&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;One caveat, never rely solely on&amp;nbsp;browser-side data validation. You cannot control what&amp;nbsp;happens&amp;nbsp;on the user's computer. It is not that hard to hack a web page and subvert the validation. Always do server-side validation also to insure that data you receive is safe and valid&lt;/i&gt;.&lt;/blockquote&gt;jQuery makes it easy to detect changes and take action on them. The basic code looks like this.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Cpp" name="code"&gt;$(document).ready(function(){&lt;br /&gt;  $('#MY_INPUT').change(function () {&lt;br /&gt;    //do something here&lt;br /&gt;  });&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;The .change() method causes the enclosed function to be called whenever the selected object value is changed and the object loses "focus." An object losses focus when the user "tabs out" or otherwise selects another object on the page. A similar method, .blur(), can also be used. The blur event occurs when the object losses focus, whether or not the value has changed.&lt;br /&gt;&lt;br /&gt;Let's say we have a simple time entry page where the user will record her time for the week. Each day has an hours&amp;nbsp;text&amp;nbsp;input element, HOURS1, HOURS2 ... HOURS7. We can watch all seven inputs with one line of code and do some validation and totaling.&lt;br /&gt;&lt;br /&gt;&lt;pre class="Cpp" name="code"&gt;$(document).ready(function(){&lt;br /&gt; $('input:text[id^=HOURS]').change(function () {&lt;br /&gt;  try{&lt;br /&gt;   var hours = parseNumber($(this).val());&lt;br /&gt;   if (hours &amp;lt; 0 || hours &amp;gt; 24){&lt;br /&gt;    alert('Daily hours must be between 0 and 24.');&lt;br /&gt;   }else{&lt;br /&gt;    $(this).val(formatNumber(hours));&lt;br /&gt;   }   &lt;br /&gt;  }catch(er){&lt;br /&gt;   alert ($(this).val() + ' is "' + er.toString() + '"');&lt;br /&gt;  }&lt;br /&gt; });&lt;br /&gt; &lt;br /&gt; // parse text to number.&lt;br /&gt; function parseNumber(n) {&lt;br /&gt;  var out;&lt;br /&gt;  if (n == ''){&lt;br /&gt;   out = 0;&lt;br /&gt;  } else{&lt;br /&gt;   var out = parseFloat(n);&lt;br /&gt;  }&lt;br /&gt;  if (isNaN(out)) {&lt;br /&gt;   throw 'Not a number';&lt;br /&gt;  }&lt;br /&gt;  return out;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; // format number to text with 2 decimal point. If 0 return ''&lt;br /&gt; function formatNumber(n) {&lt;br /&gt;  var out;&lt;br /&gt;  if (n == 0) {&lt;br /&gt;   out = '';&lt;br /&gt;  } else {&lt;br /&gt;   out = n.toFixed(2);&lt;br /&gt;  }&lt;br /&gt;  return out;&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Each time one of the HOURS inputs is changed, this code is called. First we parse the value of the input ($(this).val()) to a number. If it's not a number, the user gets an alert. Same if the value is not between 0 and 24. Finally, the number is formatted with 2 decimal places and we update the input element value.&lt;br /&gt;&lt;br /&gt;All this takes place on the browser without submitting the page to the server. Let's take one more step and provide a total. I'll add a totalHours method:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="Cpp" name="code"&gt;function totalHours() {&lt;br /&gt;  var total = 0;&lt;br /&gt;  $('input:text[id^=HOURS]').each(function () {&lt;br /&gt;   total += parseNumber($(this).val());&lt;br /&gt;  });&lt;br /&gt;  $('#TOTAL_HOURS').val(total.toFixed(2));&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;and call it from my original code:&lt;/div&gt;&lt;pre class="Cpp" name="code"&gt;...&lt;br /&gt;   }else{&lt;br /&gt;    $(this).val(formatNumber(hours));&lt;br /&gt;    totalHours();&lt;br /&gt;   }   &lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;Note how easily I can loop through each of the HOURS inputs and total them up using the each() method.&lt;br /&gt;&lt;br /&gt;Now, a&amp;nbsp;couple&amp;nbsp;PeopleSoft-specific tips.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_VMLuCoZdQIs/TM9aZ4Ovx4I/AAAAAAAADP0/xQPXu7qsslc/s1600/PageFieldName.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="106" src="http://3.bp.blogspot.com/_VMLuCoZdQIs/TM9aZ4Ovx4I/AAAAAAAADP0/xQPXu7qsslc/s200/PageFieldName.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;By default, PeopleTools gives each input an id attribute equal to the&amp;nbsp;concatenated record and field names. This can be&amp;nbsp;awkward&amp;nbsp;and sometimes not very descriptive. You can override this behavior by&amp;nbsp;setting&amp;nbsp;the "Page Field Name" in the "General" tab of the Edit Box Page Field properties. The value you set here will be used as the id and name of the element in the html. Just be sure the value you set is unique for the page.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_VMLuCoZdQIs/TM9Z3cEmCII/AAAAAAAADPw/ycoVJmZnlrQ/s1600/DisplayOnlyAppearance.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/_VMLuCoZdQIs/TM9Z3cEmCII/AAAAAAAADPw/ycoVJmZnlrQ/s200/DisplayOnlyAppearance.png" width="141" /&gt;&lt;/a&gt;&lt;/div&gt;The&amp;nbsp;Edit Box "Display-Only Appearance" should be set to "Disabled Edit Control" in the "Use" tab of&amp;nbsp;Edit Box Page Field properties. This causes the Edit Box to become an "addressable" text &amp;lt;input&amp;gt; element rather than &amp;lt;span&amp;gt; element with no id. This does cause some formatting issues depending on the browser. I'll describe my solution to this in a later post.&lt;br /&gt;&lt;br /&gt;So now you can validate, format and total data on the browser side without having to submit your page to the server.&lt;br /&gt;&lt;br /&gt;In my next post, I'll show you how to intercept the delivered PeopleSoft submit process so you can do validations and verifications on submit.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-8505351414340523802?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/8505351414340523802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=8505351414340523802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/8505351414340523802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/8505351414340523802'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2010/11/using-jquery-in-peoplesoft-validating.html' title='Using jQuery in PeopleSoft: Validating, Formatting and Totaling'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_VMLuCoZdQIs/TM9aZ4Ovx4I/AAAAAAAADP0/xQPXu7qsslc/s72-c/PageFieldName.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-299201785424454553</id><published>2010-10-20T17:41:00.000-07:00</published><updated>2010-10-22T13:12:26.952-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='peoplesoft'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='peopletools'/><title type='text'>Using jQuery in PeopleSoft: Introduction</title><content type='html'>At my company, management&amp;nbsp;decisions&amp;nbsp;have kept most of our PeopleSoft applications on PeopleTools versions&amp;nbsp;prior&amp;nbsp;to 8.50. So we haven't been able to take advantage of the new AJAX features that come with the most recent versions of Tools. However, we are now working on a application that will be&amp;nbsp;exposed&amp;nbsp;to an large&amp;nbsp;audience&amp;nbsp;outside of our corporate firewall. We realized that we would like our users to have a modern browser&amp;nbsp;experience&amp;nbsp;including: dynamic page updates, client-side validation, modal dialog boxes. How can we do this with&amp;nbsp;PeopleTools 8.49? The answer is to do our own JavaScript&amp;nbsp;programming.&lt;br /&gt;&lt;br /&gt;Having done some&amp;nbsp;JavaScript for my wife's business web site &lt;a href="http://getrolling.com/"&gt;GetRolling.com&lt;/a&gt;, I realized that using "straight" JavaScript to&amp;nbsp;program&amp;nbsp;modern features is a lot of work, so we went looking for a framework. We quickly settled on &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, a popular, open-source&amp;nbsp;JavaScript&amp;nbsp;library with lots of support and many add-ons. We had also heard that Oracle was using&amp;nbsp;jQuery with the most recent versions of &amp;nbsp;PeopleTools (true?), so it would help "future-proof" our experience.&lt;br /&gt;&lt;br /&gt;The core strength of&amp;nbsp;jQuery is its selectors, which allow you to easily select and act on one or more DOM objects without having to traverse the DOM&amp;nbsp;hierarchy. The multitude of selector options can be a bit&amp;nbsp;daunting&amp;nbsp;at first, but after learning some common patterns, I found them to be very efficient.&amp;nbsp;While the jQuery project provides&amp;nbsp;plenty&amp;nbsp;of &lt;a href="http://docs.jquery.com/Main_Page"&gt;documentation on their site&lt;/a&gt;, I found this &lt;a href="http://www.dzone.com/links/r/dzone_releases_jquery_cheatsheet.html"&gt;Ref Card from DZone&lt;/a&gt; very handy when&amp;nbsp;trying&amp;nbsp;to&amp;nbsp;figure&amp;nbsp;out how to write my selectors.&lt;br /&gt;&lt;br /&gt;A key concept is that your jQuery code should be wrapped in document ready block:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$(document).ready(function(){&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;// your code&lt;br /&gt;});&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;This ensures that you code does not get called until the DOM is loaded in the browser and ready. You will use&amp;nbsp;$(selector) throughout your jQuery code. $() is just shorthand for the core function jQuery(). jQuery also makes liberal use of&amp;nbsp;anonymous&amp;nbsp;functions like the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;function(){...} above.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Getting Started&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;I'll skip the traditional HelloWorld as it's not very&amp;nbsp;instructive&amp;nbsp;for our use and get right to a concrete example. Let's say you want to validate a user entry immediately after the user leaves the input field. In PeopleTools, you would need to add FieldChange PeopleCode to the field and uncheck "Allow Deferred Processing." &amp;nbsp;This would force the page to be submitted to the server whenever the field value is&amp;nbsp;changed&amp;nbsp;so that the validation&amp;nbsp;PeopleCode can run. This can be very disruptive to the user experience and place extra load on the server.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With jQuery, we could write this (USA-centric) code:&lt;/div&gt;&lt;blockquote&gt;&lt;code&gt;$(document).ready(function(){&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;$('#ADDRESS_ZIP_CODE').change((function () {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if($(this).val().length &amp;lt; 5) {&lt;/code&gt;&amp;nbsp;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;code&gt;            alert("Please enter a valid Zip Code");         }     }); });&lt;/code&gt;&lt;/blockquote&gt;What's happening here? # is the id selector. The fragment $(#'ADDRESS_ZIP_CODE') "selects" the object with an id='ADDRESS_ZIP_CODE'. After the DOM is ready, jQuery adds an anonymous function to the onChange event of this object that happens to be a text input element. When the value of the input is changed, the function is called. Inside the function, $(this) refers to the selected object. val() returns the value attribute string and .length is the standard JavaScript length property of the string. As you can see, you can write some very concise code with jQuery.&lt;br /&gt;&lt;br /&gt;Here is another handy example I use in PeopleTools grids.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$('input:text[id^=HOURS]').each(function(index) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;// your code&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This selects each of the input text elements whose id&amp;nbsp;attribute&amp;nbsp;starts with&amp;nbsp;HOURS. each() iterates through each element in a loop. In a&amp;nbsp;PeopleTools grid, each field id is suffixed with $i where i is the row number, e.g., HOURS$2, so you can see how useful this can be.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In future blogs I'll describe some more powerful things you can do with jQuery, but I'd like to use the rest of this blog to show how to get this code on to your page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The basic mechanism I use is to write the JavaScript in an application designer HTML object and use page activate PeopleCode to put that HTML into an HTML Area that I've included on the page. The position of the&amp;nbsp;HTMLArea does not seem to matter much, but I try to place it near the top of the page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's important to include a reference to the jQuery library in your code. Here's an example of how it looks:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;script src="/rhijs/jquery-1.4.2.min.js" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script type="text/javascript" &amp;gt;&lt;br /&gt;$(document).ready(function(){&lt;br /&gt;&amp;nbsp;$('#ADDRESS_ZIP_CODE').change((function () {&lt;br /&gt;&amp;nbsp;&amp;nbsp;if($(this).val().length &amp;lt; 5) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; alert("Please enter a valid Zip Code");&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;});&lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had my admin put the file&amp;nbsp;jquery-1.4.2.min.js on our web server in a custom directory so it can be referenced by my pages. This is the "minified" version of the library. The code is nearly impossible to read, but the file is much smaller to load and should be used for production. There also a standard&amp;nbsp;version&amp;nbsp;with the full source that can be used for reference and debugging:&amp;nbsp;jquery-1.4.2.js.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you don't have access to your web server, a good option, if your network allows, is to hot link to a CDN as described here:&amp;nbsp;&lt;a href="http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery"&gt;http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The basic PeopleCode to include your JavaScript in your PeopleSoft page is:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;MY_REC_DERIVED.HTMLAREA1.Value = GetHTMLText(HTML.MY_JQ_ZIP_VALIDATE);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A powerful technique is to use the text replacement functionality of&amp;nbsp;GetHTMLText to "customize" your code on the fly. For instance, instead of hard coding the error message in the JavaScript, we could modify the alert line to read:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;&amp;nbsp;alert("%BIND(:1)"); // note the quotes around the bind&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and change our PeopleCode to:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;Local string &amp;amp;invalidZipMsg = &amp;nbsp;MsgGet(29000, 85, "Message not found");&lt;br /&gt;MY_REC_DERIVED.HTMLAREA1.Value = GetHTMLText(HTML.MY_JQ_ZIP_VALIDATE,&amp;amp;invalidZipMsg);&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's it for now. In future blogs I'll introduce a&amp;nbsp;technique that allows you to&amp;nbsp;intercept&amp;nbsp;calls to delivered JavaScript, so you can trigger your own validation and verification code; show&amp;nbsp;you&amp;nbsp;how to format input;&amp;nbsp;how to create your own modal dialogs; and how to add an Auto-Complete textbox to your page. I'll also discuss some tools that are&amp;nbsp;essential&amp;nbsp;to your success in browser JavaScript programming.&lt;br /&gt;&lt;br /&gt;I'm certainly not the first one to use JavaScript with&amp;nbsp;PeopleSoft. There are plenty of examples on the Internet. I'm in special debt to &lt;a href="http://jjmpsj.blogspot.com/"&gt;Jim Marions' blog&lt;/a&gt; and his new book&amp;nbsp;&lt;a href="http://www.amazon.com/PeopleSoft-PeopleTools-Techniques-Osborne-ORACLE/dp/0071664939"&gt;PeopleSoft PeopleTools Tips &amp;amp; Techniques&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-299201785424454553?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/299201785424454553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=299201785424454553' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/299201785424454553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/299201785424454553'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2010/10/using-jquery-in-peoplesoft-introduction.html' title='Using jQuery in PeopleSoft: Introduction'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-1109346190571962500</id><published>2010-10-10T17:37:00.000-07:00</published><updated>2010-10-10T17:57:39.970-07:00</updated><title type='text'>I'm Back</title><content type='html'>I'm reviving my blog with a new emphasis on my professional activities as a PeopleSoft Application Architect and developer. I'm leaving my old posts up as they're fun to revisit, but in the future expect more technical content. My next post will be about using the jQuery JavaScript library to enhance the user experience for PeopleSoft Applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-1109346190571962500?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/1109346190571962500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=1109346190571962500' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1109346190571962500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1109346190571962500'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2010/10/im-reviving-my-blog-with-new-emphasis.html' title='I&apos;m Back'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-3173752444228988478</id><published>2007-09-23T17:04:00.000-07:00</published><updated>2007-09-23T17:25:06.628-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bike'/><category scheme='http://www.blogger.com/atom/ns#' term='bicycling'/><category scheme='http://www.blogger.com/atom/ns#' term='fitness'/><title type='text'>The Eucalyptus Trees</title><content type='html'>Another ride with the &lt;a href="http://www.diablocyclists.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Diablo&lt;/span&gt; Cyclists&lt;/a&gt; - my last hard ride before &lt;a href="http://www.nationalmssociety.org/site/TR?pg=entry&amp;amp;fr_id=5870"&gt;Waves-to-Wine&lt;/a&gt;&lt;a href="http://www.nationalmssociety.org/site/TR?pg=entry&amp;amp;fr_id=5870"&gt;.&lt;/a&gt; Walnut Creek through &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Danville&lt;/span&gt; and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Blackhawk&lt;/span&gt;. Out &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Tassajara&lt;/span&gt; Road to Highland, Collier Canyon and return.&lt;br /&gt;&lt;br /&gt;The pace to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Blackhawk&lt;/span&gt; was moderate, but things started to pick up after the rest break. We had a big pack going 28 mph on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Tassajara&lt;/span&gt;. Turning on to Highland, the hammer went down. I hung on until the second roller, dropping off with one other guy. We stuck together until the rest break including a fun 30+ mph stretch.&lt;br /&gt;&lt;br /&gt;When everyone got rolling after the break, it was pretty much a repeat. I hung on as long as I could with my heart rate in the low 160s. I paired up with a different partner for the ride back to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Danville&lt;/span&gt; and finished just before noon. 50 miles, 33 mph max, 17.6 mph average.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-3173752444228988478?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/3173752444228988478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=3173752444228988478' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3173752444228988478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/3173752444228988478'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2007/09/ride.html' title='The Eucalyptus Trees'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-6516017022308049756</id><published>2007-09-23T05:14:00.000-07:00</published><updated>2007-09-23T16:56:12.716-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='movies'/><title type='text'>Sunrise Sunset - Two Movies</title><content type='html'>We watched two small but amazing movies this weekend: &lt;a href="http://www.imdb.com/title/tt0112471/"&gt;&lt;span style="font-style:italic;"&gt;Before Sunrise&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://www.imdb.com/title/tt0381681/"&gt;&lt;span style="font-style:italic;"&gt;Before Sunset&lt;/span&gt;&lt;/a&gt;. Both starring Ethan Hawke and Julie Delphy, and both are essentially long conversations. In &lt;span style="font-style:italic;"&gt;Before Sunrise&lt;/span&gt;, released in 1995, their characters, American Jesse and Celine, a Parisian student, meet on a train traveling through Europe and get off together in Vienna. They spend the night walking and talking - knowing they may never see each other again.&lt;br /&gt;&lt;br /&gt;The 2004 &lt;span style="font-style:italic;"&gt;Before Sunset&lt;/span&gt; is the sequel. Jesse returns to Europe, a successful author touring a book essentially about their Vienna encounter. Celine shows up at his last stop in a Paris bookstore. They have a few hours to pick up where they left off nine years ago before Jesse flies back home.&lt;br /&gt;&lt;br /&gt;Delphy radiates a natural beauty, enthusiasm and charm  that had me in love with her. She hardly changes in the nine years (story-wise and in reality) between their encounters. Hawke, young and dashingly handsome in the first, is a bit world-worn four years into the new Millennium.&lt;br /&gt;&lt;br /&gt;Their conversations are never dull and amazingly naturalistic with no hint of scripting. Director Richard Linklater and crew pull off long, uninterrupted steady cam shots as Jesse and Celine talk their way through the streets of Paris.&lt;br /&gt;&lt;br /&gt;In the special features on the second DVD, we learn that Before Sunset was was shot in 15 days - a collaboration between the two actors and Linklater. Delphy wrote much of the script and is credited with composing the song she sings near the end.&lt;br /&gt;&lt;br /&gt;Definitely watch them in order. They could easily been one long movie, but it's more fun to see the actors as they have actually matured rather than through makeup. Both are available on DVD from &lt;a href="http://Netflix.com"&gt;Netflix&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-6516017022308049756?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/6516017022308049756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=6516017022308049756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/6516017022308049756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/6516017022308049756'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2007/09/sunrise-sunset-two-movies.html' title='Sunrise Sunset - Two Movies'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-1544761885098212384</id><published>2007-09-22T18:07:00.001-07:00</published><updated>2007-09-23T05:20:38.370-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='California'/><category scheme='http://www.blogger.com/atom/ns#' term='beach'/><category scheme='http://www.blogger.com/atom/ns#' term='hikng'/><title type='text'>Paradise Beach</title><content type='html'>There are lots of Paradise Beaches in the world. You've probably been to a few. Last weekend, I visited my favorite. &lt;br /&gt;&lt;br /&gt;We went south to the Pismo Beach-Arroyo Grande, CA area to spend the weekend with Liz's 78 year-old dad, Jerry. Liz's sister, Laurie, had died two years earlier of ovarian cancer. To commemorate the day, we went hiking on the beach – one of her favorite activities. &lt;br /&gt;&lt;br /&gt;In the tiny &lt;a href="http://www.duneguide.com/closed_areas_guadalupe_dunes.htm"&gt;Guadalupe Dunes&lt;/a&gt; parking lot, we ran into Laurie's husband who was visiting some of their favorite spots. From there, we headed south along the nearly deserted beach. Shortly, it was just us and a few surf fishermen.  Off shore was a great stream of birds; mostly gulls and pelicans, also heading south. Apparently the anchovies were schooling and the birds feasting. Shortly we saw a mass of birds diving into the waves turning the surface to foam. &lt;br /&gt;&lt;br /&gt;Just before the bluffs of Mussel Rock started to rise, we worked our way up into the dunes. The dune complex here is huge. As recently as 1982, vehicles were allowed to roam this area. Jerry was one of the dune buggy pioneers. He and Liz often reminisce about family outings in the dunes. Following a rough path through the dunes and beach scrub, we worked our way up over Mussel Rock. Stopping to chat with a couple coming the other way, we learned they had found some cougar (mountain lion, puma) tracks. There are plenty of tracks of all sizes in the sand: reptiles, birds, mammals. I'm not much of a tracker, but we think we saw tracks from snakes, centipedes, mice, rabbits, coyotes, deer, turkey vultures, and the rumored cougars. &lt;br /&gt;&lt;br /&gt;The walking surface varies from loose sand, to hard pack and exposed sandstone. The wind had blasted the sand so hard in some spots that we barely dented the surface. It was a bit disconcerting to walk across a steep, open slope wondering if our soles would stick to the rock-like surface. There are a few exposed spots where the eroding sand drops over cliffs to the crashing surf below. Don't look down!&lt;br /&gt;&lt;br /&gt;&lt;A HREF='http://localhost:3481/f1e310db5a89c7db9b2f77fccb9289cd/image4981.jpg'&gt;&lt;IMG SRC='http://localhost:3481/f1e310db5a89c7db9b2f77fccb9289cd/image4981.jpg?size=320' border=0 alt='' id='BLOGGER_PHOTO_ID_' style='clear:both;float:left; margin:0px 10px 10px 0;'&gt;&lt;/A&gt;&amp;nbsp;&lt;br /&gt;From the top of Mussel Rock, there are great views: north over the dunes, west over the ocean far below and south to Paradise Beach. We could see three fishermen. Aside from them the beach was deserted. A steep gully separates Mussel Rock from the beach. A trail of sorts leads straight down into the gully. Someone has installed a rope. It was a welcome aid as we, one-by-one, worked our way down the narrow, steep, loose-sand covered “trail.” In the bottom is a year-round stream, that drops over a 20-foot fall to the beach. Because of the drop, we had to work our way another hundred yards or so further south before we could safely descend to the beach. Calla Lilies grow along the cliffs. Some had been rooted up, apparently by wild pigs. &lt;br /&gt;&lt;br /&gt;Liz and I backpacked here some years ago coming in from the &lt;a href="http://www.localhikes.com/Hikes/PointSal_7480.asp"&gt;Point Sal road&lt;/a&gt; to the south of the beach. At that time there had been a small, quaint &lt;a href="http://www.billbuck.com/paradise/nrh_notes1.html"&gt;driftwood shack&lt;/a&gt; up against the cliffs, but it had been washed away in later winter storms. Driftwood to driftwood.&lt;br /&gt;&lt;br /&gt;Continuing south on the two mile long beach, we passed the fishermen – one had a fair-sized surf perch. Down further was a gathering of a dozen or so turkey vultures feasting on a seal carcass.  They reluctantly scattered to the cliffs as we approached. In the carcass were still a few chunks of fresh-looking liver. Yum!&lt;br /&gt;&lt;br /&gt;Sandstone cliffs supported some lovely hanging gardens above which the steep slopes rise over 400 feet. We spotted tracks in the sand that we guessed were from a mother cougar and two cubs looking for food washed up on beach.&lt;br /&gt;&lt;br /&gt;The tide was in as we approached the southern end of the beach where we found a rocky inlet and stopped to have our lunch. There were six sea lions frolicking in the relatively calm pool. I found a spot that would have been great for diving, but despite the sunshine, it was a bit cool for swimming. Nearby tide pools were full of anenomes, little crabs and other life.&lt;br /&gt;&lt;br /&gt;On the way back Jerry took the hard way up the cliff to the trail while we could only shake our heads at his tenacity as he struggled for sandy hand and foot holds.  We conquered the rest of climb with the welcome help of the rope. Jerry took his time but seemed no worse for it after a rest at the top.&lt;br /&gt;&lt;br /&gt;Large flocks of gulls and curlews resting on the sand from their earlier feast parted for us as we strode back up the Guadalupe Beach. We were tired but satisfied with our wilderness beach experience as we arrived at the parking lot after our nine mile round trip.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-1544761885098212384?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/1544761885098212384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=1544761885098212384' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1544761885098212384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/1544761885098212384'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2007/09/paradise-beach.html' title='Paradise Beach'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-5488787689130722952</id><published>2007-09-12T20:51:00.000-07:00</published><updated>2007-09-12T21:58:12.007-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='report repository'/><category scheme='http://www.blogger.com/atom/ns#' term='peoplesoft'/><category scheme='http://www.blogger.com/atom/ns#' term='load balancer'/><title type='text'>PeopleSoft and the Load Balancer</title><content type='html'>We are doing a PeopleSoft PeopleTools upgrade among with upgrading our server environment to a "high availability" configuration. In PeopleTools, we are upgrading from 8.43 to 8.48. Many "little" things have broken. I'll write more about that in the future. This time I want to discuss a problem we had with the "high availability" configuration.&lt;br /&gt;&lt;br /&gt;Our UNIX (Solaris) server setup includes a Cisco CSS Load Balancer, two boxes that host our redundant  web servers (Weblogic) and Application Servers, and two boxes that host the database server (Oracle) and two process schedulers. There is a overall network that connects the load balancer and all four machines and a private network to connect the Application Servers to the database server. &lt;br /&gt;&lt;br /&gt;The CSS has a virtual address to connect to the PeopleSoft web application (PIA) and balances the sessions between the two web servers. Each of the web servers is configured to use all four application server domains. This allows quite a bit of flexibility for fault tolerance and maintenance shutdowns. It also allows for horizontal scalability transparent to the users.&lt;br /&gt;&lt;br /&gt;However, one of the problems we ran into involved the UNIX process schedulers and their ability to post files to the report repository. We have always used the FTP method for posting files. PeopleSoft also offers an HTTP post. As we learned through our troubleshooting, the FTP method has two steps. First the distribution server FTPs the files to report repository FTP address, then it sends an http query to the  repository to confirm that the files are there. We initially configured the http address to our load balanced virtual host name. Our Windows process schedulers were able to successfully post files to the the  report repository. Our UNIX process schedulers, however, would stay in Posting status and eventually go to Not Posted. By reviewing the logs, we figured out that the FTP was working fine. The files were actually in the repository, but http confirmation was failing. After a lot of testing, our network engineer determined that the http request was routed from the process scheduler through the CSS to a web server, but the web server response was routed directly to the database/process scheduler  box through the private network. To the  process scheduler distribution server, the response appeared to be coming from a server different than the one the request was sent to so the response was discarded.&lt;br /&gt;&lt;br /&gt;If we configured the report repository http address to the actual host:port of one of the web servers, the distribution worked fine, but we lost the redundancy of the dual web servers for this function.&lt;br /&gt;&lt;br /&gt;We also found that if we disabled the private network between the application servers and the database server, the http response was routed back through the CSS and distribution server was happy. This was not an ideal solution, though, because PeopleSoft is a very database intensive application and you want to optimize any communications between the application servers and the database.&lt;br /&gt;&lt;br /&gt;Eventually, the network engineer came up with a solution involving a third NIC on the database server. I don't have details at the moment, but it works. I will post more information when I get it.&lt;br /&gt;&lt;br /&gt;In future posts, I will go into other details of our architecture and the PeopleTools upgrade.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-5488787689130722952?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/5488787689130722952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=5488787689130722952' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/5488787689130722952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/5488787689130722952'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2007/09/peoplesoft-and-load-balancer.html' title='PeopleSoft and the Load Balancer'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2387668883227766307.post-371980201207973491</id><published>2007-09-09T21:22:00.000-07:00</published><updated>2007-09-10T07:00:28.635-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bike'/><category scheme='http://www.blogger.com/atom/ns#' term='bicycling'/><category scheme='http://www.blogger.com/atom/ns#' term='fitness'/><title type='text'>Biking the Bears</title><content type='html'>&lt;span style="font-family:georgia;"&gt;I rode this morning with the &lt;a href="http://www.diablocyclists.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Diablo&lt;/span&gt; Cyclists&lt;/a&gt;. They have changed their starting spot since the last time I rode with them to Heather Farms Park in Walnut Creek. To get more miles I rode from home to the start. It was a short (30 miles) but challenging ride around &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Briones&lt;/span&gt; Park. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Reliez&lt;/span&gt; Valley and Alhambra and over Happy Valley to Lafayette. As usual, I was in the middle of the pack. Three tandems showed up, but with the hills they were trailing the whole way.&lt;br /&gt;&lt;br /&gt;The lighter riders have the advantage on the climbs. The two women, both strong riders, would blow by me only to be caught on the downhills. It's a good club to ride with if you want to go pretty hard. I'm training for the &lt;a href="http://main.nationalmssociety.org/site/TR?px=1814929&amp;pg=personal&amp;amp;fr_id=5870"&gt;Waves-to-Wine&lt;/a&gt; MS  fund raising ride at the  end of September so it was good to be with a group that could push me. Total miles: 46. Max speed: 40 mph.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2387668883227766307-371980201207973491?l=danielkibler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://danielkibler.blogspot.com/feeds/371980201207973491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2387668883227766307&amp;postID=371980201207973491' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/371980201207973491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2387668883227766307/posts/default/371980201207973491'/><link rel='alternate' type='text/html' href='http://danielkibler.blogspot.com/2007/09/biking-bears.html' title='Biking the Bears'/><author><name>Dan Kibler</name><uri>http://www.blogger.com/profile/15502251805949478749</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://2.bp.blogspot.com/_VMLuCoZdQIs/TLJP8uW7phI/AAAAAAAADNY/Ui0ayBjaJ24/S220/DanProfile.jpg'/></author><thr:total>0</thr:total></entry></feed>
