dojo aspect and key press - javascript

Is there a way to capture a key press event with dojo/aspect and aspect.after?
I am using a third party Javascript API (ESRI JS API v3.4) that provides a widget for drawing graphics on a map. The draw toolbar widget has an onDrawEnd event that provides the shape of the drawn graphic object as a parameter. I need to determine if the user was pressing the CTRL or SHIFT key while drawing on the map with this widget, but I use aspect.after(drawingToolbar, "onDrawEnd", myhandlerfunction, true) to connect the drawing event.
The only way I know how to determine if a key is pressed is by using an event object, which is not provided when using aspect like it is with dojo/on.
Any ideas how I can determine if a key is pressed here?

Maybe u musst go another way to catch up a Key-Event.
This is how i catch the "Enter"-Event in a Textbox. When the Enter-Key is hit, the function zoomToAnlage() is called. It's important that this event listener is already loaded in the ini-phase.
Sure, this is not a total resolve for your Question, but maybe it shows a way how you can handle it.
function initKielAnlagenNummernSuchen(){
queryTaskAnlagenNummern = new esri.tasks.QueryTask(restServicesLocation + NameSearchService + "/MapServer/23");
queryallAnlagenNummern = new esri.tasks.Query();
queryallAnlagenNummern.returnGeometry = true;
queryallAnlagenNummern.outFields = ["ANLAGE"];
require(["dojo/keys","dojo/dom","dojo/on"], function(keys, dom, on){
on(dom.byId("selectAnlagenNummer"), "keypress", function(evt){
var charOrCode = evt.charCode || evt.keyCode;
if (charOrCode == keys.ENTER) {
zoomToAnlage();
}
});
});
}
Here's a Link to dojo/keys : http://dojotoolkit.org/reference-guide/1.8/dojo/keys.html?highlight=keys#id2
Regards, Miriam

dojo.aspect can't connect to events, only functions. However you should be able to aspect to a function that is handling that event, and steal its args.
aspect.after(drawingToolbar, "someHandlerFunctionWithTheEventArg",
function(args){
// access the event from the args here
}, true);

Related

Post comments on Facebook page via console

Like in the image, the Facebook comment box has no submit button, when you write something and press Enter button, the comment posted.
I want to submit the comment via JavaScript that running in console, but I tried to trigger Enter event, submit event of the DOM. Could not make it work.
The current comment boxes aren't a traditional <textarea> inside of a <form>. They're using the contenteditable attribute on a div. In order to submit in this scenario, you'd want to listen to one of the keyboard events (keydown, keypress, keyup) and look for the Enter key which is keycode 13.
Looks like FB is listening to the keydown evt in this case, so when I ran this code I was able to fake submit a comment:
function fireEvent(type, element) {
var evt;
if(document.createEvent) {
evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true);
} else {
evt = document.createEventObject();
evt.eventType = type;
}
evt.eventName = type;
evt.keyCode = 13;
evt.which = 13;
if(document.createEvent) {
element.dispatchEvent(evt);
} else {
element.fireEvent("on" + evt.eventType, evt);
}
}
fireEvent('keydown', document.querySelector('[role="combobox"]._54-z span span'));
A couple of things to note about this. The class ._54-z was a class they just happened to use on my page. Your mileage may vary. Use dev tools to make sure you grab the right element (it should have the aria role "combobox"). Also, if you're looking to support older browsers, you're going to have to tweak the fireEvent function code above. I only tested the above example in the latest Chrome.
Finally, to complicate matters on your end, Facebook is using React which creates a virtual DOM representation of the current page. If you're manually typing in the characters into the combobox and then run the code above, it'll work as expected. But you will not be able to set the combobox's innermost <span>'s innerHTML to what you're looking to do and then trigger keydown. You'll likely need to trigger the change event on the combobox to ensure your message persists to the Virtual DOM.
That should get you started! Hope that helps!
Some years after, this post remains relevant and is actually the only one I found regarding this, whilst I was toying around trying to post to FB groups through JS code (a task similar to the original question).
At long last I cracked it - tested and works:
setTimeout(() => {
document.querySelector('[placeholder^="Write something"]').click();
setTimeout(() => {
let postText = "I'm a Facebook post from Javascript!";
let dataDiv = document.querySelector('[contenteditable] [data-offset-key]');
let dataKey = dataDiv.attributes["data-offset-key"].value;
//Better to construct the span structure exactly in the form FB does it
let spanHTML = `<span data-offset-key="${dataKey}"><span data-text="true">${postText}</span></span>`;
dataDiv.innerHTML = spanHTML;
let eventType = "input";
//This can probably be optimized, no need to fire events for so many elements
let div = document.querySelectorAll('div[role=presentation]')[1].parentElement.parentElement;
let collection = div.getElementsByTagName("*");
[...collection].forEach(elem => {
let evt = document.createEvent("HTMLEvents");
evt.initEvent(eventType, true, true); //second "true" is for bubbling - might be important
elem.dispatchEvent(evt);
});
//Clicking the post button
setTimeout(()=>{
document.querySelector('.rfloat button[type=submit][value="1"]').click();
},2000);
}, 4000);
}, 7000);
So here's the story, as I've learned from previous comments in this post and from digging into FB's code. FB uses React, thus changes to the DOM would not "catch on" as React uses virtual DOM. If you were to click "Post" after changing the DOM from JS, the text would not be posted. That's why you'd have to fire the events manually as was suggested here.
However - firing the right event for the right element is tricky business and has almost prevented me from succeeding. After some long hours I found that this code works, probably because it targets multiple elements, starting from a parent element of the group post, and drilling down to all child elements and firing the event for each one of them (this is the [...collection].forEach(elem => { bit). As written this can be obviously be optimized to find the one right element that needs to fire the event.
As for which event to fire, as was discussed here, I've experimented with several, and found "input" to be the one. Also, the code started working after I changed the second argument of initEvent to true - i.e. evt.initEvent(eventType, true, true). Not sure if this made a difference but I've had enough hours fiddling with this, if it works, that enough for me. BTW the setTimeouts can be played around with, of course.
(Unsuccessfully) Digging into FB's React Data Structure
Another note about a different path I tried to go and ended up being fruitless: using React Dev Tools Chrome extension, you're able to access the components themselves and all their props and states using $r. Surprisingly, this also works outside of the console, so using something like TamperMonkey to run JS code also works. I actually found where FB keeps the post text in the state. For reference, it's in a component called ComposerStatusAttachmentMentionsInputContainer that's in charge of the editor part of the post, and below is the code to access it.
$r actually provides access to a lot of React stuff, like setState. Theoritically I believed I could use that to set the state of the post text in React (if you know React, you'd agree that setState would be the right way to trigger a change that would stick).
However, after some long hours I found that this is VERY hard to do, since FB uses a framework on top of React called Draft.js, which handles all posts. This framework has it's own methods, classes, data structures and what not, and it's very hard to operate on those from "outside" without the source code.
I also tried manually firing the onchange functions attached to the components, which didn't work because I didn't have the right parameters, which are objects in the likes of editorContent and selectionContent from Draft.Js, which need to be carefully constructed using methods like Modifier from Draft.js that I didn't have access to (how the hell do you externally access a static method from a library entangled in the source code?? I didn't manage to).
Anyway, the code for accessing the state variable where the text is stored, provided you have React dev tools and you've highlighted ComposerStatusAttachmentMentionsInputContainer:
let blockMap = $r["state"].activeEditorState["$1"].currentContent.blockMap;
let innerObj = JSON.parse(JSON.stringify(blockMap)); //this is needed to get the next property as it's not static or something
let id = Object.keys(innerObj)[0]; //get the id from the obj property
console.log(innerObj[id].text); //this is it!
But as I wrote, this is pretty much useless :-)
as I wasn't able to post comments through the "normal" facebook page, I remembered that they also have the mobile version, which is on m.facebook. com, there, they still have the submit Button, so depending on your needs, this may be a good option
so, you could go to the mobile facebook post (eg https://m.facebook.com/${author}/posts/${postId}) and do
// Find the input element that saves the message to be posted
document.querySelector("input[name='comment_text']").value='MESSAGE TO POST';
// find the submit button, enable it and click it
const submitButton = document.querySelector("button[name='submit']");
submitButton.disabled = false;
submitButton.click();
Here is a working solution after 3 weeks of experimenting (using #Benjamin Solum's fireEvent function):
this version posts a comment only for the first post on the page (by using querySelector method)
this version can be used only on your personal wall (unless you change the query selectors)
function fireEvent(type, element, keyCode) {
var evt;
if(document.createEvent) {
evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true);
} else {
evt = document.createEventObject();
evt.eventType = type;
}
evt.eventName = type;
if (keyCode !== undefined){
evt.keyCode = keyCode;
evt.which = keyCode;
}
if(document.createEvent) {
element.dispatchEvent(evt);
} else {
element.fireEvent("on" + evt.eventType, evt);
}
}
// clicking the comment link - it reveals the combobox
document.querySelector(".fbTimelineSection .comment_link").click();
setTimeout(function(){
var combobox = document.querySelector(".fbTimelineSection [role='combobox']");
var spanWrapper = document.querySelector(".fbTimelineSection [role='combobox'] span");
// add text to the combobox
spanWrapper.innerHTML = "<span data-text='true'>Thank you!</span>";
var spanElement = document.querySelector(".fbTimelineSection [role='combobox'] span span");
fireEvent("blur", combobox);
fireEvent("focus", combobox);
fireEvent("input", combobox);
fireEvent("keydown", spanElement, 13); // pushing enter
},2000);
function fireEvent(type, element) {
var evt;
if(document.createEvent) {
evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true);
} else {
evt = document.createEventObject();
evt.eventType = type;
}
evt.eventName = type;
evt.keyCode = 13;
evt.which = 13;
if(document.createEvent) {
element.dispatchEvent(evt);
} else {
element.fireEvent("on" + evt.eventType, evt);
}
}
fireEvent('keydown', document.
to solve your question may you see this link, there is a example how to "Auto comment on a facebook post using JavaScript"
"Below are the steps:
Go to facebook page using m.facebook.com
Sign in and open any post.
Open developer mode in Chrome by pressing Ctrl+Shift+I
Navigate to the console.
Now, run the below script."
var count = 100;
var message = "Hi";
var loop = setInterval(function(){
var input = document.getElementsByName("comment_text")[0];
var submit = document.querySelector('button[type="submit"]');
submit.disabled = false;
input.value = message;
submit.click();
count -= 1;
if(count == 0)
{
clearInterval(loop);
}
}, 10000);
Kind regards
ref.: source page

Has anyone created keybindings in Meteor successfully?

I've been trying to implement keybindings in Meteor for a while. I tried the following package:
https://github.com/matteodem/meteor-keybindings
But no matter what I do it keeps saying that the methods (e.g. add keybinding) is undefined. So I was thinking of using another method.
Has anyone created keybindings in Meteor successfully? Say, triggering an event by pressing alt + a?
If you mean key events anywhere on the page, not just inside an input field, I use the method below to add these callbacks to the window. you then have to manually remove them too on closing that route.
on the mac, control keys etc just work to send different keycodes.
however, I haven't had success with this on windows yet - don't have a machine here to test and trying briefly didn't seem to elicit key responses. However i think that's more of a jquery/browser thing that anything meteor related. Let me know if you find useful keycodes on windows for Ctrl-S etc (or alt-S)!
onRun and onStop should only get called once, but i find events in iron;router a bit unpredictable, so it's worth adding in your own checks for initDone=true/false.
#coffeescript
#--- router
Router.map ->
#route 'myTemplate',
path: '/some/path'
onRun: ->
Template.komikPlayer.initScene()
onStop: ->
Template.komikPlayer.exitScene()
then in the relevant view template have init and exit events to setup/teardown the key events
Template.myTemplate.initScene = () ->
addKeyEvents()
Template.myTemplate.exitScene = () ->
removeKeyEvents()
addKeyEvents = () ->
console.log('addKeyEvents')
$(window).on 'keydown', (e) -> handleKeys(e)
handleKeys = (e) ->
switch e.keyCode
when 69
console.log('edit')
url = "/komikEditScene/#{comic.data.params.chapter}/#{comic.data.params.scene}"
window.open(url, 'editor')
when 39, 32, 13 # next
navTo("#nextField")
when 37 # back
navTo("#backField")
else
console.log('unused key:', e.keyCode)
Not sure if this is helpful, but I am using a simple keypress detection in the events area of my js file. This only works if the input field is selected.
//keypress input detection for autofilling form with test data
    'keypress input': function(e) {
        if (e.which === 17) { //17 is ctrl + q
            fillForm();
        }
    }

Mouse click simulates keyboard key in JavaScript

I have situation that in application (HTML/XUL) there are key bindings for some function keys (F5, F7 & F9) in order to communicate with some other application.
Now I have to make touch-based interface for same app, without keyboard and advanced touch events. All touch clicks are actually same as mouse clicks and I need to have 3 buttons/links that behave same as F5, F7 & F9 keys.
Don't ask for reasons, all I can say is that I need to keep that key bindings.
Can I assign mouse click on link to act like F-key is pressed?
In Jake's answer is most of solution and based on that I gave the whole answer, because is not so easy on first glance for beginners to modify functionality.
This is modified function from this thread:
function simulateKeyPress(target, options) {
var event = target.ownerDocument.createEvent('KeyEvents'),
options = options || {};
// Set your options or || default values
var opts = {
type: options.type || "keypress",
bubbles: options.bubbles || true,
cancelable: options.cancelable || true,
viewArg: options.viewArg || null,
ctrlKeyArg: options.ctrlKeyArg || false,
altKeyArg: options.altKeyArg || false,
shiftKeyArg: options.shiftKeyArg || false,
metaKeyArg: options.metaKeyArg || false,
keyCodeArg: options.keyCodeArg || 0,
charCodeArg: options.charCodeArg || 0
}
// Pass in the options
event.initKeyEvent(
opts.type,
opts.bubbles,
opts.cancelable,
opts.viewArg,
opts.ctrlKeyArg,
opts.altKeyArg,
opts.shiftKeyArg,
opts.metaKeyArg,
opts.keyCodeArg,
opts.charCodeArg
);
// Fire the event
target.dispatchEvent(event);
event.stopPropagation;
}
And now we call it on desired element/event for desired key to be pressed. Second argument is object with all options changeable (in my case keyCodeArg: 116 is only needed to be send to simulate F5 key press).
document.getElementById(element).addEventListener('click', function() {
simulateKeyPress(this, {keyCodeArg: 116});
});
Mozilla Developer Network has nice articles about KeyboardEvents and initKeyEvent.
There are two ways to do this I guess.
The simple way would be to have your F-keys call a function, and simply call the same function when catching a mouse event.
The other way would be to catch the mouse event, and fire a F-key press event. Then it would pretty much be a duplicate of this question:
How to simulate a mouse click using JavaScript?

Gamepad javascript create event recorder

I'm writing a little javascript game and trying to make it work with a gamepad. The gamepad works (on linux at least). I wrote this code:
var gamePad;
var checkForGamepad;
function startPolling() {
checkForGamepad= setInterval(function () {
gamePad= navigator.webkitGetGamepads && navigator.webkitGetGamepads()[0]
},20)}
function stopPolling(){
clearInterval(checkForGamepad);
checkForGamepad=null;
}
This is for starting to check if there is a gamecontroller connected and I can also stop it (for when I'm in the menu for example). But now I want to write an event recorder. I wrote already one for the keyboard, but that's easy because you have a 'keyup' event. Does anybody have an idea, how to write an event recorder for a gamepad?
My event recorder for my keyboard looks like this:
function gameNavigationKey(evt){
switch (evt.keyCode){
case 32: // spacebar was pressed
//change the gravity
// do some other stuff
break;
.
.
.
}
And in the code when I start my gameloop(), I also call window.addEventListener('keyup',gameNavigationKey,true)
So I want basically the same style for my event recorder with my gamepad.
I know I can read values of keys being pressed on the gamepad using gamePad.buttons[0] returns 0 when not pressed 1 while being pressed. So I think I need to remember the previous state of my key, but still, don't have an idea how to start.
Can somebody please help me creating this event recorder?
Thanks in advance
In the current implementation of the Gamepads with Chrome, at every update you have to call:
navigator.webkitGetGamepads();
It will give you the latest status of the pads. If you want to implement something out of it you will need to compare with the previous status and make your own events.
Firefox doesn't require to call getGamepads at every frame, but updates the object automatically after you implement the events gamepadconnected and gamepaddisconnected.
You can find extra information here:
http://www.html5rocks.com/en/tutorials/doodles/gamepad/
https://developer.mozilla.org/en-US/docs/Web/Guide/API/Gamepad

How to emulate press Enter key with Zombie.js

Do you know how to press Enter key with Zombie.js ?
Thanks in advance.
There's no way to do that yet using just zombie API. It's because .fire() method doesn't allow you to pass any event data in addition to event name (which would be necessary to state which keyCode is associated with that key event).
WTK is correct and there's no native way in zombie.js but I think you could add a javascript function to simulate the enter key press and trigger it from zombie.js like so:
If you have access to the page source, add a function on your page to simulate the enter key press:
function pressEnterKey(elmSelector){
elmSelector = elmSelector || 'document'
var e = jQuery.Event("keypress");
e.which = 13;
e.keyCode = 13;
$(elmSelector).trigger(e);
}
Trigger it from zombie.js:
browser.evaluate("pressEnterKey()");
If you don't have access to the source you could inject the script on the page using something like this. Remember to use browser.wait after to ensure the page is ready:
var injectedScript = browser.document.createElement("script");
injectedScript.setAttribute("type","text/javascript");
injectedScript.innerText = '...pressEnterKey function text here...'
browser.body.appendChild(injectedScript);

Categories

Resources