JavaScript For loop inusual behaviour - javascript

I have a jsp file with html content, and a script inside and I am also using dhtmlx. The other parts of my Web Application are working, so with this, I want only to focus on this problem because the environment works well. In one point of the file I have got:
numTabs = getNumTabs();
for (var i=0; i<numTabs;i++) {
var mytab = "tab_"+i;
tabbar.addTab(mytab,'Tab Numer: ' + i,'');
//alert("for " + i); PLACE 1
initTabContent(mytab);
}
function initTabContent(tabID){
//alert("initTabContent " + i); PLACE 2
tab = tabbar.cells(tabID);
toolbar = tab.attachToolbar();
toolbar.loadXML('.../...file.xml',function(){
//alert(i); PLACE 3
toolbar.setItemText('botton1', 'Botton 1');
});
grid = tab.attachGrid();
//more stuff
}
The point is:
If I uncomment the alert in PLACE 1, everything goes pretty well, it loads the XML and everything is working but if I comment the alert it doesn't go well.
If I uncomment alert 1 and alert 2, I will see in the web page:
I see: "for 0" -> OK
I see: "for 1" that changes almost immediately to "initTabContent 0" -> OK but I can see it
I see: "for 1" -> OK
I see: "for 2" that changes almost immediately to "initTabContent 1" -> OK
I see: "for 2" -> OK
I see: "for 3" that changes almost immediately to "initTabContent 2" -> OK
....and on
So, I understand that despite of myfunction the loop goes on and doesn't wait the complete termination of that function.
The funny part is that if I comment alert 1 and 2, and uncomment alert 3, the first thing I see on the web page is 4, then 3, 2, 1, 0...
And if I leave again, only alert 1 uncommented, everything goes ok. The reason about that I suppose is that the alert makes the system wait to the user and therefore the XML is well loaded.
My questions:
First: Why the loop is not waiting for the function to finish? It should be sequential right?
Second: How can I solve it without the alert? I also tried to put an empty for loop inside to make time but it didn't work out...(and that is not a good way to do it)
Thank you very much,
Alex.

Part of what is causing you trouble is that an 'alert' blocks execution, while the loadXML call is asynchronous.
To get a more accurate depiction of what is happening in what order, use console.log instead of alert.
Are you trying to use the value of i in your call myFunction for some purpose other than alerts ?
If that is the case. Try replacing:
myfunction(i);
With:
(function (num) { return function() {myfunction(num)} })(i);

Thanks to #KevinB I realized that indeed the toolbar declaration was missing in the whole jsp file.
The toolbar = tab.attachToolbar(); is overriden before the loading of the XML.
Now with **var** toolbar = tab.attachToolbar(); the problem is solved.
To see the reason that the loop doesn't behave properly, you can read the comments under the question.

Related

Calling javascript functions in windbg breakpoint-commands

I have a windbg-issue concerning the execution
of a javascript-function as a breakpoint-command.
This observation was made in windbg Preview 10.0.17030.1002
and also in recent versions of windbg
when debugging a native x86 C++ program on Windows 10.
Test Setup
In my javascript-file dbg_test.js I have the following function:
function test()
{
var ctl = host.namespace.Debugger.Utility.Control;
host.diagnostics.debugLog(">>> Test\n");
ctl.ExecuteCommand("g");
}
In windbg, I load the javascript-provider, load my dbg_test.js script
and define a breakpoint-command to call this javascript-function:
bs 0 "dx #$scriptContents.test()"
Expected Behavior
The string ">>> Test" is shown in the output-pane of the command-window
everytime when breakpoint 0 is hit.
The debugger resumes execution.
Observed Behavior
The output ">>> Test" is shown only the first time
when breakpoint 0 is hit.
Subsequently hitting breakpoint 0 does not
produce any output.
Remarks
1) Doing the analogous test with "old style" windbg-commands works fine:
bs 0 ".printf \">>> Test\\n\\n\";g;"
but only after ending and restarting windbg
2) The same behavior is shown when I move the code of function "test" to the function "invokeScript()" and define the breakpoint-command via
bs 0 ".scriptrun d:\\dbg_scripts\\dbg_test.js"
3) Running the script from the windbg-command-line works.
4) Calling javascript-functions as in the test-scenario above worked in previous versions of windbg.
5) It seems that the statement
ctl.ExecuteCommand("g");
is the crucial one: If I comment out this statement, then the breakpoint
is hit every time and the output from
host.diagnostics.debugLog(">>> Test\n");
is shown on each hit of the breakpoint.
Of course, I have to resume the execution manually by pressing F5 or entering the command "g"
Questions
Can someone reproduce this issue ?
Is it legal to use javascript-functions in this way or am I doing something wrong here ?
Your feedback is greatly appreciated!
Kind/Best regards!
I ran into the same problem as you did. I was able to somewhat bypass the problem by declaring a script global variable
var lines = [];
and pushing log messages to this array rather than debug printing them:
lines.push(">>> Test");
In order to see the lines, I created a function
function print_lines() {
for (var line of lines) {
host.diagnostics.debugLog(line + "\n");
}
lines = [];
}
which I called from the prompt like so
dx #$scriptContents.print_lines();
I know that this is not really answering your question, but it might still be helpful for someone else that faces the same problem.

Mocha/Chai - Test to click an element only if it's present, displayed or exists

I've just start looking at implementing tests with Selenium using a Mocha/Chai framework & am struggling with a login function. I want to check an item is present/displayed & to click it if it is.
Currently my test waits on the page loading & I want something like the following, which currently doesn't work:
var elementOnPage = driver.findElement(By.('elementId')).isDisplayed();
//var elementOnPage = driver.findElement(By.('elementId')).exist;
if(elementOnPage == true){
driver.findElement(By.('elementId')).click();
}
else{
driver.findElement(By.('anotherElement')).click();
}
I've also tried the commented out line above but neither seems to work. The code always seems to hit the 2nd part of the if statement before continuing. If the element I'm checking for is present then the test executes the next line but if it's not present then the test fails with a "NoSuchElementError: No such element".
I also didn't realise I could use stuff like exists(), isPresent() or isElementPresent() either.
Does anyone have any ideas or point me in the right direction? I'm quite new to this.
Cheers
The return value of isDisplayed is a promise, but you treat it as a boolean.
You need to do something like:
driver.findElement(By.id('elementId')).isDisplayed().then(function (displayed) {
if (displayed) {
driver.findElement(By.id('elementId')).click();
}
else{
driver.findElement(By.id('anotherElement')).click();
}
});
Or more concisely:
driver.findElement(By.id('elementId')).isDisplayed().then(function (displayed) {
driver.findElement(By.id(displayed ? 'elementId' : 'anotherElement')).click();
});
By the way By.('elementId') cannot work. I've assumed you meant By.id('elementId').

Disqus's count.js script doesn't run properly in index.html with react.js website

I've been having a hell of a time getting the comment count script to work on my react pages. To start, they recommend putting the script in my index.html file, at the bottom of the <body> tag. I've done this, and seen no result.
<body>
<div id="app">
</div>
<script src="static/index.js"></script>
<script id="dsq-count-scr" src="//mtg-hunter.disqus.com/count.js" async></script>
</body>
I have an index.js file which is loading all my components, including the component (let's call it ResultComponent.js) which I want to have the comment count <span> tags in. The <span> tags themselves look like this:
var commentCount = <span className="disqus-comment-count" onClick={function() {this.setState({currentSelectedTab: 4})}.bind(this)}
data-disqus-identifier={idGoesHere}
style={{fontVariant:"small-caps"}}>0 Comments</span>
So far, so simple. I'm not using any <a> tags so I haven't got #disqus_thread anywhere. When I load my page, I expect my comment count to go up, but no such luck. To test this, I copied the raw script, unaltered, from the raw count.js script (which is located here). I then pasted it straight into Chrome's devtools console, and it worked; all the relevant comment counters went to their appropriate values.
EDIT: a day later, more prodding; I added breakpoints in the actual code in the disqus.com domain. The script in the script tag is running just fine at the right time, except it's missing variables when it enters the displayCount() function. There's several variables that just aren't given values so it can't go in and populate the comment counts, it always fails out. I have no idea why this fails when it's called from within my index.html but not when I paste the raw count.js code into my console and do it there. No idea why.
To clarify, this is the relevant code:
e.displayCount = function(b) {
for (var c, a, d, e = b.counts, b = b.text.comments; c = e.shift(); )
if (a = j[c.id]) {
switch (c.comments) {
case 0:
d = b.zero;
break;
case 1:
d = b.one;
break;
default:
d = b.multiple
}
c = d.replace("{num}", c.comments);
a = a.elements;
for (d = a.length - 1; d >= 0; d--)
a[d].innerHTML = c
}
}
;
When it runs properly, from my pasting the script into the console, the j variable is defined. When it runs called from index.html, j is undefined, so it fails at the first if. The calling url is exactly the same in both situations: http://mtg-hunter.disqus.com/count-data.js?1=19767&1=235597&1=373322&1=382310&1=382841&1=382866&1=383023&1=397543&1=397682&1=398434. That gives the b parameter, and when I run the script locally it defines j so that the assignment operator in the if can work (which is a really weird way of doing it, but ok).
edit again: I should point out I'm doing this on a local test server (localhost:3000), not sure if that makes a difference or not?
edit more: The answer to my above question turns out to be 'no'. I uploaded my code to my server and the production site also showed that the script wasn't running properly. This is absurd... I'm out of ideas by now.
edit again more: Partial breakthrough... I added this code to ResultComponent.js:
componentDidMount() {
DISQUSWIDGETS.getCount();
},
componentDidUpdate() {
DISQUSWIDGETS.getCount();
},
Good news; when I refresh the page, it shows the right comment count! Hooray! Bad news: when I change parts of the page that hide the Result component, and then bring it back (triggering componentDidUpdate), the DISQUSWIDGETS.getCount() call doesn't work. It still gets called, but the displayCount part of the script never does, so the DOM is never updated with the new information. It's yet another example of this horrid script behaving differently despite being called in exactly the same way...
OK, after much back and forth with the support guy at Disqus I finally found an answer; I was close. The solution is:
componentDidMount() {
DISQUSWIDGETS.getCount({reset:true});
},
componentDidUpdate() {
DISQUSWIDGETS.getCount({reset:true});
},
Turns out I had to pass the reset:true param, which enabled a chunk of code in getCount to actually do something. I suppose I could've figured that out from the code, but I blame the intensely minified formatting (even with chrome dev tools helping to prettify it) for me missing that. It was also in their knowledge base article for how to add comment counters, but I missed the context of it (and got absorbed by the 'fact' that 'it obviously had to be the script not working, clearly').
And so ends one of my most frustrating few days of coding. And a useful lesson... step back and look at the big picture every now and again, because the answer can be staring you in the face.

Adjust Node REPL to not clobber prompt on async callback?

When working with the Node REPL console, I'm looking for a way for asynchronous calls to both not lock up the console input, and not clobber the console prompt when they return.
I've seen a few solutions dealing with asynchronous calls in the REPL, where writing your own custom eval function you can check the result of the executed code to see if it's a promise/async object, and just not return until it resolves.
However, I'd like to solve the issue of a repeating background process logging its progress. Ideally I'd like it to behave like the Chrome Javascript console, where if you have a command partially printed on the console prompt, and an async result gets logged, the line you're typing on gets moved one line down, and the log inserted above it.
So, functionally, I'd like to insert the logic that when console.log() is called, the line containing the cursor is first cleared, then the contents of the log() written, and then the REPL prompt (and whatever the user had typed so far onto it) gets re-written on the line following the new output.
Is there any way to hook into the REPL object to accomplish this? Is this some advanced manipulation of the output stream from the REPL (i.e. only possible on terminals that support an "erase to beginning of line" escape code)?
Tapping straight into the Output Stream I managed to get something working like how I wanted:
var server = repl.start({
prompt: '> '
});
server.context.console.log = function(msg) {
var rli = server.rli;
server.outputStream.write('\033[2K\033[1G'); // Erase to beginning of line, and reposition cursor at beginning of line
server.outputStream.write(msg+"\n");
server.outputStream.write(''+rli._prompt+rli.line); // Redraw existing line
server.outputStream.write('\033['+(rli.cursor+rli._promptLength+1)+'G'); // Move the cursor to where it was
}
server.context.doTimeout = function() {
setTimeout(function() {
server.context.console.log('Timeout done!');
}, 2000);
};
Though that all assumes an ANSI-compliant output stream is the output, and feels quite hack-ish, overriding the console.log() function like that. Is there a more compliant way to handle this, or is this the best way?
Still, now I cannot find a modern satisfactory answer on StackOverflow.
After spending a few hours on the internet, I came up with this solution for latest Node (v15.*)
const log = (msg) => {
rl.output.write('\r')
rl.output.write(msg + '\n')
rl.displayPrompt(true)
}
Basically, clear the line, write the log, then display the prompt again. Works perfectly for my case.
Improved solution.
The above works well if the buffered line is not longer than the log. So here is another version that pad the rest of log by space characters
const log = (msg) => {
rl.output.write('\r');
rl.output.write(_.padEnd(msg, process.stdout.columns - 2, ' ') + '\n');
rl.displayPrompt(true);
};
_.padEnd: lodash's padEnd, can be replaced by any lib
Based on #MidnightLightning's older answer.
As of sometime before node v12.15.0 the console.log override would look like:
activeRepl.context.console.log = (msg) => {
const promptOffset = Server._prompt.length + Server.line.length;
Server.outputStream.write('\033[2K\033[1G'); // Erase to beginning of line, and reposition cursor at beginning of line
Server.outputStream.write(msg + "\n");
Server.outputStream.write('' + Server._prompt + Server.line); // Redraw existing line
Server.outputStream.write('\033[' + (promptOffset + 1) + 'G'); // Move the cursor to where it was
};

Debugging Javascript functions in Firebug

I am trying to debug legacy scripts with Firebug. As per my knowledge (Which I got yesterday)
we use Step over (F10) to debug line by line and Step into (F11) to dig into JS function.
But when I use Step into on any JS function call, it takes control to next line. I want to see what is hidden inside the function. How can we do it ?
I kept break-point inside the function and then tried Step into then it takes control inside the function body. But it is tedious to find each function method and set break-point.
Is there any other way to do it ? or which is the right way ?
For example :
i2b2.ONT.ctrlr.FindBy = {
clickSearchName: function() {
// do some stuff
i2b2.ONT.ctrlr.FindBy.doNameSearch(search_info); // I tried Step into here
// some more stuff
}
doNameSearch: function(inSearchData) {
// If I set break-point here then only I can debug it
// or it directly takes control to `// some more stuff` in `clickSearchName:function`
}
}
PS: It also more external JS function calls.
Thanks,
Ajinkya.
"Step into" will step into the function if there is JS source for the function. If not (like for document.getElementById("foo"), it will step over it since it doesn't have anything that it understand to step into.
If you can point us to a working example where you are having the problem (either a jsFiddle reduction of the problem or a working web page) with instruction on where the relevant code is, we can probably help more.
Judging by your code example, I'm wondering what you're trying to step into. The line of code that starts with clickSearchName defines a function. It doesn't execute it. So, it won't go into that function until some later code actually calls clickSearchName. So, perhaps you're breaking on the definition of the function and trying to step into the function when it isn't being executed. That's just a guess though since we don't have a working example to try ourselves.
Add the line debugger; to your code at the place where you want to break into the debugger, it's a JavaScript keyword, which should do what you want. Just remember to take it out when you're done debugging your code.

Categories

Resources