public DomEventInstance(DomNodeInstance node, EventInfo eventInfo) { Getter = new ClrFunctionInstance(node.Engine, (thisObject, arguments) => _function ?? JsValue.Null); Setter = new ClrFunctionInstance(node.Engine, (thisObject, arguments) => { if (_handler != null) { eventInfo.RemoveEventHandler(node.Value, _handler); _handler = null; _function = null; } if (arguments[0].Is<FunctionInstance>()) { _function = arguments[0].As<FunctionInstance>(); _handler = (s, ev) => { var sender = s.ToJsValue(node.Context); var args = ev.ToJsValue(node.Context); _function.Call(sender, new [] { args }); }; eventInfo.AddEventHandler(node.Value, _handler); } return arguments[0]; }); }
public override PropertyDescriptor GetOwnProperty(JsValue property) { if (TryGetProperty(property, out var x)) { return(x); } // if we have array-like or dictionary or expando, we can provide iterator if (property.IsSymbol() && property == GlobalSymbolRegistry.Iterator && _typeDescriptor.Iterable) { var iteratorFunction = new ClrFunctionInstance( Engine, "iterator", Iterator, 1, PropertyFlag.Configurable); var iteratorProperty = new PropertyDescriptor(iteratorFunction, PropertyFlag.Configurable | PropertyFlag.Writable); SetProperty(GlobalSymbolRegistry.Iterator, iteratorProperty); return(iteratorProperty); } var member = property.ToString(); // if type is dictionary, we cannot enumerate anything other than keys // and we cannot store accessors as dictionary can change dynamically var isDictionary = _typeDescriptor.IsStringKeyedGenericDictionary; if (isDictionary) { if (_typeDescriptor.TryGetValue(Target, member, out var value)) { return(new PropertyDescriptor(FromObject(_engine, value), PropertyFlag.OnlyEnumerable)); } } var result = Engine.Options.Interop.MemberAccessor(Engine, Target, member); if (result is not null) { return(new PropertyDescriptor(result, PropertyFlag.OnlyEnumerable)); } var accessor = _engine.Options.Interop.TypeResolver.GetAccessor(_engine, Target.GetType(), member); var descriptor = accessor.CreatePropertyDescriptor(_engine, Target, enumerable: !isDictionary); if (!isDictionary) { SetProperty(member, descriptor); } return(descriptor); }
public ObjectWrapper(Engine engine, object obj) : base(engine) { Target = obj; _typeDescriptor = TypeDescriptor.Get(obj.GetType()); if (_typeDescriptor.LengthProperty is not null) { // create a forwarder to produce length from Count or Length if one of them is present var functionInstance = new ClrFunctionInstance(engine, "length", GetLength); var descriptor = new GetSetPropertyDescriptor(functionInstance, Undefined, PropertyFlag.Configurable); SetProperty(KnownKeys.Length, descriptor); } }
public ObjectWrapper(Engine engine, object obj) : base(engine) { Target = obj; var type = obj.GetType(); if (ObjectIsArrayLikeClrCollection(type)) { // create a forwarder to produce length from Count or Length if one of them is present var lengthProperty = type.GetProperty("Count") ?? type.GetProperty("Length"); if (lengthProperty is null) { return; } IsArrayLike = true; var functionInstance = new ClrFunctionInstance(engine, "length", (thisObj, arguments) => JsNumber.Create((int)lengthProperty.GetValue(obj))); var descriptor = new GetSetPropertyDescriptor(functionInstance, Undefined, PropertyFlag.Configurable); SetProperty(KnownKeys.Length, descriptor); } }
private JsValue Replace(JsValue thisObj, JsValue[] arguments) { TypeConverter.CheckObjectCoercible(Engine, thisObj); var thisString = TypeConverter.ToString(thisObj); var searchValue = arguments.At(0); var replaceValue = arguments.At(1); // If the second parameter is not a function we create one var replaceFunction = replaceValue.TryCast<FunctionInstance>(); if (replaceFunction == null) { replaceFunction = new ClrFunctionInstance(Engine, (self, args) => { var replaceString = TypeConverter.ToString(replaceValue); var matchValue = TypeConverter.ToString(args.At(0)); var matchIndex = (int)TypeConverter.ToInteger(args.At(args.Length - 2)); // Check if the replacement string contains any patterns. bool replaceTextContainsPattern = replaceString.IndexOf('$') >= 0; // If there is no pattern, replace the pattern as is. if (replaceTextContainsPattern == false) return replaceString; // Patterns // $$ Inserts a "$". // $& Inserts the matched substring. // $` Inserts the portion of the string that precedes the matched substring. // $' Inserts the portion of the string that follows the matched substring. // $n or $nn Where n or nn are decimal digits, inserts the nth parenthesized submatch string, provided the first argument was a RegExp object. var replacementBuilder = new StringBuilder(); for (int i = 0; i < replaceString.Length; i++) { char c = replaceString[i]; if (c == '$' && i < replaceString.Length - 1) { c = replaceString[++i]; if (c == '$') replacementBuilder.Append('$'); else if (c == '&') replacementBuilder.Append(matchValue); else if (c == '`') replacementBuilder.Append(thisString.Substring(0, matchIndex)); else if (c == '\'') replacementBuilder.Append(thisString.Substring(matchIndex + matchValue.Length)); else if (c >= '0' && c <= '9') { int matchNumber1 = c - '0'; // The match number can be one or two digits long. int matchNumber2 = 0; if (i < replaceString.Length - 1 && replaceString[i + 1] >= '0' && replaceString[i + 1] <= '9') matchNumber2 = matchNumber1 * 10 + (replaceString[i + 1] - '0'); // Try the two digit capture first. if (matchNumber2 > 0 && matchNumber2 < args.Length - 2) { // Two digit capture replacement. replacementBuilder.Append(TypeConverter.ToString(args[matchNumber2])); i++; } else if (matchNumber1 > 0 && matchNumber1 < args.Length - 2) { // Single digit capture replacement. replacementBuilder.Append(TypeConverter.ToString(args[matchNumber1])); } else { // Capture does not exist. replacementBuilder.Append('$'); i--; } } else { // Unknown replacement pattern. replacementBuilder.Append('$'); replacementBuilder.Append(c); } } else replacementBuilder.Append(c); } return replacementBuilder.ToString(); }); } // searchValue is a regular expression if (searchValue.IsNull()) { searchValue = new JsValue(Null.Text); } if (searchValue.IsUndefined()) { searchValue = new JsValue(Undefined.Text); } var rx = TypeConverter.ToObject(Engine, searchValue) as RegExpInstance; if (rx != null) { // Replace the input string with replaceText, recording the last match found. string result = rx.Value.Replace(thisString, match => { var args = new List<JsValue>(); for (var k = 0; k < match.Groups.Count; k++) { var group = match.Groups[k]; args.Add(group.Value); } args.Add(match.Index); args.Add(thisString); var v = TypeConverter.ToString(replaceFunction.Call(Undefined.Instance, args.ToArray())); return v; }, rx.Global == true ? -1 : 1); // Set the deprecated RegExp properties if at least one match was found. //if (lastMatch != null) // this.Engine.RegExp.SetDeprecatedProperties(input, lastMatch); return result; } // searchValue is a string else { var substr = TypeConverter.ToString(searchValue); // Find the first occurrance of substr. int start = thisString.IndexOf(substr, StringComparison.Ordinal); if (start == -1) return thisString; int end = start + substr.Length; var args = new List<JsValue>(); args.Add(substr); args.Add(start); args.Add(thisString); var replaceString = TypeConverter.ToString(replaceFunction.Call(Undefined.Instance, args.ToArray())); // Replace only the first match. var result = new StringBuilder(thisString.Length + (substr.Length - substr.Length)); result.Append(thisString, 0, start); result.Append(replaceString); result.Append(thisString, end, thisString.Length - end); return result.ToString(); } }
public MethodInfoFunctionInstance(Engine engine, MethodDescriptor[] methods, ClrFunctionInstance fallbackClrFunctionInstance) : this(engine, methods) { _fallbackClrFunctionInstance = fallbackClrFunctionInstance; }