Skip to content

Commit ee0396b

Browse files
committed
Introduced extensibility
1 parent 5ff9ec5 commit ee0396b

9 files changed

Lines changed: 427 additions & 109 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace AngleSharp.Js.Tests
2+
{
3+
using NUnit.Framework;
4+
using System.Threading.Tasks;
5+
6+
[TestFixture]
7+
public class EcoTests
8+
{
9+
[Test]
10+
public async Task GetCssSheetRuleFromJavaScript()
11+
{
12+
var config = Configuration.Default.WithCss().WithJs();
13+
var context = BrowsingContext.New(config);
14+
var style = "body { color: red; }";
15+
var script = "var sheet = document.querySelector('style').sheet; var color = sheet.cssRules[0].style.color; document.querySelector('div').textContent = color;";
16+
var document = await context.OpenAsync(r => r.Content($"<style>{style}</style><div></div><script>{script}</script>"));
17+
Assert.AreEqual("rgba(255, 0, 0, 1)", document.QuerySelector("div").TextContent);
18+
}
19+
}
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace AngleSharp.Attributes
2+
{
3+
using System;
4+
5+
/// <summary>
6+
/// Represents an event setter.
7+
/// </summary>
8+
[AttributeUsage(AttributeTargets.Method)]
9+
sealed class DomEventAttribute : Attribute
10+
{
11+
}
12+
}

src/AngleSharp.Js/Cache/PrototypeCache.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ public PrototypeCache(Engine engine)
1414
{
1515
_prototypes = new ConcurrentDictionary<Type, ObjectInstance>
1616
{
17-
[typeof(Object)] = engine.Object.PrototypeObject
17+
[typeof(Object)] = engine.Object.PrototypeObject,
1818
};
1919
_engine = engine;
2020
}
2121

22-
public ObjectInstance GetOrCreate(Type type, Func<Type, ObjectInstance> creator)
23-
{
24-
return _prototypes.GetOrAdd(type, creator.Invoke);
25-
}
22+
public ObjectInstance GetOrCreate(Type type, Func<Type, ObjectInstance> creator) =>
23+
_prototypes.GetOrAdd(type, creator.Invoke);
2624
}
2725
}

src/AngleSharp.Js/Cache/ReferenceCache.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ public ReferenceCache()
1212
_references = new ConditionalWeakTable<Object, DomNodeInstance>();
1313
}
1414

15-
public DomNodeInstance GetOrCreate(Object obj, Func<Object, DomNodeInstance> creator)
16-
{
17-
return _references.GetValue(obj, creator.Invoke);
18-
}
15+
public DomNodeInstance GetOrCreate(Object obj, Func<Object, DomNodeInstance> creator) =>
16+
_references.GetValue(obj, creator.Invoke);
1917
}
2018
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
namespace AngleSharp.Js
2+
{
3+
using AngleSharp.Attributes;
4+
using AngleSharp.Dom;
5+
using System;
6+
7+
/// <summary>
8+
/// A set of stub implementations.
9+
/// </summary>
10+
[DomExposed("Element")]
11+
public static class ElementPseudoExtensions
12+
{
13+
/// <summary>
14+
/// Getter for the scrollLeft property.
15+
/// </summary>
16+
[DomName("scrollLeft")]
17+
[DomAccessor(Accessors.Getter)]
18+
public static Double GetScrollLeft(this IElement element) => 0.0;
19+
20+
/// <summary>
21+
/// Getter for the scrollTop property.
22+
/// </summary>
23+
[DomName("scrollTop")]
24+
[DomAccessor(Accessors.Getter)]
25+
public static Double GetScrollTop(this IElement element) => 0.0;
26+
27+
/// <summary>
28+
/// Getter for the scrollWidth property.
29+
/// </summary>
30+
[DomName("scrollWidth")]
31+
[DomAccessor(Accessors.Getter)]
32+
public static Double GetScrollWidth(this IElement element) => 0.0;
33+
34+
/// <summary>
35+
/// Getter for the scrollHeight property.
36+
/// </summary>
37+
[DomName("scrollHeight")]
38+
[DomAccessor(Accessors.Getter)]
39+
public static Double GetScrollHeight(this IElement element) => 0.0;
40+
41+
/// <summary>
42+
/// Getter for the clientLeft property.
43+
/// </summary>
44+
[DomName("clientLeft")]
45+
[DomAccessor(Accessors.Getter)]
46+
public static Double GetClientLeft(this IElement element) => 0.0;
47+
48+
/// <summary>
49+
/// Getter for the clientTop property.
50+
/// </summary>
51+
[DomName("clientTop")]
52+
[DomAccessor(Accessors.Getter)]
53+
public static Double GetClientTop(this IElement element) => 0.0;
54+
55+
/// <summary>
56+
/// Getter for the clientWidth property.
57+
/// </summary>
58+
[DomName("clientWidth")]
59+
[DomAccessor(Accessors.Getter)]
60+
public static Double GetClientWidth(this IElement element) => 0.0;
61+
62+
/// <summary>
63+
/// Getter for the clientHeight property.
64+
/// </summary>
65+
[DomName("clientHeight")]
66+
[DomAccessor(Accessors.Getter)]
67+
public static Double GetClientHeight(this IElement element) => 0.0;
68+
69+
/// <summary>
70+
/// Getter for the offsetLeft property.
71+
/// </summary>
72+
[DomName("offsetLeft")]
73+
[DomAccessor(Accessors.Getter)]
74+
public static Double GetOffsetLeft(this IElement element) => 0.0;
75+
76+
/// <summary>
77+
/// Getter for the offsetTop property.
78+
/// </summary>
79+
[DomName("offsetTop")]
80+
[DomAccessor(Accessors.Getter)]
81+
public static Double GetOffsetTop(this IElement element) => 0.0;
82+
83+
/// <summary>
84+
/// Getter for the offsetWidth property.
85+
/// </summary>
86+
[DomName("offsetWidth")]
87+
[DomAccessor(Accessors.Getter)]
88+
public static Double GetOffsetWidth(this IElement element) => 0.0;
89+
90+
/// <summary>
91+
/// Getter for the offsetHeight property.
92+
/// </summary>
93+
[DomName("offsetHeight")]
94+
[DomAccessor(Accessors.Getter)]
95+
public static Double GetOffsetHeight(this IElement element) => 0.0;
96+
97+
/// <summary>
98+
/// Adds the focus in event.
99+
/// </summary>
100+
[DomName("focusin")]
101+
[DomEvent]
102+
[DomAccessor(Accessors.Setter)]
103+
public static void AddFocusIn(this IElement element, DomEventHandler handler) =>
104+
element.AddEventListener("focusin", handler);
105+
106+
/// <summary>
107+
/// Removes the focus in event.
108+
/// </summary>
109+
[DomName("focusin")]
110+
[DomEvent]
111+
[DomAccessor(Accessors.Deleter)]
112+
public static void RemoveFocusIn(this IElement element, DomEventHandler handler) =>
113+
element.RemoveEventListener("focusin", handler);
114+
115+
/// <summary>
116+
/// Adds the focus out event.
117+
/// </summary>
118+
[DomName("focusout")]
119+
[DomEvent]
120+
[DomAccessor(Accessors.Setter)]
121+
public static void AddFocusOut(this IElement element, DomEventHandler handler) =>
122+
element.AddEventListener("focusout", handler);
123+
124+
/// <summary>
125+
/// Removes the focus out event.
126+
/// </summary>
127+
[DomName("focusout")]
128+
[DomEvent]
129+
[DomAccessor(Accessors.Deleter)]
130+
public static void RemoveFocusOut(this IElement element, DomEventHandler handler) =>
131+
element.RemoveEventListener("focusout", handler);
132+
133+
/// <summary>
134+
/// Adds the unload event.
135+
/// </summary>
136+
[DomName("unload")]
137+
[DomEvent]
138+
[DomAccessor(Accessors.Setter)]
139+
public static void AddUnload(this IElement element, DomEventHandler handler) =>
140+
element.AddEventListener("unload", handler);
141+
142+
/// <summary>
143+
/// Removes the unload event.
144+
/// </summary>
145+
[DomName("unload")]
146+
[DomEvent]
147+
[DomAccessor(Accessors.Deleter)]
148+
public static void RemoveUnload(this IElement element, DomEventHandler handler) =>
149+
element.RemoveEventListener("unload", handler);
150+
151+
/// <summary>
152+
/// Adds the contextmenu event.
153+
/// </summary>
154+
[DomName("contextmenu")]
155+
[DomEvent]
156+
[DomAccessor(Accessors.Setter)]
157+
public static void AddContextMenu(this IElement element, DomEventHandler handler) =>
158+
element.AddEventListener("contextmenu", handler);
159+
160+
/// <summary>
161+
/// Removes the contextmenu event.
162+
/// </summary>
163+
[DomName("contextmenu")]
164+
[DomEvent]
165+
[DomAccessor(Accessors.Deleter)]
166+
public static void RemoveContextMenu(this IElement element, DomEventHandler handler) =>
167+
element.RemoveEventListener("contextmenu", handler);
168+
}
169+
}

src/AngleSharp.Js/Extensions/EngineExtensions.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace AngleSharp.Js
99
using Jint.Runtime.Descriptors;
1010
using Jint.Runtime.Interop;
1111
using System;
12+
using System.Collections.Generic;
1213
using System.Linq;
1314
using System.Reflection;
1415

@@ -188,8 +189,21 @@ public static JsValue Call(this EngineInstance instance, MethodInfo method, JsVa
188189
{
189190
try
190191
{
191-
var parameters = instance.BuildArgs(method, arguments);
192-
return method.Invoke(node.Value, parameters).ToJsValue(instance);
192+
if (method.IsStatic)
193+
{
194+
var newArgs = new List<JsValue>
195+
{
196+
thisObject,
197+
};
198+
newArgs.AddRange(arguments);
199+
var parameters = instance.BuildArgs(method, newArgs.ToArray());
200+
return method.Invoke(null, parameters).ToJsValue(instance);
201+
}
202+
else
203+
{
204+
var parameters = instance.BuildArgs(method, arguments);
205+
return method.Invoke(node.Value, parameters).ToJsValue(instance);
206+
}
193207
}
194208
catch (TargetInvocationException)
195209
{

src/AngleSharp.Js/Extensions/ReflectionExtensions.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace AngleSharp.Js
22
{
33
using AngleSharp.Attributes;
4+
using AngleSharp.Text;
45
using System;
56
using System.Collections.Generic;
67
using System.Linq;
@@ -17,6 +18,31 @@ public static String[] GetParameterNames(this MethodInfo method) =>
1718
public static Object GetDefaultValue(this Type type) =>
1819
type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null;
1920

21+
public static IEnumerable<Type> GetExtensionTypes(this String name)
22+
{
23+
return AppDomain.CurrentDomain
24+
.GetAssemblies()
25+
.Where(m => m.FullName.StartsWith("AngleSharp"))
26+
.SelectMany(m => m.ExportedTypes)
27+
.Where(m => m.GetCustomAttributes<DomExposedAttribute>().Any(n => n.Target.Is(name)))
28+
.ToArray();
29+
}
30+
31+
public static IEnumerable<Type> GetTypeTree(this Type root)
32+
{
33+
var type = root;
34+
var types = new List<Type>(type.GetTypeInfo().ImplementedInterfaces);
35+
36+
do
37+
{
38+
types.Add(type);
39+
type = type.GetTypeInfo().BaseType;
40+
}
41+
while (type != null);
42+
43+
return types;
44+
}
45+
2046
public static MethodInfo PrepareConvert(this Type fromType, Type toType)
2147
{
2248
try

src/AngleSharp.Js/Proxies/DomEventInstance.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ namespace AngleSharp.Js
44
using Jint.Native;
55
using Jint.Native.Function;
66
using Jint.Runtime.Interop;
7+
using System;
78
using System.Reflection;
89

910
sealed class DomEventInstance
1011
{
1112
private readonly EngineInstance _engine;
12-
private readonly EventInfo _eventInfo;
13+
private readonly MethodInfo _addHandler;
14+
private readonly MethodInfo _removeHandler;
1315
private DomEventHandler _handler;
1416
private FunctionInstance _function;
1517

16-
public DomEventInstance(EngineInstance engine, EventInfo eventInfo = null)
18+
public DomEventInstance(EngineInstance engine, MethodInfo addHandler, MethodInfo removeHandler)
1719
{
1820
_engine = engine;
19-
_eventInfo = eventInfo;
21+
_addHandler = addHandler;
22+
_removeHandler = removeHandler;
2023
Getter = new ClrFunctionInstance(engine.Jint, GetEventHandler);
2124
Setter = new ClrFunctionInstance(engine.Jint, SetEventHandler);
2225
}
@@ -25,10 +28,8 @@ public DomEventInstance(EngineInstance engine, EventInfo eventInfo = null)
2528

2629
public ClrFunctionInstance Setter { get; }
2730

28-
private JsValue GetEventHandler(JsValue thisObject, JsValue[] arguments)
29-
{
30-
return _function ?? JsValue.Null;
31-
}
31+
private JsValue GetEventHandler(JsValue thisObject, JsValue[] arguments) =>
32+
_function ?? JsValue.Null;
3233

3334
private JsValue SetEventHandler(JsValue thisObject, JsValue[] arguments)
3435
{
@@ -38,7 +39,7 @@ private JsValue SetEventHandler(JsValue thisObject, JsValue[] arguments)
3839
{
3940
if (_handler != null)
4041
{
41-
_eventInfo?.RemoveEventHandler(node.Value, _handler);
42+
_removeHandler?.Invoke(node.Value, new Object[] { _handler });
4243
_handler = null;
4344
_function = null;
4445
}
@@ -53,7 +54,7 @@ private JsValue SetEventHandler(JsValue thisObject, JsValue[] arguments)
5354
_function.Call(sender, new[] { args });
5455
};
5556

56-
_eventInfo?.AddEventHandler(node.Value, _handler);
57+
_addHandler?.Invoke(node.Value, new Object[] { _handler });
5758
}
5859
}
5960

0 commit comments

Comments
 (0)