Not able to shift focus to Shipment Nbr field on Shipments screen - javascript

I'm using the built in Acumatica browser commands to insert a new shipment record by pressing a function key. The function Key triggers the command with px.searchFrame(window.top,"main")['px_alls'].ds.executeCommand("Insert"); For some reason, it triggers the insert command, but it doesn't shift the focus to the Shipment Nbr input field. Also, if you try to shift the focus manually using var field=px_alls["edShipmentNbr"]; field.focus(); that doesn't work either. I've been able to shift the focus to other fields, so I know the code is correct, but I can't figure out why the focus can't be shifted to the Shipment Nbr input. Any ideas on what else can be done? It's not just the Insert command either. Calling the Cancel command, which should shift the focus, doesn't work either.
What's strange is that the Insert command can be called by pressing Ctrl+Insert, and it works perfectly.
I built some code that shifts the focus to the ship date field and then tabs backwards 5 times, which emulates correctly what the insert command should do, but it only works intermittently on the client's computer.
Thanks

The Acumatica Framework provides built-in support for keyboard shortcuts via the following properties defined in PXButtonAttribute:
ShortcutShift = true/false : Determines Shift key presence
ShortcutCtrl = true/false : Determines Control key presence
ShortcutChar = ‘x’ : Determines shortcut character
Below is the sample to insert new Shipment when the user presses F2. Since the code snippet below utilizes capabilities of the framework, by pressing F2 the user executes the Insert command from the SOShipmentEntry BLC instead of simulating button click in JavaScript. This approach guarantees that all logic embedded into the Insert command, including setting focus to the Shipment Nbr input, is properly executed.
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
public class PXInsertShortCut<TNode> : PXInsert<TNode>
where TNode : class, IBqlTable, new()
{
public PXInsertShortCut(PXGraph graph, string name)
: base(graph, name)
{
}
public PXInsertShortCut(PXGraph graph, Delegate handler)
: base(graph, handler)
{
}
[PXUIField(DisplayName = ActionsMessages.Insert, MapEnableRights = PXCacheRights.Insert, MapViewRights = PXCacheRights.Insert)]
[PXInsertButton(ShortcutChar = (char)113)]
protected override IEnumerable Handler(PXAdapter adapter)
{
return base.Handler(adapter);
}
}
public PXInsertShortCut<SOShipment> Insert;
}

If you're executing a callback to the server in JavaScript, the callback return might set focus to another field after it finishes execution. Your focus() statement works but the callback return performs another focus() on a different control after yours.
Hooking the Ajax callback allows you to put your focus() statement after the Acumatica framework focus():
window.addEventListener('load', function () { px_callback.addHandler(ActionCallback); });
function ActionCallback(callbackContext) {
px_alls["edShipmentNbr"].focus();
};

Related

Xamarin iOS WKWebView showing JavaScript Alert

I would like to show the JavaScript Alert in my WKWebView. I have implemented the IWKUIDelegate and its methods RunJavaScriptAlertPanel, RunJavaScriptConfirmPanel. These gets called for a JavaScript Alert. I would like to know how to handle the buttons and action on those buttons.
Is there a way i can write a generic UIAlertView for all JavaScript Alerts. For example below i have added errorAlert.AddButton("OK"); but in reality i don't know number of buttons and button title. Also how to handle the completionHandler action
[Export ("webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:")]
public void RunJavaScriptConfirmPanel (WKWebView webView, String message, WKFrameInfo frame, Action<bool> completionHandler)
{
Console.WriteLine ("RunJavaScriptConfirmPanel");
UIAlertView errorAlert = new UIAlertView();
errorAlert.Title = "Alert";
errorAlert.Message = message;
errorAlert.AddButton("OK");
errorAlert.Show();
}
I'm not sure where you're trying to handle the action, whether it is in javascript or with C# in the app, so I'll try to address both. The short answer is, let javascript handle it, and if need be, make a call back to the app from javascript once a selection has been made from the dialog.
Alert Example
public override void RunJavaScriptAlertPanel(WKWebView webView, string message, WKFrameInfo frame, Action completionHandler)
{
var alert = UIAlertController.Create("Alert", message, UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
//Let javascript handle the OK click by passing the completionHandler to the controller
ViewController.PresentViewController(alert, true, completionHandler);
}
Confirm Example
public override void RunJavaScriptConfirmPanel(WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler)
{
var alert = UIAlertController.Create("Please confirm", message, UIAlertControllerStyle.Alert);
//Let javascript handle the OK click by passing the completionHandler to the controller
alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, action => completionHandler(true)));
//Let javascript handle the Cancel click by passing the completionHandler to the controller
alert.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, action => completionHandler(false)));
ViewController.PresentViewController(alert, true, null);
}
Prompt Example
public override void RunJavaScriptTextInputPanel(WKWebView webView, string prompt, string defaultText, WKFrameInfo frame, Action<string> completionHandler)
{
var alert = UIAlertController.Create("Prompt", prompt, UIAlertControllerStyle.Alert);
alert.AddTextField(textfield => { textfield.Placeholder = defaultText; });
alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, action => completionHandler(alert.TextFields[0].Text)));
alert.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, action => completionHandler(null)));
ViewController.PresentViewController(alert, true, null);
}
So that gives you an example of how to pass the button clicks back to javascript. If you want javascript to make a call back, you'll need to register script handlers by subclassing from WKScriptMessageHandler. There's a basic example here https://forums.xamarin.com/discussion/41777/wkwebview-caching-not-working
Just as a note, UIAlertView has been deprecated. You might want to start using UIAlertController instead. See https://stackoverflow.com/a/32690371/5606840. If you want access to the view controller to display the alerts, pass it into your WKUIDelegate class at initialization.
Edit
To expand on how to handle the results in javascript
alert('This is an alert');
The webview will pause the javascript thread and call RunJavaScriptAlertPanel. Once the OK button has been clicked, it will call back the completionHandler in the webview and the rest of the javascript code will execute.
if (confirm('Do you want to confirm this?')) {
//Do some code here when the user clicks ok
} else {
//Do other code here when the user clicks cancel
}
As with the alert example, when javascript comes across the confirm method, it will call RunJavaScriptConfirmPanel. You can then show the dialog with the text passed through the message, along with an OK and Cancel button. Depending on the button clicked, the method will push either a true or false back to the webview and allow the rest of the javascript code to execute via the completion handler.

How do I create a wait event in dojo that waits for a user to click a button before continuing?

I have the following code in a javascript file:
if(dojo.byId('WC_selectedColorNumber') == null && this.defaultColor != null)
{
dijit.byId('WC_color_selection').domNode.style.display = 'block';
dojo.html.set(dojo.query(".message__button .add"), "Add product with only base color " + this.defaultColor + "?");
var userResponse = true;
dojo.connect(WC_add_color_yes, "onclick", function(evt){
userResponse = true;
});
dojo.connect(WC_add_color_no, "onclick", function(evt){
userResponse = false;
});
//var userResponse = confirm("Add product with only base color " + this.defaultColor + "?");
//I WANT TO WAIT HERE FOR THE RESPONSE
if(userResponse == false) //if user clicks Cancel or 'no', display a message and leave the function.
{
alert("Remember to select a color before adding to cart."); //should be a tooltip/popup (not javascript alert) with the same message
return; //return so item doesn't get added to cart
}
}
Firstly, the logic behind this code is correct and it works perfectly well when using javascript confirm's.
As of now, everything comes up and displays correctly, and clicking the buttons perform the correct actions (if I put a console.log in the onclick dojo events, they do indeed print to the console when I click the buttons). However, the program doesn't wait for the responses and continues beyond the dojo.connect methods before it sees the user's input.
I need it to wait until either the yes or no button have been pressed, but I cannot figure out how to do it. I've tried using a
while(userResponse == null);
but a) it's generally a terrible idea and b) it didn't work anyways.
How can I make my code wait until the user has clicked one of the two buttons?
If you can make a jsfiddle I'd be able to help you more, I think, but your dojo.connect calls shouldn't be inside a logic flow like this. Instead, set up your connects on widget startup, and have them act generically.
In your example code, it looks to me like saying "Yes" means "Use default color", and "No" means "User must specify color". So...
startup: function () {
this.inherited(arguments);
dojo.connect(WC_add_color_yes, "onclick", dojo.hitch(this, function(evt){
this.useDefaultColor();
}));
dojo.connect(WC_add_color_no, "onclick", dojo.hitch(this, function(evt){
this.displayColorPicker();
}));
}
And then... only display those two buttons (or the dialog they're hopefully in) when applicable.
There is no "wait" or "sleep" function in javascript and each invocation of javascript code executes to completion (it does not get interrupted in mid execution by a response to some other event). You have correcly identified the historical execeptions that overcome this - global alert and confirm functions execute in browser native code and wait on user input.
Because of this your code will have to be restructured in some way, e.g. an event handler for "add to cart" validates the color choice and calls a function to really add it to the cart if valid. If it is not valid it modifies the DOM to present user with some buttons. The handler for the "yes" option would likewise call the same function to really add it to the cart.
Specific code is outside the scope of this answer - there must be many methods in page and code design to achieve the desired result. For example only: breaking up the sequential code and putting it in separate event handlers, coding using Promise objects defined in EC6 but not supported in MSIE, or perhaps even providing an option of "none - base color only" in the color selection logic.
FYI the dojo 1.10 toolkit documentation reports support for Dojo Promises but I leave research to determine its suitability with you.

How to have function trigger from a keypress in node?

I have a script written in javascript which does something to a drone that I have. As of now I run that script in my shell like this node foo.js and the script runs till I abort it using control C. But now I want to be able to run that script and have it listen for keyboard events that I give it (such as ENTER, up/down arrow key, spacebar), and depending on the event it performs a specific function. And when I am done I should be still able to press control C to stop the program. It would be awesome if someone could help me. I am still in highschool and very new to programming.
Here is the script for reference:
var arDrone = require('ar-drone');
var client = arDrone.createClient();
client.takeoff();
client
.after(10000, function() {
this.stop();
this.land();
});
Each keyboard key has a special key code (i.e. f = 70). You can find that here:
http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
I would use jQuery to trigger these events, the first is any keystroke:
$(function() {
$('client').keydown();
$('client').keypress();
$('client').keyup();
});
The second is specific keystrokes:
$function() {
var e = $.Event('keypress');
e.which = 39; // right arrow
$('client').trigger(e);
});
So then you would have a function called trigger that checked for specific numbers, and you would move your drone accordingly.

Can I do SendKeys in Javascript?

SendKeys is method to sending keystroke to an application.
Can I do it in Javascript, to send keystroke in browser ?
REF :
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
If you would be able to send keystrokes on the OS Level, this would be a big security issue.
You could (for instance) install any kind of software on the client machine if you where able to send keystrokes to the needed install dialogs.
Yes, you could come up with an active-x control or some other tools to be installed on the client machine. But because of the security issues with such a tool, I wouldn't do it -- even in a controlled environment.
Most of the time, there is a way to achieve your needed functionality without breaching the security.
Update: If you want to jump to the next tabfield, you have to use the focus() method to set the focus to the next element. Unfortunately, you have to find the next element by yourself in javascript, but this should not be a big problem - you can keep an ordered list of all your elements in javascript.
btw: http://forums.devarticles.com/javascript-development-22/moving-to-next-tabindex-on-event-2382.html
There are lots of JS Framework implemented event simulation inside web page.
Is it possible to simulate key press events programmatically? for jQuery
Javascript: simulate a click on a link for YUI
However, simpler method is that the third post of the link given by Ralf which focus the "next" textfield regarding to the tabIndex property of elements inside a form element.
There might be a more brilliant way if you make up a list of textfield's IDs and the order you want to be.
Of course, the tabIndex list might not be generated by yourself but by walking around the textfield.
Create a loop to generate the list when document is loaded (DOMContentLoaded):
var tabIndexList = new Array();
function tabIndexListGeneration(){
var form = document.getElementById("Your form ID"), // remember to fill in your form ID
textfields = form.getElementsByTagName("input"),
textfieldsLength = textfields.length;
for(var i=0;i<textfieldsLength;i++){
if(textfields[i].getAttribute("type") !== "text" || textfields[i].getAttribute("tabIndex") <= 0)continue;
/* tabIndex = 0 is neglected as it places the latest, if you want it, change 0 to -1
* and change tabIndexPointer = 0 into tabIndexPointer = -1 below */
tabIndexList[textfields[i].getAttribute("tabIndex")] = textfields[i];
}
}
// You can use the function of JS Framework if you don't like the method below.
if(document.addEventListener){
document.addEventListener("DOMContentLoaded", tabIndexListGeneration, false);
}else{
window.attachEvent("onload", tabIndexListGeneration);
}
And inside the event of "text input equals textfield maxlength":
var tabIndexPointer = target.getAttribute("tabIndex"); // target is the DOM object of current textfield
while(!(++tabIndexPointer in tabIndexList)){
if(tabIndexPointer >= tabIndexList.length)
tabIndexPointer = 0; // or other action after all textfields were focused
}
tabIndexList[tabIndexPointer].focus(); // if other action needed, put it right after while ended
Note: form textfields' structure must not be mutated otherwise an error would be given out.
If textfield generate dynamically, run tabIndexListGeneration() to regenerate the list.
This works for me. The ActiveXObject needs to be opened in IE.
var PaintProg = new ActiveXObject("WScript.Shell"); //paste to mspaint
PaintProg.Run("mspaint.exe \\\\srv4\\photos\\image1.jpg",9,false);
var PaintTimer = window.setInterval(PaintPaste,1000);
function PaintPaste()
{
if (PaintProg.AppActivate("Paint",true) == true)
{
PaintProg.SendKeys('"^(v)""%(F)""x""~"',true);
window.clearInterval(PaintTimer);
}
}
Not by default in most browsers, no. You may be able to get it to work using ActiveX if it's going to be running in Internet Explorer, however.

Requiring confirmation from user before browser close _iff_ a Flex variable is true

I have a Flex application which allows the user to edit a cloud-based document. (Think SlideRocket.) When the user tries to navigate away or close the browser window, I'd like to show them an are-you-sure dialog iff they have unsaved changes.
I'm using the following custom class, which I found at Flash player notified on browser close or change page (as3). I don't think it is the problem.
package
{
import flash.external.ExternalInterface;
public class ExternalInterfaceUtil
{
public static function addExternalEventListener(qualifiedEventName:String, callback:Function, callBackAlias:String):void
{
// 1. Expose the callback function via the callBackAlias
ExternalInterface.addCallback( callBackAlias, callback );
// 2. Build javascript to execute
var jsExecuteCallBack:String = "document.getElementsByName('"+ExternalInterface.objectID+"')[0]."+callBackAlias+"()";
var jsBindEvent:String = "function(){"+qualifiedEventName+"= function(){"+jsExecuteCallBack+"};}";
// 3. Execute the composed javascript to perform the binding of the external event to the specified callBack function
ExternalInterface.call(jsBindEvent);
}
}
}
In my applicationComplete function, I add an event listener to the javascript window.onbeforeunload event, as follows:
ExternalInterfaceUtil.addExternalEventListener("window.onbeforeunload", requestUnloadConfirmation, "unloadConfirmation");
The Actionscript function requestUnloadConfirmation (below) is successfully called when the user tries to close the browser window. However, it does not prevent the browser from closing. (In Chrome, the browser closes and the Actionscript function is called subsequently. In Firefox, the browser stays open for the duration of the function but then closes.)
private function requestUnloadConfirmation():String {
if (changedSinceSave)
return "There are unsaved changes. Are you sure you want to leave without saving?";
else
return null;
}
Behavior is identical in both debug and release builds, and on the production server as well as the local machine.
Any help would be greatly appreciated,
Dave
Right now, when the JavaScript event is fired, it is set to call your function in your AS3 code, which it does. The JavaScript function, however, is not returning the value that your AS3 function returns. To get this behaviour, add 'return' to the JavaScript event-handling function created in addExternalEventListener like so:
var jsBindEvent:String = "function(){"+qualifiedEventName+"= function(){return "+jsExecuteCallBack+"};}";
Since the event handler should return a true or false value, your requestUnloadConfirmation function should have a return type of Boolean and return false to cancel the event, and true otherwise. Use the following to get a confirmation dialog box:
private function requestUnloadConfirmation():Boolean {
if (changedSinceSave)
return ExternalInterface.call("confirm", "There are unsaved changes. Are you sure you want to leave without saving?");
else
return false;
}
UPDATE:
It turns out that returning a string to window.onbeforeunload causes a confirmation dialog box to be shown automatically. The ExternalInterface.call to confirm causes a second dialog box to show; it is redundant. The only change required in the AS3 code is to add the "return" in the generated JavaScript.
In a regular html/javascript web-app you would use the window.onbeforeunload event to do this.
https://web.archive.org/web/20211028110528/http://www.4guysfromrolla.com/demos/OnBeforeUnloadDemo1.htm
Perhaps you can use this event, and check some value of your flex app to determine if you should ask the user (not familiar with flex...)?
I had to run some modifications in the above code to make it work.
The problem was due to the fact that the function which handles the event window.onbeforeunload, should not return any value to avoid popup confirmation and should return text value when a popup confirmation is in-order
Here are my changes:
private function requestUnloadConfirmation():String {
if (changedSinceSave){
return "There are unsaved changes. Are you sure you want to leave without saving?";
}
return null;
}
And a little change in embedded JS
var jsBindEvent:String = "function(){"+qualifiedEventName+"= function(){ if ("+jsExecuteCallBack+") return "+jsExecuteCallBack+"};}";

Categories