Skip to content

Commit 4b0b9ad

Browse files
committed
Implemented pseudo view properties #15
1 parent eb43a36 commit 4b0b9ad

File tree

7 files changed

+139
-49
lines changed

7 files changed

+139
-49
lines changed

AngleSharp.Scripting.JavaScript.Tests/AngleSharp.Scripting.JavaScript.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,14 @@
8181
<ItemGroup>
8282
<Compile Include="FireEventTests.cs" />
8383
<Compile Include="GeneratorTests.cs" />
84+
<Compile Include="Helpers.cs" />
8485
<Compile Include="IntegrationTests.cs" />
8586
<Compile Include="InteractionTests.cs" />
8687
<Compile Include="JqueryTests.cs" />
8788
<Compile Include="Mocks\DelayedRequester.cs" />
8889
<Compile Include="PageTests.cs" />
8990
<Compile Include="Properties\AssemblyInfo.cs" />
91+
<Compile Include="PseudoPropertiesTests.cs" />
9092
<Compile Include="ScriptEvalTests.cs" />
9193
<Compile Include="ScriptingTests.cs" />
9294
<Compile Include="Sources.Designer.cs">
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace AngleSharp.Scripting.JavaScript.Tests
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
static class Helpers
10+
{
11+
public static async Task<String> EvalScriptAsync(this String source)
12+
{
13+
var cfg = Configuration.Default.WithJavaScript();
14+
var stdOut = Console.Out;
15+
var output = new StringBuilder();
16+
Console.SetOut(new StringWriter(output));
17+
var html = "<!doctype html><script>console.log(" + source + ")</script>";
18+
await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html));
19+
Console.SetOut(stdOut);
20+
return output.ToString().Trim();
21+
}
22+
23+
public static async Task<String> EvalScriptsAsync(this IEnumerable<String> sources)
24+
{
25+
var cfg = Configuration.Default.WithDefaultLoader(setup => setup.IsResourceLoadingEnabled = true).WithJavaScript().WithCss();
26+
var scripts = "<script>" + String.Join("</script><script>", sources) + "</script>";
27+
var html = "<!doctype html><div id=result></div>" + scripts;
28+
var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html));
29+
return document.GetElementById("result").InnerHtml;
30+
}
31+
}
32+
}

AngleSharp.Scripting.JavaScript.Tests/JqueryTests.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,10 @@ public static Task<String> EvaluateScriptWithJqueryAsync(params String[] sources
1414
{
1515
var list = new List<String>(sources);
1616
list.Insert(0, Sources.Jquery);
17-
return EvaluateScriptsAsync(list);
17+
return list.EvalScriptsAsync();
1818
}
1919

20-
public static async Task<String> EvaluateScriptsAsync(List<String> sources)
21-
{
22-
var cfg = Configuration.Default.WithDefaultLoader(setup => setup.IsResourceLoadingEnabled = true).WithJavaScript().WithCss();
23-
var scripts = "<script>" + String.Join("</script><script>", sources) + "</script>";
24-
var html = "<!doctype html><div id=result></div>" + scripts;
25-
var document = await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html));
26-
return document.GetElementById("result").InnerHtml;
27-
}
28-
29-
public static String SetResult(String eval)
20+
static String SetResult(String eval)
3021
{
3122
return "document.querySelector('#result').textContent = " + eval + ";";
3223
}
@@ -93,7 +84,7 @@ public async Task JqueryWithAjaxToDelayedResponse()
9384
[Test]
9485
public async Task JqueryVersionOne()
9586
{
96-
var result = await EvaluateScriptsAsync(new List<String> { Sources.Jquery1, SetResult("$.toString()") });
87+
var result = await (new [] { Sources.Jquery1, SetResult("$.toString()") }).EvalScriptsAsync();
9788
Assert.AreNotEqual("", result);
9889
}
9990
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace AngleSharp.Scripting.JavaScript.Tests
2+
{
3+
using NUnit.Framework;
4+
using System.Threading.Tasks;
5+
6+
[TestFixture]
7+
public class PseudoPropertiesTests
8+
{
9+
[Test]
10+
public async Task GetScrollLeftOfElement()
11+
{
12+
var result = await "document.createElement('div').scrollLeft".EvalScriptAsync();
13+
Assert.AreEqual("0", result);
14+
}
15+
16+
[Test]
17+
public async Task GetScrollLeftOfDocument()
18+
{
19+
var result = await "document.scrollLeft".EvalScriptAsync();
20+
Assert.AreEqual("undefined", result);
21+
}
22+
23+
[Test]
24+
public async Task GetFocusInOfDocument()
25+
{
26+
var result = await "document.focusIn".EvalScriptAsync();
27+
Assert.AreEqual("undefined", result);
28+
}
29+
30+
[Test]
31+
public async Task GetFocusInOfElement()
32+
{
33+
var result = await "document.createElement('div').focusin".EvalScriptAsync();
34+
Assert.AreEqual("null", result);
35+
}
36+
}
37+
}

AngleSharp.Scripting.JavaScript.Tests/ScriptingTests.cs

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,66 @@
11
namespace AngleSharp.Scripting.JavaScript.Tests
22
{
33
using NUnit.Framework;
4-
using System;
5-
using System.IO;
6-
using System.Text;
74
using System.Threading.Tasks;
85

96
[TestFixture]
107
public class ScriptingTests
118
{
12-
public static async Task<String> EvaluateSimpleScriptAsync(String source)
13-
{
14-
var cfg = Configuration.Default.WithJavaScript();
15-
var stdOut = Console.Out;
16-
var output = new StringBuilder();
17-
Console.SetOut(new StringWriter(output));
18-
var html = "<!doctype html><script>console.log(" + source + ")</script>";
19-
await BrowsingContext.New(cfg).OpenAsync(m => m.Content(html));
20-
Console.SetOut(stdOut);
21-
return output.ToString().Trim();
22-
}
23-
249
[Test]
2510
public async Task PerformSimpleCalculation()
2611
{
27-
var result = await EvaluateSimpleScriptAsync("2 + 3");
12+
var result = await "2 + 3".EvalScriptAsync();
2813
Assert.AreEqual("5", result);
2914
}
3015

3116
[Test]
3217
public async Task GetPropertyOfDocument()
3318
{
34-
var result = await EvaluateSimpleScriptAsync("document.nodeName");
19+
var result = await "document.nodeName".EvalScriptAsync();
3520
Assert.AreEqual("#document", result);
3621
}
3722

3823
[Test]
3924
public async Task GetNodeTypeOfDocument()
4025
{
41-
var type = await EvaluateSimpleScriptAsync("typeof document.nodeType");
42-
var value = await EvaluateSimpleScriptAsync("document.nodeType");
26+
var type = await "typeof document.nodeType".EvalScriptAsync();
27+
var value = await "document.nodeType".EvalScriptAsync();
4328
Assert.AreEqual("number", type);
4429
Assert.AreEqual("9", value);
4530
}
4631

4732
[Test]
4833
public async Task GetChildNodesLengthOfDocument()
4934
{
50-
var result = await EvaluateSimpleScriptAsync("document.childNodes.length");
35+
var result = await "document.childNodes.length".EvalScriptAsync();
5136
Assert.AreEqual("2", result);
5237
}
5338

5439
[Test]
5540
public async Task GetQuerySelectorOfDocument()
5641
{
57-
var result = await EvaluateSimpleScriptAsync("document.querySelectorAll('script').length");
42+
var result = await "document.querySelectorAll('script').length".EvalScriptAsync();
5843
Assert.AreEqual("1", result);
5944
}
6045

6146
[Test]
6247
public async Task GetElementsByTagNameOfDocument()
6348
{
64-
var result = await EvaluateSimpleScriptAsync("document.getElementsByTagName('script').length");
49+
var result = await "document.getElementsByTagName('script').length".EvalScriptAsync();
6550
Assert.AreEqual("1", result);
6651
}
6752

6853
[Test]
6954
public async Task GetQuerySelectorScriptEqualsGetTagNameScript()
7055
{
71-
var result = await EvaluateSimpleScriptAsync("document.querySelector('script') === document.getElementsByTagName('script')[0]");
56+
var result = await "document.querySelector('script') === document.getElementsByTagName('script')[0]".EvalScriptAsync();
7257
Assert.AreEqual("True", result);
7358
}
7459

7560
[Test]
7661
public async Task GetQuerySelectorScriptNotEqualsGetTagNameBody()
7762
{
78-
var result = await EvaluateSimpleScriptAsync("document.querySelector('script') === document.getElementsByTagName('body')[0]");
63+
var result = await "document.querySelector('script') === document.getElementsByTagName('body')[0]".EvalScriptAsync();
7964
Assert.AreEqual("False", result);
8065
}
8166
}

AngleSharp.Scripting.JavaScript/DomEventInstance.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ sealed class DomEventInstance
1111
DomEventHandler _handler;
1212
FunctionInstance _function;
1313

14-
public DomEventInstance(DomNodeInstance node, EventInfo eventInfo)
14+
public DomEventInstance(DomNodeInstance node, EventInfo eventInfo = null)
1515
{
1616
Getter = new ClrFunctionInstance(node.Engine, (thisObject, arguments) => _function ?? JsValue.Null);
1717
Setter = new ClrFunctionInstance(node.Engine, (thisObject, arguments) =>
1818
{
1919
if (_handler != null)
2020
{
21-
eventInfo.RemoveEventHandler(node.Value, _handler);
21+
if (eventInfo != null)
22+
{
23+
eventInfo.RemoveEventHandler(node.Value, _handler);
24+
}
25+
2226
_handler = null;
2327
_function = null;
2428
}
@@ -32,7 +36,11 @@ public DomEventInstance(DomNodeInstance node, EventInfo eventInfo)
3236
var args = ev.ToJsValue(node.Context);
3337
_function.Call(sender, new [] { args });
3438
};
35-
eventInfo.AddEventHandler(node.Value, _handler);
39+
40+
if (eventInfo != null)
41+
{
42+
eventInfo.AddEventHandler(node.Value, _handler);
43+
}
3644
}
3745

3846
return arguments[0];

AngleSharp.Scripting.JavaScript/DomNodeInstance.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,38 @@
1111

1212
sealed class DomNodeInstance : ObjectInstance
1313
{
14-
readonly Object _value;
14+
readonly Type _type;
1515
readonly EngineInstance _engine;
16+
readonly Object _value;
17+
1618
PropertyInfo _numericIndexer;
1719
PropertyInfo _stringIndexer;
1820

1921
public DomNodeInstance(EngineInstance engine, Object value)
2022
: base(engine.Jint)
2123
{
24+
_type = value.GetType();
2225
_engine = engine;
2326
_value = value;
24-
SetAllMembers(value.GetType());
27+
28+
SetAllMembers();
29+
SetPseudoProperties();
2530

2631
// DOM objects can have properties added dynamically
2732
Extensible = true;
2833
Prototype = engine.Jint.Object;
2934
}
3035

36+
public Object Value
37+
{
38+
get { return _value; }
39+
}
40+
41+
public override String ToString()
42+
{
43+
return String.Format("[object {0}]", _type.Name);
44+
}
45+
3146
public EngineInstance Context
3247
{
3348
get { return _engine; }
@@ -70,8 +85,9 @@ public override PropertyDescriptor GetOwnProperty(String propertyName)
7085
return base.GetOwnProperty(propertyName);
7186
}
7287

73-
void SetAllMembers(Type type)
88+
void SetAllMembers()
7489
{
90+
var type = _type;
7591
var types = new List<Type>(type.GetInterfaces());
7692

7793
do
@@ -163,14 +179,33 @@ void SetMethods(IEnumerable<MethodInfo> methods)
163179
}
164180
}
165181

166-
public Object Value
167-
{
168-
get { return _value; }
169-
}
170-
171-
public override String ToString()
182+
void SetPseudoProperties()
172183
{
173-
return String.Format("[object {0}]", _value.GetType().Name);
184+
if (_type.GetInterfaces().Contains(typeof(AngleSharp.Dom.IElement)))
185+
{
186+
var focusInEventInstance = new DomEventInstance(this);
187+
var focusOutEventInstance = new DomEventInstance(this);
188+
var unloadEventInstance = new DomEventInstance(this);
189+
var contextMenuEventInstance = new DomEventInstance(this);
190+
191+
FastSetProperty("scrollLeft", new PropertyDescriptor(new JsValue(0.0), false, false, false));
192+
FastSetProperty("scrollTop", new PropertyDescriptor(new JsValue(0.0), false, false, false));
193+
FastSetProperty("scrollWidth", new PropertyDescriptor(new JsValue(0.0), false, false, false));
194+
FastSetProperty("scrollHeight", new PropertyDescriptor(new JsValue(0.0), false, false, false));
195+
FastSetProperty("clientLeft", new PropertyDescriptor(new JsValue(0.0), false, false, false));
196+
FastSetProperty("clientTop", new PropertyDescriptor(new JsValue(0.0), false, false, false));
197+
FastSetProperty("clientWidth", new PropertyDescriptor(new JsValue(0.0), false, false, false));
198+
FastSetProperty("clientHeight", new PropertyDescriptor(new JsValue(0.0), false, false, false));
199+
FastSetProperty("offsetLeft", new PropertyDescriptor(new JsValue(0.0), false, false, false));
200+
FastSetProperty("offsetTop", new PropertyDescriptor(new JsValue(0.0), false, false, false));
201+
FastSetProperty("offsetWidth", new PropertyDescriptor(new JsValue(0.0), false, false, false));
202+
FastSetProperty("offsetHeight", new PropertyDescriptor(new JsValue(0.0), false, false, false));
203+
204+
FastSetProperty("focusin", new PropertyDescriptor(focusInEventInstance.Getter, focusInEventInstance.Setter, false, false));
205+
FastSetProperty("focusout", new PropertyDescriptor(focusOutEventInstance.Getter, focusOutEventInstance.Setter, false, false));
206+
FastSetProperty("unload", new PropertyDescriptor(unloadEventInstance.Getter, unloadEventInstance.Setter, false, false));
207+
FastSetProperty("contextmenu", new PropertyDescriptor(contextMenuEventInstance.Getter, contextMenuEventInstance.Setter, false, false));
208+
}
174209
}
175210
}
176211
}

0 commit comments

Comments
 (0)