MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
453 stars 55 forks source link

Allow easy access to DOM/HTML #77

Open ukandrewc opened 5 years ago

ukandrewc commented 5 years ago

I've just started writing one to compliment this implementation: https://github.com/michael-russin/webview2-control

But wondering if it's worth waiting if you have plans for one. Thanks

AB#28556146

david-risney commented 5 years ago

Hey I just saw your projects on nuget yesterday but haven't had a chance to look into them yet. Thanks for trying it out! Did you run into any interesting issues etc?

We are planning on producing a WPF & WinForms controls sometime by the first half of next year with a dev preview earlier than that.

ukandrewc commented 5 years ago

Just to clarify, they aren't my projects ;-) Sorry, but my question is: do you plan to have DOM classes that are accessible from .Net? Thanks

david-risney commented 5 years ago

Oh I see. If I understand what you're planning, no. Similar to the EdgeHtml WebView (and unlike the mshtml WebView/WebControl), we don't plan to expose the DOM via our API and instead it should be accessed via script.

ukandrewc commented 5 years ago

Thanks David, for clarifying. Ideally we'd like to see access similar to mshtml, but I'm sure we'll create our own, or cope with JS ;-) Andrew

ukandrewc commented 4 years ago

I'm really keen to see the Winforms control, as early as possible. Our application is built on the mshtml control, which needed replacing a year ago ;-) I need to create a .Net wrapper around the DOM, so would like to get started on that ASAP. If there's anything that can be done to start work sooner, that would be great. Thanks very much Andrew

kfke commented 3 years ago

Hi All,

Also, our win32 c++ application uses the mshtml (WebBrowser control) many times, and we want to replace them with the new webview2, but need a way to access DOM/HTML directly, is there any news about this?

Thanks

Roadrunner67 commented 3 years ago

I have a scenario resembling that of @jbennink in issue #1058 It seems pretty obvious that this is a must and a showstopper for a lot of migrations from webview to webview2. This issue has my upvote.

jbennink commented 3 years ago

Any news about DOM access in WebView2? It's been more than 1.5 years since this issue was opened and a lot of similar issues have been grouped together in this issue. but no new information. Looking at the huge number of requests for this feature it should be obsious this has to be a part of the WebView2 control.

Please can we get an updated status on this!

amaitland commented 2 years ago

For those interested I've just released WebView2.DevTools.Dom to NuGet.org. The project has a public GitHub Page

Unlike some of the other packages currently available it's Chrome DevTools Protocol based framework for JavaScript execution, DOM access/manipulation and automation. Requires .Net 4.6.2 or .Net Core 3.1 or greater

More details and examples in the Readme

 await webView.EnsureCoreWebView2Async();

 // WebView2DevToolsContext implements IAsyncDisposable and can be Disposed
// via await using or await devToolsContext.DisposeAsync();
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#using-async-disposable
await using var devToolsContext = await coreWebView2.CreateDevToolsContextAsync();

// Get element by Id
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var element = await devToolsContext.QuerySelectorAsync("#myElementId");

//Strongly typed element types
//Only a subset of element types have been added so far, use HtmlElement as a generic type for all others
var htmlDivElement = await devToolsContext.QuerySelectorAsync<HtmlDivElement>("#myDivElementId");
var htmlSpanElement = await devToolsContext.QuerySelectorAsync<HtmlSpanElement>("#mySpanElementId");
var htmlSelectElement = await devToolsContext.QuerySelectorAsync<HtmlSelectElement>("#mySelectElementId");
var htmlInputElement = await devToolsContext.QuerySelectorAsync<HtmlInputElement>("#myInputElementId");
var htmlFormElement = await devToolsContext.QuerySelectorAsync<HtmlFormElement>("#myFormElementId");
var htmlAnchorElement = await devToolsContext.QuerySelectorAsync<HtmlAnchorElement>("#myAnchorElementId");
var htmlImageElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myImageElementId");
var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myTextAreaElementId");
var htmlButtonElement = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId");
var htmlParagraphElement = await devToolsContext.QuerySelectorAsync<HtmlParagraphElement>("#myParagraphElementId");
var htmlTableElement = await devToolsContext.QuerySelectorAsync<HtmlTableElement>("#myTableElementId");

// Get a custom attribute value
var customAttribute = await element.GetAttributeAsync<string>("data-customAttribute");

//Set innerText property for the element
await element.SetPropertyValueAsync("innerText", "Welcome!");

await element.SetInnerTextAsync("Welcome 2!");

//Get innerText property for the element
var innerText = await element.GetInnerTextAsync();
//Can also be acessed via calling GetPropertyValueAsync
//Can use this method to get any property that isn't currently mapped
innerText = await element.GetPropertyValueAsync<string>("innerText");

//Get all child elements
var childElements = await element.QuerySelectorAllAsync("div");

//Change CSS style background colour
_ = await element.EvaluateFunctionAsync("e => e.style.backgroundColor = 'yellow'");

//Type text in an input field
await element.TypeAsync("Welcome to my Website!");

//Scroll Element into View (if needed)
//Can optional specify a Rect to be scrolled into view, relative to the node's border box,
//in CSS pixels. When omitted, center of the node will be used
await element.ScrollIntoViewIfNeededAsync();

//Click The element
await element.ClickAsync();

//Event Handler
//Expose a function to javascript, functions persist across navigations
//So only need to do this once
await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () =>
{
    _ = devToolsContext.EvaluateExpressionAsync("window.alert('Hello! You invoked window.alert()');");
});

var jsAlertButton = await devToolsContext.QuerySelectorAsync("#jsAlertButton");

//Write up the click event listner to call our exposed function
_ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick");

        //Get a collection of HtmlElements
        var divElements = await devToolsContext.QuerySelectorAllAsync<HtmlDivElement>("div");

        foreach (var div in divElements)
        {
            // Get a reference to the CSSStyleDeclaration
            var style = await div.GetStyleAsync();

            //Set the border to 1px solid red
            await style.SetPropertyAsync("border", "1px solid red", important: true);

            await div.SetAttributeAsync("data-customAttribute", "123");
            await div.SetInnerTextAsync("Updated Div innerText");
        }

        //Using standard array
        var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync();

        foreach(var row in tableRows)
        {
            var cells = await row.GetCellsAsync().ToArrayAsync();
            foreach(var cell in cells)
            {
                var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
                await newDiv.SetInnerTextAsync("New Div Added!");
                await cell.AppendChildAsync(newDiv);
            }
        }

        //Get a reference to the HtmlCollection and use async enumerable
        //Requires Net Core 3.1 or higher
        var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync();

        await foreach (var row in tableRowsHtmlCollection)
        {
            var cells = await row.GetCellsAsync();
            await foreach (var cell in cells)
            {
                var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
                await newDiv.SetInnerTextAsync("New Div Added!");
                await cell.AppendChildAsync(newDiv);
            }
        }
amaitland commented 2 years ago

For those interested I've just released WebView2.DevTools.Dom to NuGet.org

Unlike some of the other packages currently available it's Chrome DevTools Protocol based framework for JavaScript execution, DOM access/manipulation and automation. Requires .Net 4.6.2 or .Net Core 3.1 or greater

Just as a follow up I'm working on a guide Porting from the IE WebBrowser control, I'm looking for ~3 people to provide real world samples that they'd be interested in porting over. I'll provide a port of those examples that can be used as a reference for everyone.

I'll also be offering paid consultancy services for those that need/require more than just a guide.

weitzhandler commented 5 days ago

Are there any plans to adopt this functionality and make it part of the WV2?