javascript help; pausing autorefresh - javascript

trying to figure a way to keep my chat div area from refreshing and annoyingly scrolling to the bottom. after searching the only solution I could come up with, is setting a global to a certain value and changing it when onfocus and back with onblur.
javascript was never my strongest area and I think it might just be me.
var chatarea = document.getElementById('usertalk');
window.onload= function() {
chatarea.scrollTop = chatarea.scrollHeight;
}
var chatfocus = false;
chatarea.onfocus=function(){ chatfocus = true; }
chatarea.onblur=function(){ chatfocus = false; }
setInterval("updateChat()", 5000);
function updateChat(){
var ajaxRequest;
ajaxRequest = new XMLHttpRequest();
ajaxRequest.onreadystatechange = function(){
if(ajaxRequest.readyState == 4){
if(chatfocus === false){
chatarea.innerHTML = ajaxRequest.responseText;
chatarea.scrollTop = chatarea.scrollHeight;
}
}
}
ajaxRequest.open("GET", "comments.php?t=<?php echo $topicc; ?>", true);
ajaxRequest.send(null);
}
If javascript would print me errors I could probably figure it out or search enough to understand. I've tried many different variations and assigning it to window but still script doesn't wanna work. I finally gave up and moved on in php and im now able call a edit form to replace a comment inside this same div that I want to auto refresh and going to need to pause this script for that too. But once again have no idea of achieving in js without asking questions.

"usertalk" doesn't exist at the time execution so attaching your event handlers is failing. Put your event handlers in the onload function:
var chatarea = null;
window.onload= function() {
chatarea = document.getElementById('usertalk');
chatarea.scrollTop = chatarea.scrollHeight;
chatarea.onfocus=function(){ chatfocus = true; }
chatarea.onblur=function(){ chatfocus = false; }
}
Edit: Didn't realize you're also referencing chatarea in updateChat, define this outside onload's scope as null but only use getElementById after the page has loaded.

i apparently cannot have a onfocus or onblur event on a div area?
after trying every possible way to get those events to work and change a value i didnt quite know how to set as a global without guessing until success, i made a input button to enable/disable my auto updateChat function and set the value in my hidden html form.
also i found useful websites like jshint.com to diagnose possible errors. sorry for being unaware

Related

Tampermonkey: Trigger event does not work for element

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");
}

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();
}
}
})

Convert contenteditable div's content to plaintext via javascript

I'm trying to make custom lightweight rich text editor with just one feature - adding links. I did some research and desided iframe is the best choice. After some messing around it works with one exception - I need to run some code on keyup event. I read everything I found on the internet and nothing helped, still doesn't work...
iframe.document.designMode = 'On';
iframe.document.open();
iframe.document.write(someHTML);
iframe.document.close();
var keyupHandle = function() { /* some code */ };
var iframeDoc = document.getElementById('iframe').contentWindow.document;
if(iframeDoc.addEventListener) {
iframeDoc.addEventListener('keyup', keyupHandle(), true);
} else {
iframeDoc.attachEvent('onkeyup', keyupHandle());
}
I think I remember needing to wait for the iframe to fully load before adding event handlers to the document. If possible, add something to the iframe's HTML to call out to the parent page when it's loaded:
window.iframeLoaded = function() {
var iframeDoc = document.getElementById('iframe').contentWindow.document;
if(iframeDoc.addEventListener) {
iframeDoc.addEventListener('keyup', keyupHandle(), true);
} else {
iframeDoc.attachEvent('onkeyup', keyupHandle());
}
};
iframe.document.designMode = 'on';
iframe.document.open();
iframe.document.write('<html><body onload="parent.iframeLoaded()">Stuff</body></html>');
iframe.document.close();
Failing that, setting a brief timer using window.setTimeout() will probably work.

userscript: I lost some JS?

I do not understand what's going on...
I have a simple userscript, that add couple DIVs, css styles and JS functions in the pages I visit
In particular, I have one DIV that trigger a JS function with a onClick listener - this function is a "toggle" function (display/hide an other DIV):
function togglegm(etat) {
if (etat = 'on') {
document.getElementById('greasemky').style.display = 'block';
document.getElementById('greasemkytoggle').innerHTML = '';
} else if (etat = 'off') {
document.getElementById('greasemky').style.display = 'none';
document.getElementById('greasemkytoggle').innerHTML = '';
}
}
var script2 = d.createElement('script');
script2.appendChild(d.createTextNode(togglegm));
(d.body || d.head || d.documentElement).appendChild(script2);
The DIV "greasemkytoggle" only contains a link with a onClick that trigger "togglegm('on'), and my objective is that when togglegm(on) is executed, the innerHTML of this DIV becomes a trigger for togglegm(off).
Now the weird part... when I click on my DIV greasemkytoggle, the function togglegm(on) is perfectly executed (greasemky is displayed), and the innerHTML is perfectly changed with a link for "togglegm(off)", BUT if I click again, then nothing happens.
I looked at the source code, and discovered that my JS function just disappeared (that's why nothing happened on the last click)! Now, there is an empty function replacing my togglegm():
<script>
scriptHolderArray1
</script>
Do you understand that kind of behaviour...?
I found nothing online for that kind of situation...
GreaseMonkey runs under a much more security conscience set of rules.
Attach the event listeners using the proper DOM3 (addEventListener) method.
It is never a good idea (in user scripts or general scripting) to assign Javascript through innerHTML.
It is never a good idea to use the "javascript:" pseudo-protocol.
The problems are etat = 'on' and etat = 'off'.
If you want to set values, use
etat = 'on'
etat = 'off'
If you want to compare, use:
etat == 'on'
etat == 'off'
Moreover, href="javascript:return(false);" throws an error on Firefox because there is a return outside a function (SyntaxError: return not in function). You should do href="javascript:void(0);", or return false at the end of the onclick event.
Anyway, I don't understand very well what you are doing here:
var script2 = d.createElement('script');
script2.appendChild(d.createTextNode(togglegm));
(d.body || d.head || d.documentElement).appendChild(script2);
You have a function togglegm loaded to browser's memory by a <script> element.
Then, you create a new <script> with that function and append it to the document, in order to load it to browser's memory again (I guess).
Why?

Javascript: How to temporarily disable all actions on the page?

On a page with Ajax event, I want to disable all actions until the Ajax call returns (to prevent issues with double-submit etc.)
I tried this by prepending return false; to the current onclick events when "locking" the page, and removing this later on when "unlocking" the page. However, the actions are not active any more after they are "unlocked" -- you just can't trigger them.
Why is this not working? See example page below. Any other idea to achieve my goal?
Example code:
both the link and the button are showing a JS alert; when pressing lock, then unlock the event handler is the same as it was before, but doesn't work...?!?
The code is meant to work with Trinidad in the end, but should work outside as well.
<html><head><title>Test</title>
<script type="text/javascript">
function lockPage()
{
document.body.style.cursor = 'wait';
lockElements(document.getElementsByTagName("a"));
lockElements(document.getElementsByTagName("input"));
if (typeof TrPage != "undefined")
{
TrPage.getInstance().getRequestQueue().addStateChangeListener(unlockPage);
}
}
function lockElements(el)
{
for (var i=0; i<el.length; i++)
{
el[i].style.cursor = 'wait';
if (el[i].onclick)
{
var newEvent = 'return false;' + el[i].onclick;
alert(el[i].onclick + "\n\nlock -->\n\n" + newEvent);
el[i].onclick = newEvent;
}
}
}
function unlockPage(state)
{
if (typeof TrRequestQueue == "undefined" || state == TrRequestQueue.STATE_READY)
{
//alert("unlocking for state: " + state);
document.body.style.cursor = 'auto';
unlockElements(document.getElementsByTagName("a"));
unlockElements(document.getElementsByTagName("input"));
}
}
function unlockElements(el)
{
for (var i=0; i<el.length; i++)
{
el[i].style.cursor = 'auto';
if (el[i].onclick && el[i].onclick.search(/^return false;/)==0)
{
var newEvent = el[i].onclick.substring(13);
alert(el[i].onclick + "\n\nunlock -->\n\n" + newEvent);
el[i].onclick = newEvent;
}
}
}
</script>
<style type="text/css">
</style>
</head>
<body>
<h1>Page lock/unlock test</h1>
<p>Use these actions to lock or unlock active elements on the page:
lock,
unlock.</p>
<p>And now some elements:</p>
<a onclick="alert('This is the action!');return false;" href="#">link action</a>
<input type="button" value="button action" onclick="alert('This is another action!')"/>
</body>
</html>
Thanks guys for your ideas and answers.
Now I see that I have mixed up Strings and functions, which obviously can't work ;(
I should have made clear that we use some Web FW and tag libraries (Trinidad) which create the event handling (and Ajax) code, hence I can't edit that directly or use synchronous Ajax etc.
Moreover, Ajax is only one scenario where this code should be executed. It's purpose is to prevent the user to double-submit a page/action, which is also relevant for non-Ajax pages where you could kind of doulbe-click on a button. I know that this is not really safe, and it's only meant to be a "convenience" thingy to avoid getting the navigation error page too often (we have server-side protection, of course).
So, will try the div overlay, probably.
Thanks again,
Christoph.
How about setting up a global var
actions_disabled = 0
increment when the AJAX call starts then decrement when it finishes. All your "action" handlers can then start with
if (actions_disabled) return false;
Much simpler than debugging self-modifying code!
Alternatively, to lock your controls you could set:
control.disabled="disabled"
which will have the bonus of greying them out, making it obvious to the user that they can't submit. To unlock, simply set:
control.disabled=""
NEW IDEA BASED ON COMMENTS (can't quote code in comments, it appears ...):
You can always just hang extra attributes off Javascript objects:
To lock, you could:
control.onclick_old = control.onclick
control.onclick = "return false;"
To unlock, you could:
control.onclick = control.onclick_old
I once achieved this goal by creating a DIV that covered the area I wanted disabled, setting its z-index higher than any of the other elements on the page, and then setting its opacity to 0. By default, this DIV was hidden by display: none, so that it wouldn't interfere with anything. However, when I wanted the area disabled, I just set its display to block.
Steve
AJAX. Asynchronous. Just make the HTTP request synchronous. Problem solved.
The problem with your code is a result of not coming to grips with types in javascript.
When you say:
var newEvent = 'return false;' + el[i].onclick
what this does is coerce el[i].onclick (which is a function) to a string, then concatenates it to the string 'return false;'. Then when you reassign it as so:
el[i].onclick = newEvent;
onclick which was previously a function is now a string.
Then you attempt to resurrect your old function from the string by taking a substring:
var newEvent = el[i].onclick.substring(13);
which is fine, except newEvent is still a string! So when you assign it back to onclick again, you are assigning the string representation of the original function, not the function itself.
You could use eval to evaluate the string and return the function, but please don't do that. There are a number of better ways to do this, as has been suggested by other commenters.
I would also question why you wish to use AJAX at all if you don't want to allow asynchronous requests.
Put lockPage() at top of activete() function, and unlockPage() at bottom of deactivate().
activate: function() {
function lockPage()
{
lockElements(document.getElementsByTagName("a"));
lockElements(document.getElementsByTagName("input"));
lockElements(document.getElementsByTagName("button"));
};
function lockElements(el)
{
for (var i=0; i<el.length; i++)
{
el[i].style.pointerEvents="none";
}
};
lockPage();
// ...
},
deactivate: function() {
// ...
function unlockPage() {
unlockElements(document.getElementsByTagName("a"));
unlockElements(document.getElementsByTagName("input"));
unlockElements(document.getElementsByTagName("button"));
};
function unlockElements(el)
{
for (var i=0; i<el.length; i++)
{
el[i].style.pointerEvents="auto";
}
};
unlockPage();
},
Using a div overlay does not prevent a user from tab-ing into your page. Usually that is OK, since most users do not tab through a page anyhow.
If you use any keyboard shortcuts on your page, they will still be available, so separate handling will be needed for those.
Alse, I assume that clicking an element that can have focus (eg. an <a> tag), then pressing enter, would still cause a double submit.

Categories