JavaScript Loop doesn't exit - javascript

I've tried everything I can think of.
I'm building a sort of chat bot for IMVU, using injected JavaScript on the IMVU mobile website. I have a loop to crawl the messages received, and search for certain key terms, like a message beginning with a slash (/) to indicate a command to the bot.
When certain commands are used, I have a problem that the bot seems to get stuck in the loop, almost as if the index of the for loop is being modified inside the loop. The code is included below.
If you need more, ask, and if you find something that might be causing the problem, please let me know. I'm at my wit's end.
Just for a note: jQuery is properly injected, all my variables are there, no errors in the debug console, and running under Chrome 41.0.2272.101m on Windows 7 x64.
function verifyCommand() {
if (document.getElementsByClassName("message-list-item").length > last_cmd_count && !processing_commands) {
var new_length = $('.message-list .message-list-item').length;
console.log("Begin processing commands... ** SYSTEM LOCK **");
console.log(new_length);
for (var i = last_cmd_count; i < (new_length); i++) {
processing_commands = true;
try {
var callinguser = $('.message-list .message-list-item .header .username .username-text')[i].innerText.replace("Guest_", "");
var messagetext = $('.message-list .message-list-item .message .message-text')[i].innerText
if (callinguser != "USERNAME REMOVED") {
if (messagetext.substr(0, 1) == "/") {
if (strContains(callinguser, "IMVU User")) {
die();
}
processCommand(messagetext.substr(1), callinguser);
} else {
if (messagetext.toLowerCase().indexOf('roomgreet') > -1 || messagetext.toLowerCase().indexOf('room greet') > -1) {
if (detectFlirt()) {
sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
if (!isAdmin(callinguser)) {
logIdiot(callinguser);
}
} else if (strContains(messagetext, 'what is ')) {
sendMsgRaw('Please use /solve or /advsolve for math.');
} else {
if (callinguser != "USERNAME REMOVED") {
ident();
}
}
}
if (strContains(messagetext, 'free') && strContains(messagetext, 'credits') && strContains(messagetext, 'http://')) {
sendMsgFrom("*** SCAM ALERT ***", callinguser);
}
}
}
} catch (ex) {} finally {}
}
processing_commands = false;
last_cmd_count = new_length;
console.log("Finish processing commands... ** SYSTEM FREE **");
if (monitoring) {
verifyUserMessageCount();
}
}
}
HTML of the IMVU Mobile messages can be found at http://common.snftech.tk/imvu/roomgreet-html-sample.htm

Try changing your function to use each() to loop through each element instead of the loop you have. Once an element has been processed, add a "processed" class to the element so we dont look at them again later. This should be more stable than forcing our logic to keep up with what ones have been processed already.
Here is a jsFiddle,, throw in the html from your page that actually causes the problem and see if it still occurs
function verifyCommand() {
//fixed some logic in here
if ($(".message-list-item").length > last_cmd_count && !processing_commands) {
processing_commands = true; // you should set this immediately
var new_length = $('.message-list-item').length;
console.log("Begin processing commands... ** SYSTEM LOCK **");
console.log('Last command count: '+ last_cmd_count +', New Length: '+new_length);
var newMessages = $('.message-list-item:not(.processed)'); // get all of the message elements that do not have the class "processed"
// loop through each of the message elements
newMessages.each(function(index, element){
console.log('Processing new element at index '+index );
try {
var callinguser = $(this).find('.username-text').text().replace("Guest_", "");
var messagetext = $(this).find('.message-text').text();
$(this).addClass('processed'); // add processed class to the element so we know not to process it again later
if (callinguser != "RoomGreet") {
if (messagetext.match(/^\//)) {
if (callinguser.match(/IMVU User/)) {
die();
}
processCommand(messagetext.substr(1), callinguser);
}
else {
if (detectFlirt(messagetext)) {
if (!isAdmin(callinguser)) {
sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
logIdiot(callinguser);
}
}
else if (messagetext.match('what is ')) {
sendMsgRaw('Please use /solve or /advsolve for math.');
}
else {
if (callinguser != "Nezzle" && !isAdmin(callinguser)) {
ident();
}
}
if (strContains(messagetext,"imvu") && strContains(messagetext,"credits") && strContains(messagetext,"http://")) {
sendMsgFrom("*** SCAM ALERT ***", callinguser);
}
}
}
}
catch (ex) {
console.log('caught error');
}
finally {
}
});
last_cmd_count = new_length;
console.log("Finish processing commands... ** SYSTEM FREE **");
processing_commands = false;
if (monitoring) {
verifyUserMessageCount();
}
}
}

I think your problem is this
if (messagetext.substr(0,1) == "/") {
if the user has a space in front of the "/" then it will not interpret as a command so you need to process
var messagetext = $('.message-list .message-list-item .message .message-text')[i].innerText
remove all white space from message text like this
messagetext.text().replace(" ", "");
you should also have more error catching in
if (messagetext.substr(0,1) == "/") {

Related

Office.js outlook add-in issue

I'm trying to get the Body in Outlook and then update/set it with categories. My issue is this - when I debug it - it works fine. But when I don't debug from function to function - it gets all the way to the last function and just stops - updateBody(). What's really strang is if I remove the breakpoints on each function and just set a breakpoint on last function - never gets hit, but console will write out "Starting update body". All the console.logs are writing out data as expected. Not sure what is going on. Appreciate any help! Thanks.
"use strict";
var item;
var response;
var tags;
var updatedBody;
Office.initialize = function () {
$(document).ready(function () {
// The document is ready
item = Office.context.mailbox.item;
debugger;
getBodyType();
});
}
function getBodyType() {
item.body.getTypeAsync(
function (resultBody) {
if (resultBody.status == Office.AsyncResultStatus.Failed) {
write(resultBody.error.message);
} else {
response = resultBody;
console.log('Successfully got BodyType');
console.log(response.value);
getCategories();
}
});
}
function getCategories() {
tags = "";
// Successfully got the type of item body.
// Set data of the appropriate type in body.
item.categories.getAsync(function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log("Action failed with error: " + asyncResult.error.message);
} else {
var categories = asyncResult.value;
console.log("Categories:");
categories.forEach(function (item) {
var tag = item.displayName;
tags += '#' + tag.replace(/\s/g, "") + ' ';
});
console.log('Successfully got tags');
console.log(tags);
getBody();
}
});
}
function getBody() {
var body = "";
updatedBody = "";
console.log("Starting get body");
if (response.value == Office.MailboxEnums.BodyType.Html) {
item.body.getAsync(
Office.CoercionType.Html,
{ asyncContext: "This is passed to the callback" },
function (result) {
//Replace all the # tags and update again.
body = result.value.replaceAll(/#(\w)+/g, "").trimEnd();
var domParser = new DOMParser();
var parsedHtml = domParser.parseFromString(body, "text/html");
$("body", parsedHtml).append("<div>" + tags + "</div>");
var changedString = (new XMLSerializer()).serializeToString(parsedHtml);
if (changedString != "") {
updatedBody = changedString;
}
console.log(updatedBody);
updateBody();
});
}
}
function updateBody() {
console.log("Starting update body");
item.body.setAsync(
updatedBody,
{ coercionType: Office.CoercionType.Html },
function (result2) {
console.log("Body updated");
});
}
Image - With breakpoints on each function - works as expected
Image - Without breakpoints - gets to updateBody() function.
But the string updatedBody isn't logged. It somehow skips over that
even though it's called before updateBody() on getBody()
Image - Same code run via Script Lab - works just fine as well.

How to append "user is typing to label", and removing after 5 sec

I'm trying to build a chat program. I have read several guides (such as: http://www.tamas.io/further-additions-to-the-node-jssocket-io-chat-app/),
however I still can't get it to work.
When someone is typing, the "is typing" is not added to the other user's label.
I really hope someone can point out where I have gone wrong.
Thanks,
Here's my code.
client-side:
// Detect typing
var typing = false;
var timeout = undefined;
function timeoutFunction() {
typing = false;
socket.emit("typing", false);
socket.emit("notTyping", true)
}
$("#msg").keypress(function(e){
if (e.which !== 13) {
if (typing === false && $("#msg").is(":focus")) {
notTyping = false;
typing = true;
socket.emit("typing", true);
} else {
clearTimeout(timeout);
timeout = setTimeout(timeoutFunction, 5000);
}
}
});
client.on("isTyping", function(msg) {
$typingActivity.append('<div>' + msg + '</div>');
timeout = setTimeout(timeoutFunction, 5000);
});
server-side:
client.on("typing", function(data) {
console.log("Typing...");
client.broadcast.emit("isTyping", people[client.id] + " is typing...");
});

Object doesn't support property or method 'stop' IE

When i click on submit button. I got an error like "Object doesn't support property or method stop " in Internet Explorer but data is successfully added in database.
Here is my code.
function SaveComment(subCommentId, trShowresponseId, tdShowresponseId, startDate, endDate) {
// alert("");
debugger;
try {
var response = document.getElementById("TextBoxResponse~" + subCommentId).value;
if (response === "") {
alert("Please Enter Response.");
return false;
}
else {
// var isAdvanceComment = 1;
$("#showloading").show();
var commentType = 'A';
var returnReult = dashboards_DiscreteRating.SaveComment(response, subCommentId, commentType, startDate, endDate, 0).value;
if (returnReult.match("Error")) {
document.getElementById("spanErrorMessage").innerHTML = returnResponse;
}
else {
document.getElementById(tdShowresponseId).innerHTML = returnReult;
}
// document.getElementById(tdShowresponseId).innerHTML = dashboards_DiscreteRating.SaveComment(response, subCommentId, commentType, 0).value;
document.getElementById("trHiddenTextBox~" + subCommentId).className = "hide";
document.getElementById("trAddSpan~" + subCommentId).className = "show";
document.getElementById("TextBoxResponse~" + subCommentId).value = "";
document.getElementById(trShowresponseId).className = "show";
$("#showloading").hide();
window.stop();
}
}
catch (ex) {
alert(ex.description);
}}
Instead of using window.stop(), return false or call preventDefault on the event object in the form’s submit listener – likely wherever you call SaveComment. Something along the lines of:
commentForm.addEventListener('submit', function (e) {
// …
SaveComment(…);
e.preventDefault();
});
The alert here suggests you might already be passing the return value straight through:
alert("Please Enter Response.");
return false;
in which case you should be able to do it here too:
$("#showloading").hide();
return false;
See https://developer.mozilla.org/en-US/docs/Web/API/Window/stop
The stop() method is not supported by Internet Explorer.
Also: I don't know what you are trying to achieve by calling stop().
However: you call window.stop(); as the last line in your file. Since you don't rollback in your catch-block or anything, everything before that call (e.g. writing to database) gets executed and not rolled back
Finally i solved this error by using this .
function SaveComment(subCommentId, trShowresponseId, tdShowresponseId, startDate, endDate) {
// alert("");
debugger;
try {
var response = document.getElementById("TextBoxResponse~" + subCommentId).value;
if (response === "") {
alert("Please Enter Response.");
return false;
}
else {
// var isAdvanceComment = 1;
$("#showloading").show();
var commentType = 'A';
var returnReult = dashboards_DiscreteRating.SaveComment(response, subCommentId, commentType, startDate, endDate, 0).value;
if (returnReult.match("Error")) {
document.getElementById("spanErrorMessage").innerHTML = returnResponse;
}
else {
document.getElementById(tdShowresponseId).innerHTML = returnReult;
}
// document.getElementById(tdShowresponseId).innerHTML = dashboards_DiscreteRating.SaveComment(response, subCommentId, commentType, 0).value;
document.getElementById("trHiddenTextBox~" + subCommentId).className = "hide";
document.getElementById("trAddSpan~" + subCommentId).className = "show";
document.getElementById("TextBoxResponse~" + subCommentId).value = "";
document.getElementById(trShowresponseId).className = "show";
$("#showloading").hide();
if ($.browser.msie) { //************** Here is the answer ************
document.execCommand('Stop'); //************** Here is the answer ***********
}
else {
window.stop();
}
}
}
catch (ex) {
alert(ex.description);
}}
Internet Explorer does not support window.stop() so we can use document.execCommand("Stop") for IE.

Memory Game - how to get both card images to display before the alert pops

I have written code for a memory game in JavaScript. My problem is that I can't figure out why both cards selected don't show before the alert (saying that hooray they are the same/or no they don't match) pops up. I am confused because the alert is in the isMatch function which is run after both cards are clicked (isTwoCards function).
var isTwoCards = function(){
if (this.getAttribute('data-card') === 'king') {
this.innerHTML = '<img src="King.png" class = "myImgClass" alt="King"/>';
} else {
this.innerHTML = '<img src="Queen.png" class = "myImgClass" alt="Queen" />';
}
cardsInPlay.push(this.getAttribute('data-card'));
if (cardsInPlay.length === 2) {
isMatch(cardsInPlay);
}
};
var isMatch = function() {
if (cardsInPlay[0] !== cardsInPlay[1]) {
alert('Sorry, try again.');
cardElement.className = "";
} else {
alert('You found a match!')
};
cardsInPlay = [];
}
Here is the entire code: http://codepen.io/Lupeman/pen/GNgXrm
Any help would be greatly appreciated because it's driving me nuts! I'd like to do it without JQuery.
You would want to delay the isMatch checking until the UI finish updating and the user already done mouse up.
if (cardsInPlay.length === 2) {
setTimeout(function() {
isMatch(cardsInPlay);
}, 1000);
}

xhr.status and xhr.readyState is 0

I'm working with HTML5 multiple file uploader. For some purpose I'm queuing the requests into a JavaScript array and I'm trying with two approaches here, one is, sending all the requests by a loop using a for loop and the next approach is like starting the next request after the previous request got finished. Here is the code,
function processUploads(i)
{
if(typeof(i)=="undefined")
return;
if(i==0)
{
for(i=0;i<4;i++)
{
xhrQ[i].open("POST",FUurl,true);
xhrQ[i].send(fdQ[i]);
xhrQ[i].onreadystatechange = function() {
if (xhrQ[i].readyState == 4 && xhrQ[i].status == 200) {
uploadComplete(xhrQ[i],i);
}
}
}
}
else
{
xhrQ[i].open("POST",FUurl,true);
xhrQ[i].send(fdQ[i]);
xhrQ[i].onreadystatechange = function() {
if (xhrQ[i].readyState == 4 && xhrQ[i].status == 200) {
uploadComplete(xhrQ[i],i);
}
}
}
}
function uploadComplete(xhr,i)
{
//processUploads(i+1);
var responseJSON = eval('(' + xhr.responseText + ')');
var upldrID = responseJSON.data.queueId;
var fileProgElem = $("#file_content").find("div[file-count="+upldrID+"]");
fileProgElem.attr("upload","finished");
fileProgElem.find("input[id=asset_id]").val(responseJSON.data.asset_id);
if(typeof(responseJSON)=="undefined") {
return;
}
$("#bar"+upldrID).css("width: 100%");
$("#progress_text"+upldrID).addClass("hide");
$("#progress_bar"+upldrID).html("Upload Complete!");
var pagename = $("#pagename").attr('value');
var cover_art = "<img src='"+responseJSON.data.thumb_location+"' alt='"+$.trim($("#file_name"+upldrID).html())+"' />";
$("#cover_art"+upldrID).html(cover_art);
//Hide the cross icon and enable the save
var action_divs = '<div id="done'+upldrID+'" class="hide enable">'
+'<a id="delete_file_'+upldrID+'" onclick="saveWorkspaceFileDetails(\''+responseJSON.data.project_id+'\',\''+responseJSON.data.asset_id+'\',\''+upldrID+'\',\''+responseJSON.data.file_name+'\',\''+responseJSON.data.size+'\',\'delete\',\''+pagename+'\')">'
+'<i class="tl-icon-20-close-gray"></i>'
+'</a>'
+'</div>';
$("#cancel_upload"+upldrID).append(action_divs);
$("#progress_cancel"+upldrID).addClass("hide").removeClass("show");
$("#done"+upldrID).addClass("show").removeClass("hide");
//To show the post and cancel button
$("#submitFileUpload").removeClass("hide").addClass("show");
//Updating the title with the default value of file_name
var file_title = $.trim($("#file[file-count='"+upldrID+"']").find("#file_title").val());
if (file_title == "" && file_title != undefined){
$("#file[file-count='"+upldrID+"']").find("#file_title").val(responseJSON.data.file_name);
}
//For other category we need to enable the dropdown
if(responseJSON.data.category_id=='999')
{
$("#select_category"+upldrID).removeClass("hide").addClass("show");
}
//totSelFiles is a number of selected files that i sets as a global variable
if(i<(totSelFiles-1))
{
processUploads(i+1);
}
else
return;
}
But the problem is i'm getting the readyState and status as 0 in the if loop. But the file is getting uploaded to the server and the else condition is also working well if i only enable that block. So what could be the problem. I'm greatly confused. Any help would be greatly appreciate.
The problem is related to the closure you create with the anonymous function you use for onreadystatechange. It will have access to the value of i, but not from the time of creation of the closure but rather from the time of its execution. At that point of time i is always 4 and xhrQ[i] will not refer to the correct object. Use this instead
xhrQ[i].onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
}
}
The problem is that you want to continue with the index i inside the uploadComplete() function. For this you might need to create another inner closure with an immediately executing function that will create a local copy of the current index.
xhrQ[i].onreadystatechange = (function(_innerI) {
var that = this;
return function() {
if(that.readyState == 4 && that.status == 200) {
uploadComplete(that, _innerI);
}
}
})(i);

Categories