Skip to content

Commit 0c93399

Browse files
committed
Release source code
1 parent d183029 commit 0c93399

File tree

338 files changed

+34519
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

338 files changed

+34519
-3
lines changed

.github/workflows/dotnet.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: windows-latest
13+
14+
steps:
15+
- uses: actions/checkout@v3
16+
- name: Setup .NET
17+
uses: actions/setup-dotnet@v2
18+
with:
19+
dotnet-version: 6.0.x
20+
21+
- name: Restore dependencies
22+
run: dotnet restore
23+
24+
- name: Build
25+
run: |
26+
dotnet build src\WebView2.DevTools.Dom.sln --no-restore --configuration Release
27+
dotnet pack src\WebView2.DevTools.Dom\WebView2.DevTools.Dom.csproj --no-build --configuration Release
28+
29+
# Disable Test Run until I can workout how to install WebView2 Runtime (not clear that it will run on GitHub Actions either).
30+
# Possibly used a fixed runtime
31+
# - name: Test
32+
# run: dotnet test -f net5.0-windows -s WebView2.DevTools.Dom.Tests\test.runsettings --no-build --verbosity normal
33+
34+
- name: Publish Nuget to GitHub
35+
run: |
36+
dotnet nuget push src\WebView2.DevTools.Dom\bin\Release\*.nupkg -k ${{ secrets.GITHUB_TOKEN }} -s https://nuget.pkg.github.com/ChromiumDotNet/index.json
37+
dotnet nuget push src\WebView2.DevTools.Dom\bin\Release\*.nupkg -k ${{ secrets.MyGetToken }} -s https://www.myget.org/F/cefsharp/api/v3/index.json

Nuget/Readme.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# WebView2 DevTools DOM
2+
3+
WebView2 DevTools Dom is a port of [puppeteer-sharp by Darío Kondratiuk](https://github.com/hardkoded/puppeteer-sharp) that has been adapted specifically for use with WebView2.
4+
- Direct communication with the CoreWebView2 via the DevTools protocol (no need to open a Remote Debugging Port).
5+
- 1:1 mapping of WebView2DevToolsContext and CoreWebView2 (create a single WebView2DevToolsContext per CoreWebView2 instance)
6+
- The primary focus of this project is DOM access/manipulation and Javascript execution/evaluation.
7+
- Only a **subset** of the Puppeteer Sharp features were ported (It maybe possible to port additional features if sufficent user demand).
8+
9+
# Sponsorware
10+
11+
This project has adopted a variant of the [Sponsorware](https://github.com/sponsorware/docs) open source model. To ensure the project maintainer/developer ([@amaitland](https://github.com/amaitland))
12+
can support the project the source will be released under an MIT license when the target of 25 sponsors signup to the [WebView2 DevTools Dom Supporter](https://github.com/sponsors/amaitland/)
13+
tier here on GitHub. Sponsors will get **priority support**. **Everyone** is free to download and use the Nuget package.
14+
15+
# Prerequisites
16+
17+
* .Net 4.6.2 or .Net Core 3.1 or greater
18+
* Microsoft.Web.WebView2.DevToolsProtocolExtension 1.0.824 or greater
19+
20+
# Questions and Support
21+
22+
Sponsors can:
23+
24+
* Ask a question on [Discussions](https://github.com/amaitland/WebView2.DevTools.Dom/discussions).
25+
* File bug reports on [Issues](https://github.com/amaitland/WebView2.DevTools.Dom/issues).
26+
27+
# Usage
28+
29+
Checkout https://github.com/ChromiumDotNet/WebView2.DevTools.Dom#readme for more details

Nuget/WebView2.DevTools.Dom.nuspec

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0"?>
2+
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
3+
<metadata>
4+
<id>WebView2.DevTools.Dom</id>
5+
<title>WebView2 DevTools Dom</title>
6+
<version>$version$</version>
7+
<authors>Alex Maitland</authors>
8+
<owners>amaitland</owners>
9+
<projectUrl>https://github.com/ChromiumDotNet/WebView2.DevTools.Dom</projectUrl>
10+
<license type="file">LICENSE</license>
11+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
12+
<repository type="git" url="https://github.com/ChromiumDotNet/WebView2.DevTools.Dom.Source.git" />
13+
<description>
14+
WebView2.DevTools.Dom - Extension WebView2 providing strongly typed DOM access/modification.
15+
16+
✔️ WebView2.DevTools.Dom is a library for strongly typed DOM access when using WebView2.
17+
✔️ It provides a convenient way to write readable/robust/refactorable DOM access code.
18+
✔️ Chrome DevTools Protocol based API
19+
✔️ Talks directly to the WebView2 browser (no remote debugging port required).
20+
✔️ Extensive Unit Tests
21+
✔️ Free for everyone to use
22+
23+
<![CDATA[
24+
// Add using WebView2.DevTools.Dom; to get access to the CreateDevToolsContextAsync extension method
25+
var devToolsContext = await coreWebView2.CreateDevToolsContextAsync();
26+
27+
// Get element by Id
28+
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
29+
var htmlDivElement = await devToolsContext.QuerySelectorAsync<HtmlDivElement>("#myDivElementId");
30+
31+
//Set innerText property for the element
32+
await htmlDivElement.SetInnerTextAsync("Welcome!");
33+
34+
// Manually dispose of context (only DisposeAsync is supported as the whole API is async)
35+
// alternativly use await using var devToolsContext = await coreWebView2.CreateDevToolsContextAsync();
36+
// if your .Net version supports it.
37+
await devToolsContext.DisposeAsync();
38+
]]>
39+
40+
Website: https://github.com/ChromiumDotNet/WebView2.DevTools.Dom
41+
</description>
42+
<tags>webview2 webview devtools dom automation</tags>
43+
<copyright>Copyright © Alex Maitland</copyright>
44+
<readme>docs\README.md</readme>
45+
<dependencies>
46+
<group targetFramework=".NETFramework4.6.2">
47+
<dependency id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" exclude="Build,Analyzers" />
48+
<dependency id="Microsoft.Extensions.Logging" version="2.1.1" exclude="Build,Analyzers" />
49+
<dependency id="Microsoft.Web.WebView2.DevToolsProtocolExtension" version="1.0.2901" exclude="Build,Analyzers" />
50+
</group>
51+
<group targetFramework=".NETCoreApp3.1">
52+
<dependency id="Microsoft.Extensions.Logging" version="2.1.1" exclude="Build,Analyzers" />
53+
<dependency id="Microsoft.Web.WebView2.DevToolsProtocolExtension" version="1.0.2901" exclude="Build,Analyzers" />
54+
</group>
55+
</dependencies>
56+
<releaseNotes>
57+
<![CDATA[
58+
Fix CssStyleDeclaration.GetPropertyValueAsync<T> return type (https://github.com/ChromiumDotNet/WebView2.DevTools.Dom/issues/9)
59+
]]>
60+
</releaseNotes>
61+
</metadata>
62+
<files>
63+
<file src="..\src\WebView2.DevTools.Dom\bin\Release\net462\obfuscated\WebView2.DevTools.Dom.dll" target="lib\net462" />
64+
<file src="..\src\WebView2.DevTools.Dom\bin\Release\net462\WebView2.DevTools.Dom.xml" target="lib\net462" />
65+
66+
<file src="..\src\WebView2.DevTools.Dom\bin\Release\netcoreapp3.1\obfuscated\WebView2.DevTools.Dom.dll" target="lib\netcoreapp3.1" />
67+
<file src="..\src\WebView2.DevTools.Dom\bin\Release\netcoreapp3.1\WebView2.DevTools.Dom.xml" target="lib\netcoreapp3.1" />
68+
69+
<file src="Readme.txt" target="" />
70+
<file src="..\README.md" target="docs\" />
71+
<file src="..\LICENSE" target="LICENSE" />
72+
</files>
73+
</package>

Nuget/build.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dotnet pack ..\src\WebView2.DevTools.Dom\WebView2.DevTools.Dom.csproj --no-build --configuration Release

README.md

Lines changed: 165 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,132 @@ coreWebView2.NavigationCompleted += async (sender, args) =>
186186
}
187187
};
188188
```
189-
<sup><a href='/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs#L20-L144' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryselector' title='Start of snippet'>anchor</a></sup>
189+
<sup><a href='/src/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs#L20-L144' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryselector' title='Start of snippet'>anchor</a></sup>
190+
<a id='snippet-queryselector-1'></a>
191+
```cs
192+
// Add using WebView2.DevTools.Dom; to get access to the
193+
// CreateDevToolsContextAsync extension method
194+
195+
coreWebView2.NavigationCompleted += async (sender, args) =>
196+
{
197+
if(args.IsSuccess)
198+
{
199+
// WebView2DevToolsContext implements IAsyncDisposable and can be Disposed
200+
// via await using or await devToolsContext.DisposeAsync();
201+
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#using-async-disposable
202+
await using var devToolsContext = await coreWebView2.CreateDevToolsContextAsync();
203+
204+
// Get element by Id
205+
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
206+
var element = await devToolsContext.QuerySelectorAsync<HtmlElement>("#myElementId");
207+
208+
//Strongly typed element types
209+
//Only a subset of element types have been added so far, use HtmlElement as a generic type for all others
210+
var htmlDivElement = await devToolsContext.QuerySelectorAsync<HtmlDivElement>("#myDivElementId");
211+
var htmlSpanElement = await devToolsContext.QuerySelectorAsync<HtmlSpanElement>("#mySpanElementId");
212+
var htmlSelectElement = await devToolsContext.QuerySelectorAsync<HtmlSelectElement>("#mySelectElementId");
213+
var htmlInputElement = await devToolsContext.QuerySelectorAsync<HtmlInputElement>("#myInputElementId");
214+
var htmlFormElement = await devToolsContext.QuerySelectorAsync<HtmlFormElement>("#myFormElementId");
215+
var htmlAnchorElement = await devToolsContext.QuerySelectorAsync<HtmlAnchorElement>("#myAnchorElementId");
216+
var htmlImageElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myImageElementId");
217+
var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync<HtmlImageElement>("#myTextAreaElementId");
218+
var htmlButtonElement = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId");
219+
var htmlParagraphElement = await devToolsContext.QuerySelectorAsync<HtmlParagraphElement>("#myParagraphElementId");
220+
var htmlTableElement = await devToolsContext.QuerySelectorAsync<HtmlTableElement>("#myTableElementId");
221+
222+
// Get a custom attribute value
223+
var customAttribute = await element.GetAttributeAsync<string>("data-customAttribute");
224+
225+
//Set innerText property for the element
226+
await element.SetInnerTextAsync("Welcome!");
227+
228+
//Get innerText property for the element
229+
var innerText = await element.GetInnerTextAsync();
230+
//Can also be acessed via calling GetPropertyValueAsync
231+
//Can use this method to get any property that isn't currently mapped
232+
innerText = await element.GetInnerTextAsync();
233+
234+
//Get all child elements
235+
var childElements = await element.QuerySelectorAllAsync("div");
236+
237+
//Change CSS style background colour
238+
await element.EvaluateFunctionAsync("e => e.style.backgroundColor = 'yellow'");
239+
240+
//Type text in an input field
241+
await element.TypeAsync("Welcome to my Website!");
242+
243+
//Scroll Element into View (if needed)
244+
//Can optional specify a Rect to be scrolled into view, relative to the node's border box,
245+
//in CSS pixels. When omitted, center of the node will be used
246+
await element.ScrollIntoViewIfNeededAsync();
247+
248+
//Click The element
249+
await element.ClickAsync();
250+
251+
// Simple way of chaining method calls together when you don't need a handle to the HtmlElement
252+
var htmlButtonElementInnerText = await devToolsContext.QuerySelectorAsync<HtmlButtonElement>("#myButtonElementId")
253+
.AndThen(x => x.GetInnerTextAsync());
254+
255+
//Event Handler
256+
//Expose a function to javascript, functions persist across navigations
257+
//So only need to do this once
258+
await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () =>
259+
{
260+
_ = devToolsContext.EvaluateExpressionAsync("window.alert('Hello! You invoked window.alert()');");
261+
});
262+
263+
var jsAlertButton = await devToolsContext.QuerySelectorAsync("#jsAlertButton");
264+
265+
//Write up the click event listner to call our exposed function
266+
_ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick");
267+
268+
//Get a collection of HtmlElements
269+
var divElements = await devToolsContext.QuerySelectorAllAsync<HtmlDivElement>("div");
270+
271+
foreach (var div in divElements)
272+
{
273+
// Get a reference to the CSSStyleDeclaration
274+
var style = await div.GetStyleAsync();
275+
276+
//Set the border to 1px solid red
277+
await style.SetPropertyAsync("border", "1px solid red", important: true);
278+
279+
await div.SetAttributeAsync("data-customAttribute", "123");
280+
await div.SetInnerTextAsync("Updated Div innerText");
281+
}
282+
283+
//Using standard array
284+
var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync();
285+
286+
foreach(var row in tableRows)
287+
{
288+
var cells = await row.GetCellsAsync().ToArrayAsync();
289+
foreach(var cell in cells)
290+
{
291+
var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
292+
await newDiv.SetInnerTextAsync("New Div Added!");
293+
await cell.AppendChildAsync(newDiv);
294+
}
295+
}
296+
297+
//Get a reference to the HtmlCollection and use async enumerable
298+
//Requires Net Core 3.1 or higher
299+
var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync();
300+
301+
await foreach (var row in tableRowsHtmlCollection)
302+
{
303+
var cells = await row.GetCellsAsync();
304+
await foreach (var cell in cells)
305+
{
306+
var newDiv = await devToolsContext.CreateHtmlElementAsync<HtmlDivElement>("div");
307+
await newDiv.SetInnerTextAsync("New Div Added!");
308+
await cell.AppendChildAsync(newDiv);
309+
}
310+
}
311+
}
312+
};
313+
```
314+
<sup><a href='/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs#L20-L144' title='Snippet source file'>snippet source</a> | <a href='#snippet-queryselector-1' title='Start of snippet'>anchor</a></sup>
190315
<!-- endSnippet -->
191316

192317
## Inject HTML
@@ -207,7 +332,24 @@ await using var devtoolsContext = await coreWebView2.CreateDevToolsContextAsync(
207332
await devtoolsContext.SetContentAsync("<div>My Receipt</div>");
208333
var result = await devtoolsContext.GetContentAsync();
209334
```
210-
<sup><a href='/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SetContentTests.cs#L22-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-setcontentasync' title='Start of snippet'>anchor</a></sup>
335+
<sup><a href='/src/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SetContentTests.cs#L22-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-setcontentasync' title='Start of snippet'>anchor</a></sup>
336+
<a id='snippet-setcontentasync-1'></a>
337+
```cs
338+
// Add using WebView2.DevTools.Dom; to get access to the
339+
// CreateDevToolsContextAsync extension method
340+
341+
// WebView2DevToolsContext implements IAsyncDisposable and can be Disposed
342+
// via await using or await devToolsContext.DisposeAsync();
343+
// Only DisposeAsync is supported. It's very important the WebView2DevToolsContext is Disposed
344+
// When you have finished. Only create a single instance at a time, reuse an instance rather than
345+
// creaeting a new WebView2DevToolsContext. Dispose the old WebView2DevToolsContext instance before
346+
// creating a new instance if you need to manage the lifespan manually.
347+
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#using-async-disposable
348+
await using var devtoolsContext = await coreWebView2.CreateDevToolsContextAsync();
349+
await devtoolsContext.SetContentAsync("<div>My Receipt</div>");
350+
var result = await devtoolsContext.GetContentAsync();
351+
```
352+
<sup><a href='/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SetContentTests.cs#L22-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-setcontentasync-1' title='Start of snippet'>anchor</a></sup>
211353
<!-- endSnippet -->
212354

213355
## Evaluate Javascript
@@ -232,7 +374,27 @@ var fourtyTwo = await devToolsContext.EvaluateFunctionAsync<int>("() => Promise.
232374
var someObject = await devToolsContext.EvaluateFunctionAsync<dynamic>("(value) => ({a: value})", 5);
233375
System.Console.WriteLine(someObject.a);
234376
```
235-
<sup><a href='/WebView2.DevTools.Dom.Tests/QuerySelectorTests/ElementHandleQuerySelectorEvalTests.cs#L17-L35' title='Snippet source file'>snippet source</a> | <a href='#snippet-evaluate' title='Start of snippet'>anchor</a></sup>
377+
<sup><a href='/src/WebView2.DevTools.Dom.Tests/QuerySelectorTests/ElementHandleQuerySelectorEvalTests.cs#L17-L35' title='Snippet source file'>snippet source</a> | <a href='#snippet-evaluate' title='Start of snippet'>anchor</a></sup>
378+
<a id='snippet-evaluate-1'></a>
379+
```cs
380+
// Add using WebView2.DevTools.Dom; to get access to the
381+
// CreateDevToolsContextAsync extension method
382+
383+
await webView2Browser.EnsureCoreWebView2Async();
384+
385+
// WebView2DevToolsContext implements IAsyncDisposable and can be Disposed
386+
// via await using or await devToolsContext.DisposeAsync();
387+
// https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#using-async-disposable
388+
await using var devToolsContext = await webView2Browser.CoreWebView2.CreateDevToolsContextAsync();
389+
await devToolsContext.IgnoreCertificateErrorsAsync(true);
390+
var seven = await devToolsContext.EvaluateExpressionAsync<int>("4 + 3");
391+
// Can evaluate a function that returns a Promise
392+
var fourtyTwo = await devToolsContext.EvaluateFunctionAsync<int>("() => Promise.resolve(42)");
393+
// Pass in arguments to a function, including references to HtmlElements and JavascriptHandles
394+
var someObject = await devToolsContext.EvaluateFunctionAsync<dynamic>("(value) => ({a: value})", 5);
395+
System.Console.WriteLine(someObject.a);
396+
```
397+
<sup><a href='/WebView2.DevTools.Dom.Tests/QuerySelectorTests/ElementHandleQuerySelectorEvalTests.cs#L17-L35' title='Snippet source file'>snippet source</a> | <a href='#snippet-evaluate-1' title='Start of snippet'>anchor</a></sup>
236398
<!-- endSnippet -->
237399

238400
## NOT YET SUPPORTED

0 commit comments

Comments
 (0)