iframe.contentDocument.documentElement.scrollHeight - Dart equivalent - dart

final html.IFrameElement iframe = rootDemoElement.querySelector("iframe");
final int contentHeight = <???>.scrollHeight;
this works in JS:
var contentHeight = iframe.contentDocument.documentElement.scrollHeight;
contentDocument is not available in Dart.
Is it really possible that contentDocument is missing in Dart?

Here is my solution:
var jsIFrame = new JsObject.fromBrowserObject(iframe);
var contentHeight = jsIFrame["contentDocument"]["documentElement"]["scrollHeight"];

As far as I know there was an attempt to make Dart in the browser more secure than JavaScript and this led to a model where cross-window communication was limited (to postMessage). I assume an Iframe suffers from the same limitations. There was a comment on an issue that they want to leave this strategy because this is usually circumnavigated by using dart-js-interop anyway.
I think the main culprit is that you get a _DOMWindowCrossFrame instead of a Window instance.
See
http://dartbug.com/17936#c2
probably also related
http://dartbub.com/20146
http://dartbug.com/20143
http://dartbug.com/20173
http://dartbug.com/21219
http://dartbug.com/20216
http://dartbug.com/19610
http://dartbug.com/16814
http://dartbug.com/12788
http://dartbug.com/2312

Related

struggle for javascript porting to dart

Original javascript code I like to port to Dart.
hterm.defaultStorage = new lib.Storage.Chrome(chrome.storage.sync);
I have tried
js.context['hterm']['defaultStorage'] =
new js.JsObject(js.context['lib']['Storage']['Chrome'], js.context['chrome']['storage']['sync']);
but this doest work as I expected. perhaps, because js.JsObject returns dart object.
Do I have to use JsObject.jsify ? it seems that jsify receive collection of dart object only.
I think it should work this way
js.context['hterm']['defaultStorage'] =
js.context['lib']['Storage'].callMethod('Chrome', [js.context['chrome']['storage']['sync']]);

Firefox bootstrapped extension: Get native HWND handle of the browser window

I have an external application and I want it to display some information on top of the browser window. My bootstrapped extension needs to pass the browser window handle (native HWND) to my application, along with some other useful information about the window. I'm able to do the communication between them, the only thing that is missing is a way to get the native HWND of the Firefox window.
I read a lot about it and although I belive it's possible, I couldn't find a working solution. Here's what I've tried so far:
This one should give me nsIBaseWindow, so I could get nsIBaseWindow.nativeHandle or nsIBaseWindow.ParentNativeWindow, but no success:
var window = SomeDOMWindow; // Informative
var baseWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIXULWindow)
.docShell
.QueryInterface(Components.interfaces.nsIBaseWindow);
The above code is widely spread on forums, but I couldn't get it to work for me.
The other one does not seem to be much accurate since it gets the HWND based on the window's class and title, which can lead to wrong results:
Components.utils.import("resource://gre/modules/ctypes.jsm");
var lib = ctypes.open("user32.dll");
var fww = lib.declare("FindWindowW", ctypes.winapi_abi,
ctypes.voidptr_t, ctypes.jschar.ptr, ctypes.jschar.ptr);
var sfw = lib.declare("SetForegroundWindow", ctypes.winapi_abi,
ctypes.int32_t, ctypes.voidptr_t);
var hwnd = fww("MozillaWindowClass", document.title);
setTimeout(function() {
sfw(hwnd);
lib.close();
}, 3000);
Any help would be appreciated.
window must be a root one (i.e. an instance of ChromeWindow)
The following code should work
var win = Cc["#mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
var basewindow = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativehandle = basewindow.nativeHandle;
The problem was that I was querying the wrong interface from the subject param in the xul-window-registered observer. I need to get an nsIDOMWindow instead of an nsIXULWindow so the first code mentioned in my question works. So now I'm doing the following, with some piece of code #Noit suggested:
observe: function(subject, topic, data) {
var newWindow = subject.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
var basewindow = newWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativehandle = basewindow.nativeHandle;
}
And it works!
Thank you very much for your help.
I also just came across this, it might be nice:
Cu.import("resource://gre/modules/ctypes.jsm");
/*start getcursorpos*/
var lib = ctypes.open("user32.dll");
/*foreground window stuff*/
var FindWindowA = lib.declare('FindWindowA', ctypes.winapi_abi, ctypes.uint32_t, ctypes.jschar.ptr, ctypes.jschar.ptr)
var GetForegroundWindow = lib.declare('GetForegroundWindow', ctypes.winapi_abi, ctypes.uint32_t)
function doFindWindow() {
var wm = Cc['#mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
var title = wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.title;
Cu.reportError('title=' + title)
var ret = FindWindowA('', title + ' - Mozilla Firefox');
//var ret = GetForegroundWindow();
Cu.reportError(ret);
}
/*end foreground window stuff*/
The code in the answer of user 'paa' worked until Firefox version 69.
If you execute it in Firefox 70 you will get an exception:
TypeError: win.QueryInterface is not a function
This is strange because the variable win has the same content in Firefox 69 and 70.
When I execute alert(win) I get: "[object ChromeWindow]" in both browsers.
And alert(win.document.title) displays correctly the title of the document in both browsers.
I downloaded the sourcecode of both Firefox versions to compare them and possibly find the cause. But the source code of Firefox is huge (2 Gigabyte) and nearly completely free of comments. I found that I'm wasting my time with that approach.
It is extremely difficult to understand sourcecode of Firefox which runs spread over multiple processes which communicate with each other. It seems that the content of the variable win corresponds to the C++ class mozIDOMWindowProxy or nsChromeOuterWindowProxy. But these seem to be only wrapper classes for other classes. Finally I gave up trying to understand Firefox sourcecode.
But playing around for some hours I finally found a solution by try and error.
It is even simpler:
var baseWindow = win.docShell
.treeOwner
.nsIBaseWindow;
It works on Firefox 70 up to 79 (which is currently the latest version). However this new code does not run on Firefox versions <= 62. On Firefox 62 or older you get the error
TypeError: win.docShell is undefined
So the Firefoxes from 63 to 69 allow both versions of code. Maybe in version 70 the QueryInterface() has been removed because it is not needed anymore and has become legacy?
NOTE: In Firefox 68 they made another change. Now there are 2 native windows: The toplevel 'MozillaWindowClass' now has a child window 'MozillaCompositorWindowClass' which runs in another process and draws the web content.

How to not use threads

This is a dart newbie question about how to do "multithreading" in dart.
(Excuse me I am an old java developer ...)
So I have this kind of code (se below) but since recreating the gui is costly I would like to defer it so that instead of recreating the gui in the _onWindowResize() I would like to start a thread that does this when the size has been stable some time. E.g. for one second.
If a thread is already is started do nothing. (Btw, StageXL is cool ....)
(This will also fix the bug that _onWindowResize() is called twice by the dart:html ...)
...
html.window.onResize.listen((e) => _onWindowResize());
}
_createGui() {
var shape = new Shape();
shape.graphics.ellipse(html.window.innerWidth / 2, html.window.innerHeight / 2, html.window.innerWidth / 4, html.window.innerHeight / 4);
shape.graphics.fillColor(Color.Red);
stage.addChild(shape);
}
void _onWindowResize() {
print("New window size ${html.window.innerWidth}x${html.window.innerHeight}");
stage = new Stage('stage', canvas);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
renderLoop = new RenderLoop();
renderLoop.addStage(stage);
juggler = renderLoop.juggler;
_createGui();
}
One can send work to other threads in Dart via Isolates, but this won't work for your scenario since it's mostly about modifying the UI of the app.
One cannot share objects between isolates in Dart (or using WebWorkers in general). So you cannot pass the canvas into an Isolate to create your stage, renderloop, etc.
If you are doing complex calculations (Physics, for example), it might make sense to send those off to an Isolate and use the result to update the UI.

Why Won't this Clipboard Code Pass Mozilla Validation?

Salve! When I try Mozilla's Validator on my addon, it get the following error related to my treatment of clipboard usage:
nsITransferable has been changed in Gecko 16.
Warning: The nsITransferable interface has changed to better support
Private Browsing Mode. After instantiating the object, you should call
the init function on it before any other functions are called.
See https://developer.mozilla.org/en-US/docs/Using_the_Clipboard for more
information.
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if ('init' in trans){ trans.init(null);};
I can't understand this.
Here is my code - I am clearly calling trans.init:
var clip = Components.classes["#mozilla.org/widget/clipboard;1"].getService(Components.interfaces.nsIClipboard);
if (!clip) return "";
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if ('init' in trans){ trans.init(null);}; //<--IT DOESN'T LIKE THIS
if (!trans) return false;
trans.addDataFlavor("text/unicode");
I've also tried the Transferable function from Mozilla's example here, but get the same non-validation report.
One of the Mozilla AMO editors told me to write exactly this, and it still doesn't validate.
I've also tried, simply:
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.init(null); //<---LOOK HERE
if (!trans) return false;
trans.addDataFlavor("text/unicode");
The Validator does not report any errors - just this warning. Everything works properly. Mozilla updated their Gecko engine, and they want devlopers to match up to the new standard.
In my usage, we want to be able to use the contents of the clipboard that was probably gotten from outside the application, too, so we do want to call the init function with null instead of window.
Any advice would be wonderful!
trans.init(null) is valid in some circumstances, such as yours. It can also cause privacy leaks if used in the wrong circumstances, so the validator flags all uses of it as potentially requiring changing. Therefore, it is a warning that you can ignore in this case.

Difference between Msxml2.DOMDocument and Msxml2.XMLHTTP

What is the difference between:
Msxml2.DOMDocument
Msxml2.XMLHTTP
? And of course, the other question is which one will work best for my purpose as described below?
The context is this - I have code that makes many calls to retrieve web pages. I am looking for the most efficient object for this task. For example, something like this:
Dim oXmlHttp : Set oXmlHttp = CreateObject("MSXML2.XMLHTTP")
oXmlHttp.Open "GET", sUri, False
oXmlHttp.Send
If Err Then
getWebPage = "ERROR - could not get the source text of the webpage."
Exit Function
End If
sResponse = oXmlHttp.responseBody
This seems to work the same way if I create an object using:
Dim oXmlHttp : Set oXmlHttp = CreateObject("MSXML2.XMLHTTP")
Can anyone explain or point me to a reference that clearly outlines the differences (and intended usages) for each of those?
If you want to learn more about MSXML, these links may help:
http://msdn.microsoft.com/en-us/library/aa468547.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms766487(v=vs.85).aspx
In short, XMLHTTP is used to retrieve information, while DOMDocument is used to structure and parse it.
This page explains it better: http://msdn.microsoft.com/en-us/library/windows/desktop/ms760218(v=vs.85).aspx
DOMDocument "Represents the top node of the XML DOM tree." while XMLHTTP "Provides client-side protocol support for communication with HTTP servers."

Resources