How to add client side java script on a Acumatica Button - acumatica

Good day
I was wondering if it's possible to hook a Javascript onto a PXAction button. normally you can use the ClientEvents Property but with a button, these are not exposed.
The problem I am is every now and then there is a delay between the client and the server and the client will click the button a second time. I have server-side code to help stop this by disabling the button but I want to add a javascript to see if I can prevent it completely.
The code I want to add:
<script type="text/javascript">
var submit = 0;
function CheckDouble() {
if (++submit > 1) {
alert('This sometimes takes a few seconds - please be patient.');
return false;
}
}
</script>
Any ideas or workaround I can maybe try?

I believe the PXJavaScript control is what you are after.
I used this link to help get my head wrapped around how to use the control. We had a need to trigger something off with Java Script and the PXJavaScript control got us to the end result we needed.
Dynamically Change Button Color
Let me know if this helps?
Robert

Related

xpages - enableModifiedFlag -> possible to prevent default dialog at beforeunload event?

For my xpages app I want to set the enableModifiedFlag to true to have a dirty form functionality to check if changes are made to a page.
I tried to avoid that the default warning message will appear when moving away from the page by setting the page to not dirty but this not prevent/hinder that the default dialog appears. what am I doing wrong?
window.addEventListener('beforeunload',(event) =>{
var isdirty = XSP._isDirty();
console.log("check -> is dirty? " + isdirty);
if(XSP._isDirty()){
console.log("set dirty to false to avoid ugly standard alert dialog");
XSP._setDirty(false,"");
//add this to prevent default behaviour e.g. open another page
event.preventDefault();
//add here code to present a more fancy bootstrap dialog
//XSP.openDialog("dirtyDialog")
return false;
}
});
Haven't done exactly what you do...
However, if on a button you want to "cancel" then you only need to call
XSP._setDirty(false,"");
prior to navigating away. No need to call event.preventDefault() in that case. So I'm guessing that the default code is called prior to your "before unload" event - perhaps you can try and see if you could intervene a little before or somehow rethink the approach.
Perhaps I don't fully understand what you want to obtain when having this functionality but avoiding to use it when leaving the page - or is this just a test example?
/John

Auto-collapse any item in PrimeFaces PanelMenu on page loading

I'm writing a Primefaces 5.1 portlet.
It consists in a unique page containing a panelMenu, and I need that it starts with any panel collapsed everytime a user change page (on page loading).
But, if I open a panel, then change page, it will start showing that panel still opened.
I wasn't able to find any option to achieve this goal (e.g. collapsed=true, ignoreCookie=true or something similar).
The only solution I found was the following Javascript code:
PrimeFaces.widgets.myPanelMenu.collapseRootSubmenu(PrimeFaces.widgets.myPanelMenu.headers);
The problem is that this code will collapse any opened panel (so on page loading user is able to see panel menu collapsing animation) but it seems it doesn't store this state in its cookie/localstorage... the result is that on any page loading user can see this animation.
I'm sure it doesn't save its state, because the only way to "solve" the problem is to manually re-open and re-collapse the panels... then, on following page change, these menus start closed (and there is no animation).
I also tried to use PrimeFaces.widgets.sideMenuPanel.saveState() after collapsing, but with no success.
Do you have any idea about?
Thank you...
I found a solution to the problem.
If you read my discussion with Kukeltje (comments on my question), you will find that latest Primefaces' versions will solve the problem.
Otherwise, if you want to avoid upgrade or modify sources, and you need a quick fix based on Javascript only please read the following part of the answer.
It directly works on the component's state using JavaScript.
First of all you need to have a variable reference to your component:
<p:panelMenu model="#{menuBackingBean.menuModel}" widgetVar="sidePanelMenu" />
Then you should add the following JS code on document ready:
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
// following line is commented because it never should be necessary is not necessary (unless unexpected situation I never verified)
//clearSidePanelMenuPreferences();
// 2. Call the "clear preferences" actions on click on two tpe of links: first level are the panel link (used to open/close the menu) and second level are the destination links
// We need to fork also on the first level links to be sure it works after user clicks there then exit from the page in another way
panelMenu.headers.children("a").click(function(){setTimeout(clearSidePanelMenuPreferences, 500)}); // setTimeout is necessary because this event should be fired after preferences are written
panelMenu.headers.siblings().find("a").click(function(){clearSidePanelMenuPreferences();});
The function called to clear preferences are the following:
function clearSidePanelMenuPreferences() {
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState(); // store this information
}
Hope it helps
Please check this block of code
PF('myPanelMenu').headers.each(
function(){
var header = jQuery(this);
PF('myPanelMenu').collapseRootSubmenu(header);
header.removeClass('ui-state-hover');
}
);
I prefer to do this in order to execute this method only once and keep the menu option selected.
$(document).ready(function() {
if(location.pathname == "/cotizador/" || location.pathname == "/cotizador/faces/login.xhtml"){
var panelMenu = PrimeFaces.widgets.sidePanelMenu;
// 1. On page loading collapses possible opened panels
panelMenu.collapseRootSubmenu(panelMenu.headers);
panelMenu.expandedNodes = []; // clear the opened panels lists
panelMenu.saveState();
}
});

Chrome Extension - first link is auto-focused in popup

How do I stop my Google Chrome extension's default action to auto-focus the first link in my popup.html? I know I could probably do some roundabout hack with JS or change the :focus CSS, but I think this is throwing off something else I'm trying to do and I'd prefer to stop the root cause of it.
The easiest (and javascript free!) way is to simply add tabindex="-1" to any element which you don't want to receive automatic focus.
Perhaps auto-focus was intended for a convenience, but often it does a disservice. Since I see no way to stop the root cause, I found some roundabouts. One is using JavaScript. Chrome puts auto-focus after a short delay after displaying the popup. It's possible to unfocus it with blur() but unfocusing it too late will flash it momentarily, and trying to unfocus too early will do nothing. So to find the right time to unfocus is not easy, and this solution tries to do this several times during the first second after the popup is displayed:
document.addEventListener("DOMContentLoaded", function () {
var blurTimerId = window.setInterval(function() {
if (document.activeElement != document.body) {
document.activeElement.blur();
}
}, 200);
window.setTimeout(function() {
window.clearInterval(blurTimerId);
}, 1000);
});
Another pure HTML solution is to add tabindex="1" to the body tag.
Wrangling the initially focused element with a tabindex attribute is probably the best way to go, using:
tabindex="-1", as suggested by Paul Ferret to prevent an element from getting focus
tabindex="1", as suggested by link0ff, to specify which element should start with focus
If your situation is more complicated and you do want to bring in some javascript, I'd recommend using link0ff's solution, except, instead of trying to guess when to blur with timeouts, listen for the initial focus in event:
function onInitialFocus(event) {
// Any custom behavior your want to perform when the initial element is focused.
// For example: If this is an anchor tag, remove focus
if (event.target.tagName == "A") {
event.target.blur();
}
// ALSO, remove this event listener after it is triggered,
// so it's not applied to subsequent focus events
document.removeEventListener("focusin", onInitialFocus);
}
// NOTE: the "focusin" event bubbles up to the document,
// but the "focus" event does not.
document.addEventListener("focusin", onInitialFocus);
I don't believe the focus event is cancelable, so you can't just suppress the event.
Another easy alternative (which preserves "tabbability") is to just add an empty link () before your first actual link. It will invisibly "catch" the auto-focus from Chrome, but any users who want to tab through the links will still be able to do so normally.
The only minor downside of this approach is that it introduces a second "dead tab" when looping; that is, users will have to press tab three times to get from the last link back to the first, instead of just twice.
tabindex="-1" worked for me. I was adding autofocus to an input and it didn't work until I used this tabindex="-1" attribute for each link before the input.
Strange to say the least.
This is the best solution to the problem. The tabindex="-1" solution harms user experience, and as opposed to #link0ff's solution, this one removes the focus instantly.
This element should be the first focusable element in the DOM:
<button class="invisible-button"></button>
This simply removes the button once it's been focused:
function removeAutoFocus(e) {
if (e.target.classList.contains("invisible-button")) {
e.target.style.display = "none";
document.removeEventListener("focus", removeAutoFocus);
}
}
document.addEventListener("focus", removeAutoFocus, true);

#{javascript:viewScope.something} won't update after context.redirectToPage(...)

It is not long ago that I asked this question, which was about updating a property bundle after a csjs-induced full refresh. I solved it with a URL-parameter that lead to a context.redirectToPage.
Now I have an xPage with a jquery-based jqGrid, which receives a string with JSON-data from the viewScope and displays that data in a table. When I edit a record in the grid and hit 'submit' the grid posts a parameter called 'oper' with values like 'edit', 'add', etc., for which I check in the beforePageLoad event of the page and then execute the save method of my managed bean. After this I update the viewScope variable with the new JSON-string and conduct a full refresh in the above mentioned manner which had worked before.
<xp:this.beforePageLoad><![CDATA[#{javascript:
if (bccUser.isAdmin() && param.containsKey('oper') && param.get('oper').toString().length>0) {
bccGridDataHandler.saveGridDoc('RequestDummy','PersonRequestsDummy',param);
}
viewScope.put('jsonString',bccView.getViewColumnValue('PersonRequestsDummyJson',1));
print('jsonString in viewScope: '+viewScope.get('jsonString'));
if (bccUser.isAdmin() && param.containsKey('oper') && param.get('oper').toString().length>0) {
var url = context.getUrl().toSiteRelativeString(context);
if (url.indexOf('?')!=-1) {
url += "&doRefresh=true";
} else {
url += "?doRefresh=true";
}
print("redirecting to: "+url);
context.redirectToPage(url);
}}]]>
In the server console I can see the correct, updated JSON-string from the first print statement, so the save-method was successful and I have up-to-date data in my viewScope. The grid, however, does not show the updated data, neither does my test-div
<xp:text value="#{javascript:viewScope.get('jsonString')}" />
I also tried a partial refresh on the grid and div after updating the viewScope, but the same happened. After a manual refresh of the page everything is fine again. So, what's happening here? I just want to pass a simple string to a control. Am I mistaken again about the xPages-Lifecycle and the order of events?
Thanks in advance. Regards, Sarah
I think you are losing the viewScope value in the redirectToPage. Try with requestScope or sessionScope.
Thanks for all the suggestions, I tried them all out but unfortunately with no luck. The most interesting thing about this was, that when I put a clientside alert statement into the onClientLoad event it would just fire once, when I enter the page, but not after any of the context.redirect or .reload commands.
After all I solved the problem the following way:
I removed the redirect command from the beforePageLoad event and added the following parameter to the submit function of the jqGrid (see documentation here):
afterSubmit: function(response, postdata) {window.location.href=window.location.href;return [true,'',''];}
This works for me (onClientLoad is also triggered again after this), but still I wonder why a page refresh induced from the serverside doesn't do the same thing as a clientside refresh, or isn't able to imitate a clienside refresh.
I am not sure if the beforePageLoad event is the right one, have you considered generating the JSON in beforeRenderResponse?

jQuery or JS handling browsers back button

Any ideas how to intercept the browser back button via jQuery, so I can run my event function?
I don't need to use jQuery BBQ or jQuery Address, only prevent the default behaviour and run it later after some animate.
Thank you!
d
Have not tried but i guess this do what you want.
window.onbeforeunload = function () {
// stuff do do before the window is unloaded here.
}
with jQuery you could try the .unload() function
The unload event is sent to the window
element when the user navigates away
from the page. This could mean one of
many things. The user could have
clicked on a link to leave the page,
or typed in a new URL in the address
bar. The forward and back buttons will
trigger the event. Closing the browser
window will cause the event to be
triggered. Even a page reload will
first create an unload event.
In jQuery land:
$(window).unload( function () { /*code here*/ });
EDIT- There was a parentheses instead of a close bracket
EDIT - Removed Extra Semicolin

Resources