Esempio n. 1
0
        public object ConvertToJs(object obj)
        {
            if (obj == null)
            {
                return(Null.Value);
            }

            if (obj == _globalFn())
            {
                return(_engine.Global);
            }

            if (obj is int || obj is double || obj is ushort || obj is short || obj is float || obj is decimal || obj is long || obj is ulong)
            {
                return(Convert.ToDouble(obj));
            }

            if (obj is string || obj is bool)
            {
                return(obj);
            }

            if (obj is IRawJson json)
            {
                try
                {
                    var x           = (JSONObject)Engine.Global["JSON"];
                    var parseMethod = (FunctionInstance)x["parse"];
                    return(parseMethod.Call(x, json.JsonString));
                }
                catch
                {
                    return(Null.Value);
                }
            }

            if (_clrToJsObjects.TryGetValue(obj, out var jsObj))
            {
                return(jsObj);
            }

            //todo: check if the func and action are necessary
            if (obj is Func <object, object> func)
            {
                jsObj = new FuncInst(this, func);
            }
            else if (obj is Action <object, object[]> actObjs)
            {
                jsObj = new ActInst(this, actObjs);
            }
            else
            {
                jsObj = new ClrObjectInstance(this, obj, GetPrototype(obj.GetType()));
            }

            RegisterMap(obj, jsObj);

            return(jsObj);
        }
Esempio n. 2
0
        /// <summary>
        /// Adds properties to the specified js object from the specified clr object.
        /// </summary>
        public static void DefineProperties(this ObjectInstance jsObject, ClrTypeConverter ctx, Type type, object clrOwner = null)
        {
            var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;

            //register properties
            foreach (var property in type.GetProperties(bindingFlags).Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null))
            {
                var name = property.GetName();

                //todo: compile delegate instead of reflection, research what is faster.

                var jsGetter =
                    property.GetMethod != null && property.GetMethod.IsPublic ? new FuncInst(ctx, clrThis => property.GetValue(clrThis)) : null;

                var jsSetter =
                    property.SetMethod != null && property.SetMethod.IsPublic ? new ActInst(ctx, (clrThis, objects) =>
                                                                                            property.SetValue(clrThis, ctx.ConvertToClr(objects[0], property.PropertyType, ctx.ConvertToJs(clrThis)))) : null;

                var jsProperty = new PropertyDescriptor(jsGetter, jsSetter, PropertyAttributes.Configurable);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //register methods
            foreach (var methods in type
                     .GetMethods(bindingFlags)
                     .Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null &&
                            p.GetCustomAttribute <JsCtorAttribute>() == null)
                     .GroupBy(p => p.GetName()))
            {
                var methodsArray = methods.ToArray();

                var firstMethod = methodsArray[0];

                if (firstMethod.IsSpecialName)
                {
                    continue;
                }

                if (firstMethod.DeclaringType == typeof(object))
                {
                    continue;
                }

                var name = methods.Key;

                var jsMethod =
                    methodsArray.Length == 1
                        ? new ClrMethodInstance(ctx, clrOwner, firstMethod, name)
                        : (FunctionInstance) new ClrOverloadMethodInstance(ctx, clrOwner, methodsArray, name);

                //todo: check the PropertyAttributes
                var jsProperty = new PropertyDescriptor(jsMethod, PropertyAttributes.Sealed);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //register events
            foreach (var evt in type.GetEvents(bindingFlags)
                     .Where(p => p.GetCustomAttribute <JsHiddenAttribute>() == null))
            {
                var name = evt.GetName().ToLowerInvariant();

                var jsGetter = new FuncInst(ctx, clrThis =>
                {
                    var attachedEvents = ctx.GetAttachedEventsFor(clrThis);
                    return(attachedEvents[evt]);
                }, false);

                var jsSetter = new ActInst(ctx,
                                           (clrThis, args) =>
                {
                    var jsThis = ctx.ConvertToJs(clrThis);

                    var attachedEvents = ctx.GetAttachedEventsFor(clrThis);

                    if (attachedEvents.TryGetValue(evt, out var existHandler))
                    {
                        var clrHandler = ctx.ConvertToClr(existHandler, evt.EventHandlerType, jsThis);
                        evt.RemoveMethod.Invoke(clrThis, new [] { clrHandler });
                        attachedEvents.Remove(evt);
                    }

                    if (args.Length != 0 && args[0] is FunctionInstance functionInstance)
                    {
                        var clrHandler = ctx.ConvertToClr(args[0], evt.EventHandlerType, jsThis);
                        evt.AddMethod.Invoke(clrThis, new[] { clrHandler });
                        attachedEvents[evt] = functionInstance;
                    }
                });

                var jsProperty = new PropertyDescriptor(jsGetter, jsSetter, PropertyAttributes.Configurable);

                jsObject.DefineProperty(name, jsProperty, false);
            }

            //Register static fields
            DefineStaticProperties(jsObject, ctx, type);
        }