public JavaScriptValue Call(JavaScriptObject thisObject, IEnumerable<JavaScriptValue> args) { var eng = GetEngineAndClaimContext(); if (thisObject == null) thisObject = eng.NullValue; if (args == null) args = Enumerable.Empty<JavaScriptValue>(); var applyFn = GetBuiltinFunctionProperty("call", "Function.prototype.call"); return applyFn.Invoke(args.PrependWith(thisObject)); }
public JavaScriptFunction Bind(JavaScriptObject thisObject, IEnumerable<JavaScriptValue> args) { var eng = GetEngineAndClaimContext(); if (thisObject == null) thisObject = eng.NullValue; if (args == null) args = Enumerable.Empty<JavaScriptValue>(); var bindFn = GetBuiltinFunctionProperty("bind", "Function.prototype.bind"); return bindFn.Invoke(args.PrependWith(thisObject)) as JavaScriptFunction; }
public JavaScriptValue Call(JavaScriptObject thisObject, IEnumerable<JavaScriptValue> args) { var eng = GetEngine(); if (thisObject == null) thisObject = eng.NullValue; if (args == null) args = Enumerable.Empty<JavaScriptValue>(); var argsArray = args.PrependWith(thisObject).Select(v => v.handle_.DangerousGetHandle()).ToArray(); JavaScriptValueSafeHandle result; Errors.CheckForScriptExceptionOrThrow(api_.JsCallFunction(handle_, argsArray, unchecked((ushort)argsArray.Length), out result), eng); return eng.CreateValueFromHandle(result); }
public JavaScriptValue Apply(JavaScriptObject thisObject, JavaScriptArray args = null) { var eng = GetEngineAndClaimContext(); if (thisObject == null) thisObject = eng.NullValue; var applyFn = GetBuiltinFunctionProperty("apply", "Function.prototype.apply"); List<JavaScriptValue> resultList = new List<JavaScriptValue>(); resultList.Add(thisObject); if (args != null) resultList.Add(args); return applyFn.Invoke(resultList); }
private void ProjectEvents(string owningTypeName, JavaScriptObject target, JavaScriptEngine engine, IEnumerable<EventInfo> events, JavaScriptProjection baseTypeProjection, bool instance) { var eventsArray = events.ToArray(); var eventsLookup = eventsArray.ToDictionary(ei => ei.Name.ToLower()); // General approach here // if there is a base thing, invoke that // for each event, register a delegate that marshals it back to JavaScript var add = engine.CreateFunction((eng, ctor, thisObj, args) => { bool callBase = instance && (baseTypeProjection?.HasInstanceEvents ?? false); var @this = thisObj as JavaScriptObject; if (@this == null) return eng.UndefinedValue; if (callBase) { var baseObj = baseTypeProjection.Prototype; var baseFn = baseObj.GetPropertyByName("addEventListener") as JavaScriptFunction; if (baseFn != null) { baseFn.Call(@this, args); } } var argsArray = args.ToArray(); if (argsArray.Length < 2) return eng.UndefinedValue; string eventName = argsArray[0].ToString(); JavaScriptFunction callbackFunction = argsArray[1] as JavaScriptFunction; if (callbackFunction == null) return eng.UndefinedValue; EventInfo curEvent; if (!eventsLookup.TryGetValue(eventName, out curEvent)) return eng.UndefinedValue; MethodInfo targetMethod = curEvent.EventHandlerType.GetMethod("Invoke"); var paramsExpr = targetMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); int cookie = EventMarshaler.RegisterDelegate(callbackFunction, SynchronizationContext.Current); var marshaler = Expression.Lambda(curEvent.EventHandlerType, Expression.Block( Expression.Call( typeof(EventMarshaler).GetMethod(nameof(EventMarshaler.InvokeJavaScriptCallback)), Expression.Constant(cookie), Expression.NewArrayInit(typeof(string), targetMethod.GetParameters().Select(p => Expression.Constant(p.Name))), Expression.NewArrayInit(typeof(object), paramsExpr)) ), paramsExpr); curEvent.AddMethod.Invoke(@this.ExternalObject, new object[] { marshaler.Compile() }); return eng.UndefinedValue; }, owningTypeName + ".addEventListener"); target.SetPropertyByName("addEventListener", add); }
private void ProjectProperties(string owningTypeName, JavaScriptObject target, JavaScriptEngine engine, IEnumerable<PropertyInfo> properties) { foreach (var prop in properties) { if (prop.GetIndexParameters().Length > 0) throw new NotSupportedException("Index properties not supported for projecting CLR to JavaScript objects."); JavaScriptFunction jsGet = null, jsSet = null; if (prop.GetMethod != null) { jsGet = engine.CreateFunction((eng, ctor, thisObj, args) => { var @this = thisObj as JavaScriptObject; if (@this == null) { eng.SetException(eng.CreateTypeError("Could not retrieve property '" + prop.Name + "' because there was an invalid 'this' context.")); return eng.UndefinedValue; } try { return FromObject(prop.GetValue(@this.ExternalObject)); } catch (Exception ex) { eng.SetException(FromObject(ex)); return eng.UndefinedValue; } }, owningTypeName + "." + prop.Name + ".get"); } if (prop.SetMethod != null) { jsSet = engine.CreateFunction((eng, ctor, thisObj, args) => { var @this = thisObj as JavaScriptObject; if (@this == null) { eng.SetException(eng.CreateTypeError("Could not retrieve property '" + prop.Name + "' because there was an invalid 'this' context.")); return eng.UndefinedValue; } try { var val = ToObject(args.First()); if (prop.PropertyType == typeof(int)) { val = (int)(double)val; } prop.SetValue(@this.ExternalObject, val); return eng.UndefinedValue; } catch (Exception ex) { eng.SetException(FromObject(ex)); return eng.UndefinedValue; } }, owningTypeName + "." + prop.Name + ".set"); } var descriptor = engine.CreateObject(); if (jsGet != null) descriptor.SetPropertyByName("get", jsGet); if (jsSet != null) descriptor.SetPropertyByName("set", jsSet); descriptor.SetPropertyByName("enumerable", engine.TrueValue); target.DefineProperty(prop.Name, descriptor); } }
private void ProjectMethods(string owningTypeName, JavaScriptObject target, JavaScriptEngine engine, IEnumerable<MethodInfo> methods) { var methodsByName = methods.GroupBy(m => m.Name); foreach (var group in methodsByName) { var method = engine.CreateFunction((eng, ctor, thisObj, args) => { var @this = thisObj as JavaScriptObject; if (@this == null) { eng.SetException(eng.CreateTypeError("Could not call method '" + group.Key + "' because there was an invalid 'this' context.")); return eng.UndefinedValue; } var argsArray = args.ToArray(); var candidate = GetBestFitMethod(group, thisObj, argsArray); if (candidate == null) { eng.SetException(eng.CreateReferenceError("Could not find suitable method or not enough arguments to invoke '" + group.Key + "'.")); return eng.UndefinedValue; } List<object> argsToPass = new List<object>(); for (int i = 0; i < candidate.GetParameters().Length; i++) { argsToPass.Add(ToObject(argsArray[i])); } try { return FromObject(candidate.Invoke(@this.ExternalObject, argsToPass.ToArray())); } catch (Exception ex) { eng.SetException(FromObject(ex)); return eng.UndefinedValue; } }, owningTypeName + "." + group.Key); //var propDescriptor = engine.CreateObject(); //propDescriptor.SetPropertyByName("configurable", engine.TrueValue); //propDescriptor.SetPropertyByName("enumerable", engine.TrueValue); //propDescriptor.SetPropertyByName("value", method); //target.DefineProperty(group.Key, propDescriptor); target.SetPropertyByName(group.Key, method); } }
public JavaScriptObject CreateObject(JavaScriptObject prototype = null) { ClaimContext(); JavaScriptValueSafeHandle handle; Errors.ThrowIfIs(api_.JsCreateObject(out handle)); if (prototype != null) { Errors.ThrowIfIs(api_.JsSetPrototype(handle, prototype.handle_)); } return CreateObjectFromHandle(handle); }
public void DefineProperties(JavaScriptObject propertiesContainer) { var eng = GetEngine(); var fnDP = GetObjectBuiltinFunction("defineProperties", "Object.defineProperties"); fnDP.Invoke(new JavaScriptValue[] { eng.UndefinedValue, this, propertiesContainer }); }
public void DefineProperty(string propertyName, JavaScriptObject descriptor) { if (descriptor == null) throw new ArgumentNullException(nameof(descriptor)); var eng = GetEngine(); IntPtr propId; Errors.ThrowIfIs(api_.JsGetPropertyIdFromName(propertyName, out propId)); bool wasSet; Errors.CheckForScriptExceptionOrThrow(api_.JsDefineProperty(handle_, propId, descriptor.handle_, out wasSet), eng); }
public bool IsPrototypeOf(JavaScriptObject other) { if (other == null) throw new ArgumentNullException(nameof(other)); var eng = GetEngine(); var fn = GetBuiltinFunctionProperty("isPrototypeOf", "Object.prototype.isPrototypeOf"); var args = new List<JavaScriptValue>() { this, other }; return eng.Converter.ToBoolean(fn.Invoke(args)); }
private void ProjectEvents(string owningTypeName, JavaScriptObject target, JavaScriptEngine engine, IEnumerable <EventInfo> events, JavaScriptProjection baseTypeProjection, bool instance) { var eventsArray = events.ToArray(); var eventsLookup = eventsArray.ToDictionary(ei => ei.Name.ToLower()); // General approach here // if there is a base thing, invoke that // for each event, register a delegate that marshals it back to JavaScript var add = engine.CreateFunction((eng, ctor, thisObj, args) => { bool callBase = instance && (baseTypeProjection?.HasInstanceEvents ?? false); var @this = thisObj as JavaScriptObject; if (@this == null) { return(eng.UndefinedValue); } if (callBase) { var baseObj = baseTypeProjection.Prototype; var baseFn = baseObj.GetPropertyByName("addEventListener") as JavaScriptFunction; if (baseFn != null) { baseFn.Call(@this, args); } } var argsArray = args.ToArray(); if (argsArray.Length < 2) { return(eng.UndefinedValue); } string eventName = argsArray[0].ToString(); JavaScriptFunction callbackFunction = argsArray[1] as JavaScriptFunction; if (callbackFunction == null) { return(eng.UndefinedValue); } EventInfo curEvent; if (!eventsLookup.TryGetValue(eventName, out curEvent)) { return(eng.UndefinedValue); } MethodInfo targetMethod = curEvent.EventHandlerType.GetMethod("Invoke"); var paramsExpr = targetMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); int cookie = EventMarshaler.RegisterDelegate(callbackFunction, SynchronizationContext.Current); var marshaler = Expression.Lambda(curEvent.EventHandlerType, Expression.Block( Expression.Call( typeof(EventMarshaler).GetMethod(nameof(EventMarshaler.InvokeJavaScriptCallback)), Expression.Constant(cookie), Expression.NewArrayInit(typeof(string), targetMethod.GetParameters().Select(p => Expression.Constant(p.Name))), Expression.NewArrayInit(typeof(object), paramsExpr)) ), paramsExpr); curEvent.AddMethod.Invoke(@this.ExternalObject, new object[] { marshaler.Compile() }); return(eng.UndefinedValue); }, owningTypeName + ".addEventListener"); target.SetPropertyByName("addEventListener", add); }
private void ProjectProperties(string owningTypeName, JavaScriptObject target, JavaScriptEngine engine, IEnumerable <PropertyInfo> properties) { foreach (var prop in properties) { if (prop.GetIndexParameters().Length > 0) { throw new NotSupportedException("Index properties not supported for projecting CLR to JavaScript objects."); } JavaScriptFunction jsGet = null, jsSet = null; if (prop.GetMethod != null) { jsGet = engine.CreateFunction((eng, ctor, thisObj, args) => { var @this = thisObj as JavaScriptObject; if (@this == null) { eng.SetException(eng.CreateTypeError("Could not retrieve property '" + prop.Name + "' because there was an invalid 'this' context.")); return(eng.UndefinedValue); } try { return(FromObject(prop.GetValue(@this.ExternalObject))); } catch (Exception ex) { eng.SetException(FromObject(ex)); return(eng.UndefinedValue); } }, owningTypeName + "." + prop.Name + ".get"); } if (prop.SetMethod != null) { jsSet = engine.CreateFunction((eng, ctor, thisObj, args) => { var @this = thisObj as JavaScriptObject; if (@this == null) { eng.SetException(eng.CreateTypeError("Could not retrieve property '" + prop.Name + "' because there was an invalid 'this' context.")); return(eng.UndefinedValue); } try { var val = ToObject(args.First()); if (prop.PropertyType == typeof(int)) { val = (int)(double)val; } prop.SetValue(@this.ExternalObject, val); return(eng.UndefinedValue); } catch (Exception ex) { eng.SetException(FromObject(ex)); return(eng.UndefinedValue); } }, owningTypeName + "." + prop.Name + ".set"); } var descriptor = engine.CreateObject(); if (jsGet != null) { descriptor.SetPropertyByName("get", jsGet); } if (jsSet != null) { descriptor.SetPropertyByName("set", jsSet); } descriptor.SetPropertyByName("enumerable", engine.TrueValue); target.DefineProperty(prop.Name, descriptor); } }