Can I do SendKeys in Javascript? - 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.

Related

What can make a web application to not recognize the very inputting of values with JavaScript?

Often, in different websites, when I input text into a field with JavaScript (for the sake of automating form filling):
document.querySelector("#username").value = "USERNAME";
I encounter the following problem.
My problem
The above very inputting of text via JavaScript, either manually by devtool console or by a userscript manager, isn't effective so the form could not be submitted and I am asked something like "fill in data in all fields".
A way to deal with that is to delete the last (or first) character of the inputted text and then re-input that character manually myself and then the ext will be recognized but it's not really a solution.
A failed solution
I have tried to cope with the aforementioned problem with the following pattern, which failed:
1) Manually mouselick on all fields and then execute in devtool console:
dispatchEvent(new Event("keydown"));
dispatchEvent(new Event("keyup"));
dispatchEvent(new Event("change"));
true
2) Manually mouselick on all fields again;
My question
What can make a web application not recognizing the very inputting of values with JavaScript?
What can prevent the data being recognized unless at least one characters of it is manually changed?
Some possibilities of how a page may not recognize a programmatically inputted value are:
It may be listening for a different event from the one you're triggering. There are many types of events related to inputting text, including keypress, input, and focus. Take a look at what's logged in the following snippet when you manually click on the input and press keys:
let obj = input;
while (obj) {
for (const prop of Object.getOwnPropertyNames(obj)) {
if (!prop.startsWith('on')) continue;
input.addEventListener(prop.slice(2), () => console.log(prop.slice(2)));
}
obj = Object.getPrototypeOf(obj);
}
<input id="input">
The script may require one of those initial events to be fired before it starts processing other events. For example, perhaps the script requires a focus event before it starts observing key changes in the input. (Similarly, the script may be listening for events in a particular order, though that'd be pretty odd)
The script may also check if the event is trusted or not. Only user-initiated events are trusted; events dispatched via Javascript are not:
input.addEventListener('input', (e) => {
console.log(e.isTrusted);
});
setTimeout(() => {
input.dispatchEvent(new Event('input'));
}, 1000);
<input id="input">
In a situation like the above, your options to bypass it include
Triggering the event using something outside a browser, such as with AutoHotKey
Intercepting the <script> that adds the functionality and tweaking it so that it doesn't check if the event is trusted. Here's an example of doing that on Stack Exchange.

Quill JS - check if text change on Form Submit

I am using Quill (Rich Text) and need to find a way to checking to see if the text has changed when the page does a form submit. I am quite new to using Quill and have been looking at the events here. Using the text-change triggers everytime the text is changed (obviously) but I have other Form Input controls on the page which are checked on form submit to see if they have changed... I need my RTF boxes to do the same.
EDIT
I have managed to get the Event Firing using the example below. My problem now is that the event appears to trigger even when the editor is pre-populated on page load. I dont want to acknowledge these initial loads, only if the text has been changed by a user.
Two ways to do so:
1) listen for quill changes and if any occurred, raise a flag telling your form content has changed (flow: if you add a char, then delete it, your flag would be true even if resulting content is the same)
Using :
let changes = false
quill.on('text-change', function(delta, oldDelta, source) {
changes = true
})
2) comparing two snapshots of the document to detect front-end if changes occurred. You could either compare strings (with quill.getText()) this is the simplest, but you could miss lot of things, I would recommend to compare objects (with quill.getContents()) and use lodash or other deep equality objects method check.
Using:
const initialContents = quill.getContents()
const beforeSubmitContents = quill.getContents()
const hasChanged = _.isEqual(initialContents.ops, beforeSubmitContents.ops)
for detect if exis change only implement this function
quill.on('text-change', function(delta, oldDelta, source) {
if (source == 'api') {
console.log("An API call triggered this change.");
} else if (source == 'user') {
console.log("A user action triggered this change.");
}
});
this function detect if write or have a change on editor, detect if has change on your words or font or image...etc.. !!
In this case i use the example of official page:
page official
result :

document.getElementById always returns "null" for ribbons

I need to set the background color of one of the buttons in the form's ribbon. This isn't supported through Ribbon Workbench, so I have written following javascripts to achieve the same:
function setOpportunityRibbonsAppearance() {
var submitToForeCastButton = parent.document.getElementById("opportunity|NoRelationship|Form|sfw.opportunity.Button1.Button");
if (submitToForeCastButton != null) {
submitToForeCastButton.style.backgroundColor = "lightyellow";
}
}
I have registered this scripts in Form Load event. However the issue is that, I always get parent.document.getElementById as null only.
Surprisingly, I am able to see the control while running the parent.document.getElementById statement in the browser's console, and can also change the styling attributes.
Can anyone please suggest what could be wrong here?
P.S. - I understand document.getElementById is not recommended to use in CRM, however, I am left with no other choice while trying to change the appearance of some of the buttons.
Any help on this, will be much appreciated.
You could upload an icon with a yellow background, to keep everything supported. You won't see text on yellow but it might work for you. Easy and standard.
To keep it unsupported and ugly, you could just keep on trying until you make it, setInterval allows for a function to be repeated:
function setOpportunityRibbonsAppearance() {
var submitToForeCastButton = null;
var interval = setInterval(function(){
submitToForeCastButton = parent.document.getElementById("opportunity|NoRelationship|Form|sfw.opportunity.Button1.Button");
if(submitToForeCastButton != null) {
submitToForeCastButton.style.backgroundColor = "lightyellow";
clearInterval(interval);
}
}, 500); // Every 500ms. Adjust as needed, not too fast or browser will choke.
}
Its probably because your script is running before the page is fully loaded.
Try adding a delay to the to the function Put a Delay in Javascript

Zendesk Apps: How to create Event listeners after app was initialised?

I'm currently working on an app which has brand_field_id as one of it's parameters. It will hold the Custom Ticket Field ID for "Brand". The thing is: it is not required as the user might want or not to use the functionality it provides. Expected behaviour:
If this field is filled with an ID, an event listener for it's .change will be added on the custom field (and stuff will get done);
If it is left blank, nothing should happen. It means user opted to not use it.
Zendesk already provides the perfect listener for Custom Ticket Field change event, which works like this (dynamically using brand_field_id):
events: {
"ticket.custom_field_ticket.custom_field_{{brand_field_id}}.changed": "myCustomFieldChangedFunction"
}
... aaand it would be really awesome if the app didn't crash when brand_field_id is empty.
Since I don't want the app crashing if brand_field_id is left blank, I figured to validate it before adding the event listener, but didn't manage to get it done. I've tried a few variations of the following code within app.created event, but all unsuccessful.
if(!_.isEmpty(this.setting('brand_field_id'))){
console.log('Brand change event added');
this.events['ticket.custom_field_ticket.custom_field_{{brand_field_id}}.changed'] = 'brandChangedHandler';
}
console.log gets fired, so the validation is ok. Unfortunately the event never fires for the custom field.
So my question is: how can I add an event listener on the go? Or is there another way to achieve what I need?
I've even posted about this in Zendesk's community on a similar thread but no answers so far. The workaround I've found there actually works, but I'm not very fond of it:
events: {
// [...]
'*.changed': 'anyFieldChangedHandler'
},
// [...]
anyFieldChangedHandler: function(e){
// If the changed field was {brand_field_id}
if(!_.isEmpty(this.setting('brand_field_id')) && e.propertyName === 'ticket.custom_field_'+ this.setting('brand_field_id')){
this.brandChangedHandler(e);
}
},
It's much too broad and will fire whenever any field is changed on the ticket. I would like to find a better, cleaner and more elegant solution.
I'm in the same boat as I am aware of how difficult it is to find answers related to the Zendesk Apps framework.
I would do something like this
events: {
"ticket.custom_field_ticket.custom_field_{{brand_field_id}}.changed":"itChanged"
},
itChanged: function(){
if(ticket.custom_field_ticket.custom_field_{{brand_field_id}} !== null && ticket.custom_field_ticket.custom_field_{{brand_field_id}} !== undefined){
//Your custom field exists and has a value. Do something with it.
}
else{
//Your custom field does not exist and/or does not have a value. do nothing
}
}
Would something like this work for your app? I'm not sure if this would have the same functionality as !_.isEmpty() but you might give it a try. I use this a lot in my app sometimes just as a safe guard incase my app loads faster than the actual ticket, which causes some values to be "undefined" at the time the app loads.
Hope this helps

What's an effective way to move data from one open browser tab to another?

I am looking for a quick way to grab some data off of one Web page and throw it into another. I don't have access to the query string in the URL of the second page, so passing the data that way is not an option. Right now, I am using a Greasemonkey user script in tandem with a JS bookmarklet trigger: javascript:doIt();
// ==UserScript==
// #include public_site
// #include internal_site
// ==/UserScript==
if (document.location.host.match(internal_site)) {
var datum1 = GM_getValue("d1");
var datum2 = GM_getValue("d2");
}
unsafeWindow.doIt = function() {
if(document.location.host.match(public_site)) {
var d1 = innerHTML of page element 1;
var d2 = innerHTML of page element 2;
//Next two lines use setTimeout to bypass GM_setValue restriction
window.setTimeout(function() {GM_setValue("d1", d1);}, 0);
window.setTimeout(function() {GM_setValue("d2", d2);}, 0);
}
else if(document.location.host.match(internal_site)) {
document.getElementById("field1").value = datum1;
document.getElementById("field2").value = datum2;
}
}
While I am open to another method, I would prefer to stay with this basic model if possible, as this is just a small fraction of the code in doIt() which is used on several other pages, mostly to automate date-based form fills; people really like their "magic button."
The above code works, but there's an interruption to the workflow: In order for the user to know which page on the public site to grab data from, the internal page has to be opened first. Then, once the GM cookie is set from the public page, the internal page has to be reloaded to get the proper information into the internal page variables. I'm wondering if there's any way to GM_getValue() at bookmarklet-clicktime to prevent the need for a refresh. Thanks!
Can you move the bookmarklet to a button or link -- that Greasemonkey will add to the page(s)?
Then you could set click-event handlers to fire GM_getValue().
It looks like the current method is exploiting a "security hole" -- one that may be closed in the future. You might consider doing everything in a Firefox extension, instead.
Possibly useful link: http://articles.sitepoint.com/article/ten-tips-firefox-extensions/1

Categories