Saturday, November 2, 2013

AutoSave ePerformance Part II

In September I posted a link to some auto Save JavaScript for ePerformance.  This worked, but it prevented the page from timing out and it would also save while I would be typing on the document and then all of a sudden I would be at the top of the document.  This was quite annoying.  At the same time I was working on warning the user about leaving the page via the back button, I had asked Jim Marion a couple questions and he recommended I monkey patch the timeout function to auto save the document. So below is my JavaScript that monkey patches the displayTimeoutMsg function and warns the user if they navigate away from the page with the back button.


<input type="hidden" name="AUTOSAVE" value=""/>
<script type="text/javascript">

threadLock = false;

function user_function()
{
//alert('starting process');

var changes = checkFormChanged(document.%formname);
if (changes && !threadLock)
{
threadLock = true;
if ("%page" == "EP_APPR_MAIN1" || "%page" == "EP_APPR_BASE1")
{
//submitAction_%Formname(document.%Formname,"EP_BTN_LINK_WRK_EP_STORE_PB");
hAction_%Formname(document.%Formname,'EP_BTN_LINK_WRK_EP_STORE_PB', 0, 0, 'Save', false, true);
}
}
}

</script>
<script type="text/javascript" language="javascript">
(function() {
  var originalendModalCntrl = ptCommonObj.endModalCntrl;
  ptCommonObj.endModalCntrl = function() {
    window.onbeforeunload = function(){};
    return new originalendModalCntrl();
  }
})();

window.onbeforeunload = function(e) {
           var changes = checkFormChanged(document.%formname);
if (changes && !threadLock)
{
threadLock = true;
if ("%page" == "EP_APPR_MAIN1" || "%page" == "EP_APPR_BASE1")
{
            return "You have unsaved changes, please save them."
        };
}
}
</script>

<script type="text/javascript">
function adaptLinks() {
    var links = document.getElementsByTagName('a');
    for (i = 0; i != links.length; i++) {
        links[i].onclick = (function () {
            var origOnClick = links[i].onclick;
            return function (e) {
                 window.onbeforeunload = function(){};
                if (origOnClick != null && !origOnClick()) {
                    return false;
                }               
            }
        })();
    }
}
(function() {
  var originaldisplayTimeoutMsg = displayTimeoutMsg;
  displayTimeoutMsg = function() {
    window.onbeforeunload = function(){};
   
    user_function();

    return new  originaldisplayTimeoutMsg();
  }
})();

adaptLinks();
</script>

13 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. We tried this piece of code on Tools 8.51, but when the Save is triggered, it reset's the Timeout counter. How can we prevent the Time-out counter from being reset in Tools 8.51 and App 9.1 ?

    ReplyDelete
  3. Divya,

    This code does reset the timeout counter, however the second time the user will be timed out. This was acceptable in my organization as we time users out every 30 minutes. But we had considered moving that to 1 hour. If this is not acceptable to your organization then you need a mechanism to tell you when the save happens organically vs the timeout JavaScript that we are injecting into the page.

    You can add a hidden field to your page and mark that field as “Modifiable Via JavaScript” , then give it Page Field Name that is meaningful, something like AUTOSAVEFLAG. Then in your HTML that your adding to the page add this new Flag as a Hidden Input.

    < input type="hidden" id="AUTOSAVEFLAG" name="AUTOSAVEFLAG" value="F"/>
    < script type="text/javascript">
    threadLock = false;
    function user_function()
    {
    var changes = checkFormChanged(document.%formname);
    if (changes && !threadLock)
    {
    threadLock = true;
    if ("%page" == "EP_APPR_MAIN1" || "%page" == "EP_APPR_BASE1")
    {
    //submitAction_%Formname(document.%Formname,"EP_BTN_LINK_WRK_EP_STORE_PB");

    var flag = document.getElementById('AUTOSAVEFLAG');
    flag.value = 'T';
    Preceding code is not changed….
    Then add some PeopleCode to the SavePreChange event of your hidden field to inject javascript to redirect the user to the logout url.

    ReplyDelete
  4. Kevin,
    We are currently trying to implement exactly what you documented here. I have one question and it may sound very stupid, but where do we need to put this code. We already have a working 'autosave' like your original , but we would like to do exactly what you have posted here and I just need some help as to where the code needs to go. I am very new to javascript and monkey patching and just need some guidance.

    Thanks,
    Anthony

    ReplyDelete
  5. Anthony,

    I added an HTML area to both the Page.EP_APPR_MAIN1 and Page.EP_APPR_BASE1 at the bottom, then I pasted the JavaScript above into the HTML area as a constant value.

    To test this code, I used FireFox and the Firefox plugin, Firebug. You can set breakpoints within the JavaScript and interact with the browser via the console. These techniques are shown in Jim Marion's PeopleTools Tips and Techniques book. If you don't have a copy then I recommend that you get one, as it has a great chapter on JavaScript.


    Thanks for stopping by!

    ReplyDelete
    Replies
    1. Kevin, Should this also work for IE 8? I added the HTML area (and code) to both pages and neither the autosave or navigation message is working. Is there something else that needs done in AppDesigner? My email is scott.tallent@windstream.com Thanks

      Delete
    2. Scott, I believe this will work with IE 8. However, I would start by debugging using firebug or chrome.

      Delete
  6. Hi Kevin,

    Could you please tell me whether you are passing any time interval for auto-save to happen or will the code be fired continuously until the user gets logged off?

    Since EP_APPR_EDIT5 is the page where we type a lot , and if we using the above piece of code to save EP_APPR_EDIT5 which will call the save button thus redirecting it to EP_APPR_BASE1 page might lead to resetting of timer.

    ReplyDelete
  7. Supriya,

    We are also discovering that users are being timed out on this page as well, we are also discovering managers are opening multiple windows and are losing their data when the secondary window timesout. I have no solution for this last issue, other then training. But the first issue, the same one you are having is not accounted for within this post. I will be looking into a solution for this in the near future.

    My initial thought is to add a hidding field that is accessible via javascript to this page that will execute some save peoplecode, since there is currently no save functionality on this page.

    ReplyDelete
  8. I hope this blog topic is still active in spite of its age.

    We have tried this code at PT 8.50, PS 9.1. The warning about leaving the page without saving data is a welcomed touch, and is working. But the timeout does not work for us.

    Even after enabling the alert("starting process") code, we never see that alert. Instead, we see the standard timeout message, and then the timeout does occur without save.

    I wonder if the function displayTimeoutMsg() has a different name or doesn't exist at our version level?

    I am also confused by the test for page names (if ("%page" == "EP_APPR_MAIN1" || "%page" == "EP_APPR_BASE1")) since we are directly modifying those two pages. Makes me think my approach may be incorrect. To me, that is the equivalent of code like "if (2+2 == 4)" So I'm convinced that I didn't understand something, and my approach is flawed. Can you help?

    ReplyDelete
    Replies
    1. You are correct regarding the %page code. The useful part of this code is if your going to use tools 8.54+ and component branding. You would only want to save the component from these two pages, or you will get a data buffer error on the document.


      Try using chrome and bring up console (F12) and then navigate to the doucment and look for some JavaScript errors. We have decommissioned this code and now use the delivered auto save that is available in 9.2 tools 8.54.

      Delete
  9. kevin, looks like your above code for "warning the user about leaving the page via the back button" works only in 9.1/<8.52 versions.

    I heard you saying there is a delivered auto save that is available in 9.2 tools 8.54.
    we just recently upgraded tools to 8.54 but still on 9.1.

    1.can you let me know the delivered auto save code and i will try to implement in 8.54/9.1 to see if it works.

    ReplyDelete
    Replies
    1. I included the js that we were using during testing, while we worked out a bug with the delivered Autosave. I am happy to share it with you, but it is not fully vetted and you will still need to follow the approach I laid out in AutoSave III.


      change the input_tag to input and the script_tag to script below:












      // special variable to store "our" single jQuery instance
      if(!window.psjq$) {
      window.psjq$ = window.$ = window.jQuery;
      } else {
      // ignore recent import and use the global single instance
      window.jQuery = window.$ = psjq$;
      }









      threadLock = false;
      var xStore = document.getElementById("ZZ_EP_STORE");




      function user_function()
      {
      //alert('starting process');
      // debugger;
      console.log('user_functin called');
      if (!threadLock)
      {
      threadLock = true;
      if ("%page" == "EP_APPR_BASE1" )
      {
      xStore.value = 'T';
      //alert(xStore.value);
      //document.%formname.submit();
      window.onbeforeunload = function(){};
      console.log('appr_base1 save called');
      submitAction_%Formname(document.win0,'#ICSetFieldEP_APPR_BASE1.EOTL_UI_BTN_ID.EXIT_SAVE#SAVE');


      } else {
      xStore.value = 'T';
      //alert(xStore.value);
      //document.%formname.submit();
      window.onbeforeunload = function(){};
      console.log('EP_APPR_MAIN1 save called');
      submitAction_%Formname(document.win0,'#ICSetFieldEP_APPR_MAIN1.EOTL_UI_BTN_ID.EXIT_SAVE#SAVE');



      }


      }
      }





      function adaptLinks() {
      var links = document.getElementsByTagName('a');
      for (i = 0; i != links.length; i++) {
      links[i].onclick = (function () {
      var origOnClick = links[i].onclick;
      return function (e) {

      window.onbeforeunload = function(){};
      if (origOnClick != null && !origOnClick()) {
      return false;
      }
      }
      })();
      }
      }
      $(document).ready(function() {
      // debugger;
      console.log('setting ZZtimeoutID');
      zztimeoutID = window.setTimeout('user_function()', (warningTimeoutMilliseconds + 5000));
      });



      Delete