Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
IntraWeb 15.3.x JavaScript code generation issue
#1
I may have found a bug, or at least an issue in IntraWeb 15.3.4 that breaks existing IntraWeb applications.

IntraWeb 15.3.x made a change in unit IWRenderContext.pas where procedure TIWPageContext40.AddToJavaScriptOnce(const ACode: string); contains the following code:
Code:
procedure TIWPageContext40.AddToJavaScriptOnce(const ACode: string);
var
  len: Integer;
  LCode: string;
begin
  len := Length(ACode);
  if len = 0 then begin
    Exit;
  end;
  if (len > 2) and (ACode[len-1] = CR) and (ACode[len] = LF) then begin
    LCode := ACode;
  end else begin
    LCode := ACode + EOL;
  end;
  if Pos(LCode, FJavaScript) <= 0 then begin
    FJavaScript := FJavaScript + LCode;
  end;
end;

The line with "if Pos(LCode, FJavaScript) <= 0 then begin" is introduced in IntraWeb 15.3.x (and was not present in IntraWeb 15.2.69).

This causes problems in our case where we have a page with a TIWControl and an onkeydown Script Event:
Code:
if (event.which == 13) {
  console.log("HW");
  IWBUTTON_LOGIN_onclick(event);
  return false;
} else {
  return true;
}


The problem is caused in unit IWRenderContext;


Code:
procedure TIWPageContext40.FinalizeContext;
begin
  ...

  AddToJavaScriptOnce('  return true;' + EOL + '}' + EOL); // last line
end;

The last call to AddToJavaScriptOnce tries to add a JavaScript snippet that only consists of "return true;" and the closing }.

However, inside the AddToJavaScriptOnce, this snippet is found to be already in the FJavaScript (because it's part of the onkeydown Script Event shown in the second screenshot).

As a consequence the last call to AddToJavaScriptOnce has no effect: the JavaScript is not added, and inside the browser we only get the "function Validate(){" without the closing "return true;" and }.

WORKAROUND

A simple workaround is to modify the
Code:
  AddToJavaScriptOnce('  return true;' + EOL + '}' + EOL);


And change it into
Code:
  AddToJavaScriptOnce('  return true;' + EOL + '} // Bob' + EOL);


However, any other place where we only add a "return true;" and "}" will still be ignored, so this may still break IntraWeb applications in other places

FIX?

I do not know the reason why the condition was added to the procedure TIWPageContext40.AddToJavaScriptOnce, but a real fix appears to be to remove that if statement (again, it was not present in IbtraWeb 15.2.69):


Code:
  if Pos(LCode, FJavaScript) <= 0 then begin // prevent LCode to be added to FJavaScript more than once?
    FJavaScript := FJavaScript + LCode;


Both the workaround and the fix seem to solve the problem for us. Please let me know your thoughts, especially why the new if-statement in the AddToJavaScriptOnce is required, so I can avoid any other issues that may be introduced by my workaround or fix.

Thanks in advance.

Groetjes, Bob Swart
Reply
#2
Hi Bob. In your event onKeyDown, change last line to: };
Like this code:
Code:
if (event.keyCode == 13) {
  IWBUTTON_BUSCAIWCL.click();
  return false;
} else {
  return true;
};
Reply
#3
Thank you for the suggestion, but the fact remains that the code in procedure TIWPageContext40.AddToJavaScriptOnce(const ACode: string); has an condition to check if the JavaScript code you want to add is not already present (the comment is mine).
Code:
  if Pos(LCode, FJavaScript) <= 0 then begin // prevent LCode to be added to FJavaScript more than once?
    FJavaScript := FJavaScript + LCode;
end;

And inside procedure TIWPageContext40.FinalizeContext; is a last line as follows:
Code:
  AddToJavaScriptOnce('  return true;' + EOL + '}' + EOL);
end;

which means that I must now ensure that there is no snippet of JavaScript equal to
Code:
'  return true;' + EOL + '}' + EOL
in the FJavaScript before the FinalizeContext is called.

Which means that for example
Code:
if (event.keyCode != 13) {
  return true;
}
else
{
  IWBUTTON_BUSCAIWCL.click();
  return false;
};
would also break the IntraWeb application.

I'm sorry, but I do not believe it's feasible to ask IntraWeb developers to never add the snippet containing "  return true;EOL}EOL" using AddToJavaScriptOnce to prevent procedure TIWPageContext40.FinalizeContext from breaking.

Groetjes, Bob Swart
Reply
#4
Hi Dr. Bob,

I can confirm that this issue exists.Thanks for your detailed report and workaround.

Unfortunately, an ancient poor piece of code went unnoticed when the behavior of the method changed and it broke AddToJavaScriptOnce() result. Instead of inserting the code at once, FinalizeContext() inserts small pieces of code.

The change is because it is PageContext responsibility to ensure that no duplicate code is inserted by different pieces of code rendered in different component contexts, such as the image cache.

Anyway, a new overloaded method has been introduced and the FinalizeContext() method has also been "fixed" so that it won't insert just small pieces of a JavaScript method.

The new maintenance update 15.3.5 is already available.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)