Adding a script element to an existing TWebBrowser document

Prompt a couple of SO qs this weekend, I decided to see if I could figure out how to add some javascript to the Html element to the document uploaded to TWebBrowser. In doing this, I ran into a weirdness that someone might explain.

Here is my html document

<html>
  <body>
  Something
  <br>
  <div id="forscript">some more text</div>
  </body>
</html>

      

and my javascript element i want to add to it

<script type="text/javascript" defer="false">{alert('hello');}</script>

      

which I am passing as the Script argument to AddScript () below.

This is my code (doc2 is IHtmlDocument2 obtained from WebBrowser):

procedure TForm1.AddScript(const Script : String);
var
  Element : IHtmlElement;
  Doc3 : IHtmlDocument3;
begin
  Doc2.QueryInterface(IHtmlDocument3, Doc3);
  Element := Doc3.GetElementByID('forscript');
  Element.innerHTML := Element.innerHTML + Script;
end;

      

This works great, but ...

The reason for Element.innerHTML in RHS assignments is simply that I found that if the RHS contains only Script js, the js is not executed. My question is why not, and is there a simpler alternative, for example, somehow create an IHtmlScriptElement in code and insert it into the DOM? Obviously, my simple approach is to just add text The element already contains, but it's a little hard for me to believe that people who really know what they are doing will find it appropriate.

FWIW # 1 . I tried to use Element.insertAdjacentHtml to add the Script, but got the same behavior I just described, in terms of having to insert something in addition to the Script in order to execute the Script, so I wonder if this is related to how the DOM is processed after changes are made.

FWIW # 2 : I used the Element.innerHtml route because TWebBrowser / MSHTML.Pas resisted my attempt to create an IHtmlScriptElement in code; AFAICS, trying to use any of the CohtmlXXXElement Routines in MSHTML.Pas throws a "Class not registered" exception which seems to corroborate the comment I found somewhere @kobik of this coming.

(Btw using D7 + IE11 on Win7 64-bit)

+3


source to share


1 answer


Here's a complete use case IHtmlScriptElement

. The html is loaded when the application starts. The code below Button1Click

adds javascript to the DOM and executes it:



unit u_frm_SO27091639;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, MsHtml, ActiveX;

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure LoadDocFromString(Webbrowser : TWebbrowser);

var
  Strm    : TStringStream;
  Adapter : TStreamAdapter;

begin
 WebBrowser.Navigate('about:blank');
 // warning - don't use this trick in production code, use the `OnDocumentComplete` event
 while WebBrowser.ReadyState <> READYSTATE_INTERACTIVE do
  Application.ProcessMessages;
 // end of warning
 Strm := TStringStream.Create;
 try
  Strm.WriteString('<html><body>Something<br></body></html>');
  Strm.Seek(0, 0);
  Adapter := TStreamAdapter.Create(Strm);
  (WebBrowser.Document as IPersistStreamInit).Load(Adapter) ;
 finally
  Strm.Free;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);

var
  Doc2     : IHtmlDocument2;
  Script   : IHtmlDOMNode;
  HTMLWindow: IHTMLWindow2;

begin
 Doc2 := Webbrowser1.Document as IHtmlDocument2;
 if Assigned(Doc2.body) then
  begin
   Script := Doc2.createElement('script') as IHTMLDOMNode;
   (Script as IHTMLScriptElement).text := 'function helloWorld() { alert("hello world!") }';
   (Doc2.body as IHtmlDomNode).appendChild(Script);
   HTMLWindow := Doc2.parentWindow;
   if Assigned(HTMLWindow) then
    HTMLWindow.execScript('helloWorld()', 'JavaScript')
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 LoadDocFromString(Webbrowser1);
end;

end.

      

+5


source







All Articles