Tampermonkey: Trigger event does not work for element - javascript

I'm trying to add some functionality using Tampermonkey on top of a providers angular application but I'm stuck at this simple thing. I can't replicate the issue using CodePen so we're going to have to go for theories and suggestions. I'll try to be as specific as I can.
Adding this interval when the page loads to check when an input with the id serialNumberInput is available. Then I'm adding a dropdown to the form, and attach an onChange event to it to update the serial input field with the value of the selected option. However, the trigger parts just never happens. It does work when I enter them manually, but not with the script.
var populateSerialNumbersTimer = setInterval(function(){
var serial = $("input#serialNumberInput");
if($(serial).length >= 1){
$(serial).css("display", "inline").css("width", "50%");
$(serial).after(deviceToSerialSelectionHTML);
$("select#deviceToSerial").on("change", function(){
$(serial).val($("select#deviceToSerial").val());
$(serial).trigger("change");
$(serial).trigger("blur");
});
clearInterval(populateSerialNumbersTimer);
}
}, 200);
I've thought about it and considering how the serial number ends up in the text field the field must be accessible. Maybe it's that the events that I'm trying to trigger has not been declared at the time of the function declaration?
Suggestions much appreciated.

It looks like jQuery tries to cache the event somehow. This is how I solved it with native javascript in case someone else is interested:
function triggerEvent(e, s){
"use strict";
var event = document.createEvent('HTMLEvents');
event.initEvent(e, true, true);
document.querySelector(s).dispatchEvent(event);
}
$("select#deviceToSerial").on("change", function(){
serialNumberInput.val($("select#deviceToSerial").val());
triggerEvent("change", "input#serialNumberInput");
triggerEvent("blur", "input#serialNumberInput");
}

Related

rangeslider.js calling onchange() twice

I am developing a phonegap application, and I am using rangeslider to make the regular <input type=range> elements more visually appealing. However I ran into a problem with the following function which is called when the onchange() event fires:
function store_slider(){
store_slider_val=document.getElementById("slider").value; //gets the value of the slider
if(store_slider_val==100){
//if slider is at 100 give a notification
navigator.notification.confirm('Mark task as complete?',task_complete_handle,'Hey there!','YES,NO');
function task_complete_handle(button){
if(button==1){
//do stuff
}
else{
//set the slider to 90
$('#slider').val(90).change();
}
}
}
else{
//do other stuff
}
}
The issue I'm facing is that the when the slider is at 100 the notification produced by navigator.notification.confirm('Mark task as complete?',task_complete_handle,'Hey there!','YES,NO'); appears twice instead of once when I try the app in my phone(Appears only once when I run it in my laptop browser). When I don't use rangeslider the code works as expected.
How can I fix this issue? Rangeslider was a perfect and simple solution to making range inputs look better and I would really like to continue using this and not switch to another slider plugin.
I solved this problem only by completely removing rangeslider.js and using another plugin as it seems it is connected to the way rangeslider is implemented.
What I did was to only update the model if the value was different, this ensured that my model push to the back-end was only called once and not twice eg:
if (Model.value != $this.value) {
Model.value = $this.value;
PostToBackEnd();
}

Firing a manual click event on an button in ember.js doesn't give the required result

TL;DR: Trying to fire a manual javascript click event on the chat button of twitch, won't send the message. Don't understand why the event doesn't do the same as a normal click and don't know how to make it work.
So I am trying to make a custom bot for twitch.tv, only reading his info from the HTML directly. I've got it perfectly working up to the point at where it can recognize commands and put text in the textbox. Now the problem I have is, as soon as I try to fire a manual click event on the "chat" button, it just doesn't seem to work. My guess is it has something to do with ember.js, and I frankly don't know anything about that. Anyway, here is the part of the code that doesn't work. EDIT: this works if I enter it as single in the console, doesn't work in context of the rest of my code though.
$('.send-chat-button').click();
What happens here is that I acquire a piece of html that contains the chat submit button, which is this:
<button class="button primary float-right send-chat-button" data-bindattr-3945="3945">
<span>
Chat
</span>
</button>
When I try to manually fire a click event on this, nothing happens. However, when I fire a manual click event on buttonContain.children[0] and buttonContain.children1 (which are, respectively, the settings and list of viewers buttons), it does work. They look like this:
<a data-ember-action="3943" class="button glyph-only float-left" title="Chat Settings"></a>
I'm guessing the difference is in the data-ember-action and the data-bindattr-*, but I don't know how to make it work. Anyone here knows why the click() event doesn't work and directly clicking does?
EDIT: If you have any questions about my question, feel free to ask.
EDIT2: I experimented a little more, and I can remove all HTML attributes from the button, and clicking on it will still work. I have no idea what is going on :(.
EDIT3: Okay, so it seems it only stops working when i remove the
Span within the button
Still no idea what is going on. (Yes, have also tried to fire the click event on the span)
EDIT4: As requested, here is all the code from my side. Note that I'm trying to click a button from twitch itself, of which ember side I do not own any code. This code is used by pasting it in the console on a twitch.tv stream and then starting it by calling initiateMessageProcessing. I'm sorry for the lot of hardcoded values, those are twitch' fields that I need. For now I'm just looking for a proof of concept.
var frequency = 5000;
var myInterval = 0;
var lastMessageId = 0;
function initiateMessageProcessing() {
if (myInterval > 0) {
clearInterval(myInterval);
}
myInterval = setInterval("checkMessages()", frequency);
}
function checkMessages() {
var chat = document.getElementsByClassName("chat-lines")[0];
processMessages(extractUnprocessedMessages(chat.children));
lastMessageId = parseInt(chat.lastElementChild.getAttribute("id").substring(5, 10));
}
function extractUnprocessedMessages(chat) {
var unprocessedMessages = [];
var chatId = 0;
for ( i = 0; i < chat.length; i++) {
chatId = parseInt(chat[i].getAttribute("id").substring(5, 10));
if (chatId > lastMessageId) {
unprocessedMessages.push(chat[i]);
}
}
return unprocessedMessages;
}
function processMessages(unprocessedMessages) {
var messageElement;
for ( i = 0; i < unprocessedMessages.length; i++) {
messageElement = unprocessedMessages[i].children[0].getElementsByClassName("message")[0];
if (messageElement != undefined && messageElement != null) {
if (messageElement.innerHTML.search("!test") !== -1) {
sendMessage('Hello world!');
}
}
}
}
function sendMessage(message) {
fillTextArea(message);
var button = $('.send-chat-button').get(0);
var event = new MouseEvent('click', {
bubbles : true
});
button.dispatchEvent(event);
}
function fillTextArea(message){
var textArea;
var chatInterface = document.getElementsByClassName("chat-interface")[0];
var textAreaContain = chatInterface.children[0];
textArea = textAreaContain.children[0].children[0];
textArea.value = message;
}
EDIT5: Eventlistener screenshot:
EDIT6: Edited source code to use $('.send-chat-button').click();
I have tried this, does not work in the current code, it does work if I manually fire this single command in the console when there is text in the chat. But sadly does not work in my code.
EDIT7: used Ember.run, still doesn't work.
EDIT8: used dispatchmouseevent, still doesn't work in context of code
It seems that the target site attaches event listeners without help of JQuery. If it is so, you cannot trigger it using jquery .click() method.
You can try directly mocking the browser event like this:
var button = $('.send-chat-button').get(0);
var event = new MouseEvent('click', {bubbles: true});
button.dispatchEvent(event);
This code will not work in IE8 and lower, but I guess it is not your case.
I know this post is quite old but I had been looking for an answer on this for a while and nothing really worked, after trying out A LOT of stuff I found it works when you focus the chatbox first then focus the button then triggering the click event!!! uuuhm yeah...
$('.chat_text_input').focus();
$('.send-chat-button').focus().trigger('click');
I have no idea why this works (and why it doesn't in any other way), but leaving any of the focusses out makes it fail or bug out.
Programmatically clicking a DOM element to make some action done is somewhat a wrong approach.
You should have define a method myAction() which will be called in two ways. First, from your ember action triggerMyAction() and second, after listening to a custom event, "myEvent".
Instead of $('.send-chat-button').click(); you will code $('something').trigger("myEvent") then.
Something like:
Em.Controller.extend({
myAction:function(){
//do your stuff
},
onMyEvent:function(){
$('something').on('myEvent',this.myAction);
}.on('didInsertElement'),
actions:{
triggerMyAction:function(){
this.myAction();
}
}
})

Limiting click detection on the page [javascript]

I'm trying to limit the user's ability to click on an object to a certain time limit. I looked around and found that apparently, setTimeout() is the correct function to use for this type of thing. I've applied the function to my code, but its not working. I'm thinking/know now that the problem is that the setTimeout in my code isn't limiting the actual click event, which I need to do. Here is a snippet of my click code:
function clickRun(event) {
var $objectVersion = correspondingObject(event.target.id);
if (isAnyVisible() == false) { // none open
$objectVersion.makeVisible();
} else if (isAnyVisible() && $objectVersion.isVisible()) { //click already open div
$objectVersion.makeInvisible();
} else if (isAnyVisible() && $objectVersion.isVisible()==false) { //different div open
searchAndDestroy();
$objectVersion.delay(600).makeVisible();
};
};
$('.ChartLink').click(function(event) {
setTimeout(clickRun(event),5000);
});
I've also created a JSFiddle to represent what I'm talking about: http://jsfiddle.net/FHC7s/
Is there a way to achieve limiting the actual click detection on the page?
I think the easiest way to do it is to keep track of the time of the previous click and if the current click is too soon after that, then don't do anything:
onClick = function(){
if(new Date().getTime() - lastCheck < MIN_CLICK_SPACING) return;
}
Have a look at this JSFiddle, I've set it up so you can have the button disable itself for time duration after detecting a click. Just make sure to remember how your closures are operating with your setTimeouts.
Your code contains an error... your line should be
setTimeout(function(){clickRun(event)},5000);
but even then I don't think that's exactly what you're looking for; that code will "delay" the click by 5 seconds, not actually prevent more clicks. If your true intent is to ignore all clicks after a certain amount of time, then I would go with mowwalker's answer; there's no way to stop the clicks, but you can check to see if you should honor them or not.

Prevent typeahead.js dropdown from closing on select

How can I prevent a typeahead dropdown from closing when an item is selected? I've tried using preventDefault like this:
$('#q').bind('typeahead:selected',function(obj, datum, name) {
...
obj.preventDefault();
});
But no success.
Edit:
I've managed to "fix" this by building Typeahead with lines 217-218 commented from typeahead_views.js:
byClick && utils.isMsie() ?
utils.defer(this.dropdownView.close) : this.dropdownView.close();
But there has to be another way without modifying source files?
Had the same problem and the (very easy) solution doesn't seem to be documented anywhere
$(document).on('typeahead:beforeclose', function(event, data) {
event.preventDefault()
})
(this just prevents the dropdown from closing at all which can be very helpful during development, use 'typeahead:beforeselect' if you want to prevent closing just on selet).
Trigger the focus of the input on the closed callback.
$('#typeahead-input').on('typeahead:closed', function(e, d) {
$('#typeahead-input').focus();
});
I'm working on typeahead inside tokenfield so the first part is me accessing the Typeahead.dropdown object, which in itself took some hunting.
Tried toying with isOpen or overwriting close functions, in the end closest I got was this. Breaking down the marshalling of events. You'd have to reimplement any saving of values etc, basically the first 3 lines of Typeahead.select.
I myself was blocked at being able to put a form (focus stays in input field) in the dropdown and still a bit more hunting if were to put something interactive in there. Think I'll go for a roll-your-own solution on this one but might help someone who just wants to block the closing, put the original function in a var to put it back in place when you're finished.
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').dropdown.trigger = function(e) {};
Also this has potential:
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').eventBus.trigger = function(e) {};
A simpler way:
input.data('tt-typeahead')._selectOld = input.data('tt-typeahead')._select
input.data('tt-typeahead')._select = function(datum) {
if (false)
this._selectOld(datum)
}

TinyMCE opened in jqueryUI modal dialog

When using tinyMCE in a jqueryUI modal dialog, I can't use the hyperlink or 'insert image' features.
Basically, after lots of searching, I've found this:
http://www.tinymce.com/develop/bugtracker_view.php?id=5917
The weird thing is that to me it seams less of a tinyMCE issue and more of a jqueryUI issue since the problem is not present when jqueryUI's modal property is set to false.
With a richer form I saw that what happens is that whenever the tinyMCE loses focus, the first element in the form gets focus even if it's not the one focused / clicked.
Does some JavaScript guru have any idea how I might be able to keep the dialog modal and make tinyMCE work?
This fixed it for me when overriding _allowInteraction would not:
$(document).on('focusin', function(e) {
if ($(event.target).closest(".mce-window").length) {
e.stopImmediatePropagation();
}
});
I can't really take credit for it. I got it from this thread on the TinyMCE forums.
(They have moved their bugtracker to github. tinymce/issues/703 is the corresponding github issue.)
It seems there are no propper solution for this issue yet. This is kind of a hack but it really worked for me.
Every time you open the Dialog remove the text area and re add it like following,
var myDialog = $('#myDialog');
var myTextarea = myDialog.find('textarea');
var clonedTextArea = myTextarea.clone(); // create a copy before deleting from the DOM
var myTextAreaParent = myTextarea.parent(); // get the parent to add the created copy later
myTextarea.remove(); // remove the textarea
myDialog.find('.mce-container').remove(); // remove existing mce control if exists
myTextAreaParent.append(clonedTextArea); // re-add the copy
myDialog.dialog({
open: function(e1,e2){
setTimeout(function () {
// Add your tinymce creation code here
},50);
}
});
myDialog.dialog('open');
This seems to fix it for me, or at least work around it (put it somewhere in your $(document).ready()):
$.widget('ui.dialog', $.ui.dialog, {
_allowInteraction: function(event) {
return ($('.mce-panel:visible').length > 0);
}
});

Categories