public void Dispose(JSWrapper et)
        {
            try
            {
                Element e = et.As <Element>();
                WAContext.SetAtomControl(e, null);
                WAContext.SetLogicalParent(e, null);
                WAContext.SetTemplateParent(e, null);

                //if (e is Page page)
                //{
                //    // we need to remove this page if the page is on the stack...
                //    try
                //    {
                //        // WAContext.(page);
                //    }
                //    catch (Exception ex)
                //    {
                //        System.Diagnostics.Debug.WriteLine(ex);
                //    }
                //}
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex);
            }
        }
        public JSDisposable WatchProperty(JSWrapper objTarget, string name, JSValue events, JSFunction callback)
        {
            object obj = objTarget.As <object>();

            if (obj is INotifyPropertyChanged element)
            {
                var pinfo = obj.GetProperty(name);

                PropertyChangedEventHandler handler = (s, e) =>
                {
                    if (e.PropertyName == name)
                    {
                        var value = pinfo.GetValue(obj);
                        callback.Call(null, new Java.Lang.Object[] { value.Wrap(Engine) });
                    }
                };

                element.PropertyChanged += handler;
                return(new JSDisposable(Engine, () =>
                {
                    element.PropertyChanged -= handler;
                }));
            }

            return(new JSDisposable(Engine, () => { }));
        }
        public void VisitDescendents(JSWrapper target, JSFunction action)
        {
            Element element = target?.As <Element>();

            if (element == null)
            {
                throw new ObjectDisposedException("Cannot visit descendents of null");
            }

            var views = element as IViewContainer <View>;

            if (views == null)
            {
                return;
            }
            foreach (var e in views.Children)
            {
                var ac    = WAContext.GetAtomControl(e);
                var child = e.Wrap(Engine);
                var r     = action.Call(null, new Java.Lang.Object[] {
                    child,
                    (JSValue)ac
                });
                if ((bool)r.IsUndefined() || (bool)r.IsNull() || !((bool)r.ToBoolean()))
                {
                    continue;
                }
                VisitDescendents(JSWrapper.Register(e), action);
            }
        }
        public JSValue AtomParent(JSWrapper target, JSValue climbUp)
        {
            Element element = target.As <Element>();

            bool cu = !((bool)climbUp.IsUndefined()) && !((bool)climbUp.IsNull()) && (bool)climbUp.ToBoolean();

            if (cu)
            {
                element = element.Parent;
                if (element == null)
                {
                    return(null);
                }
            }
            do
            {
                var e = WAContext.GetAtomControl(element);
                if (e != null)
                {
                    return(e.Wrap(Engine));
                }
                element = element.Parent;
            } while (cu && element != null);
            return(null);
        }
        public void SetTemplate(JSWrapper elementWrapper, string name, JSFunction factory)
        {
            var          element = elementWrapper.As <Element>();
            PropertyInfo p       = element.GetType().GetProperty(name);

            p.SetValue(element, new DataTemplate(() => {
                try
                {
                    var ac  = (factory.Call(null) as JSValue).ToObject();
                    var eid = ac.GetJSPropertyValue("element");
                    var e   = JSWrapper.FromKey(eid.ToString()).As <View>();
                    return(new TemplateView
                    {
                        View = e,
                        SetBindingContext = (obj) =>
                        {
                            ac.SetJSPropertyValue("data", (Java.Lang.Object)obj);
                        }
                    });
                }
                catch (Exception ex) {
                    System.Diagnostics.Debug.WriteLine(ex);
                    throw;
                }
            }));
        }
        public Element FindChild(JSWrapper rootTarget, string name)
        {
            Element root = rootTarget.As <Element>();
            var     item = root.FindByName <Element>(name);

            //var v = new ObjectReferenceWrapper(engine) {Target = item };
            //return v;
            return(item);
        }
        public JSValue GetValue(JSWrapper viewTarget, string name)
        {
            Element view  = viewTarget.As <Element>();
            var     pv    = view.GetProperty(name);
            var     value = pv.GetValue(view);

            return(value.Wrap(Engine));
            // return null;
        }
 public void Close(JSWrapper wrapper, JSFunction success, JSFunction error)
 {
     Device.BeginInvokeOnMainThread(async() => {
         try {
             var e = wrapper.As <Element>();
             await WebAtoms.WAContext.Current.PopAsync(e, true);
             success.Call(null, new Java.Lang.Object[] { });
         } catch (Exception ex) {
             error.Call(null, new Java.Lang.Object[] { ex.ToString() });
         }
     });
 }
        public JSValue TemplateParent(JSWrapper elementTarget)
        {
            Element element = elementTarget.As <Element>();

            do
            {
                var e = WAContext.GetTemplateParent(element);
                if (e != null)
                {
                    return(e.Wrap(Engine));
                }
                element = element.Parent;
            } while (element != null);
            return(null);
        }
        public void AttachControl(JSWrapper target, JSValue control)
        {
            Element element = target.As <Element>();
            var     ac      = WAContext.GetAtomControl(element);

            if (ac != null)
            {
                if (ac == control as object)
                {
                    return;
                }
                throw new InvalidOperationException("Control already attached");
            }
            WAContext.SetAtomControl(element, control);
        }
        public void SetImport(JSWrapper elementWrapper, string name, JSFunction factory)
        {
            var element = elementWrapper.As <Element>();
            var d       = WAContext.GetImports(element);

            if (d == null)
            {
                d = new Dictionary <string, Func <Element> >();
                WAContext.SetImports(element, d);
            }
            d[name] = () => {
                var t  = WAContext.GetAtomControl(element);
                var jv = factory.Call((JSObject)t.Wrap(Engine)) as JSValue;
                return(JSWrapper.FromKey(jv.ToObject().GetJSPropertyValue("element").ToString()).As <Element>());
            };
        }
 public static JSValue Wrap(this object value, JSContext context)
 {
     if (value == null)
     {
         return(null);
     }
     if (value is JSValue jv)
     {
         return(jv);
     }
     if (value is string s)
     {
         return(new JSValue(context, s));
     }
     if (value is int i)
     {
         return(new JSValue(context, i));
     }
     if (value is float f)
     {
         return(new JSValue(context, f));
     }
     if (value is double d)
     {
         return(new JSValue(context, d));
     }
     if (value is decimal dec)
     {
         return(new JSValue(context, (double)dec));
     }
     if (value is bool b)
     {
         return(new JSValue(context, b));
     }
     if (value is DateTime dt)
     {
         return(dt.ToJSDate(context));
     }
     if (value is JSWrapper w)
     {
         return(new JSValue(context, w.Key));
     }
     return(new JSValue(context, JSWrapper.Register(value).Key));
 }
 public void LoadContent(JSWrapper elementTarget, string content)
 {
     try
     {
         Element element = elementTarget.As <Element>();
         if (element is View v)
         {
             v.LoadFromXaml(content);
         }
         else if (element is Page p)
         {
             p.LoadFromXaml(content);
         }
         // (element as View).LoadFromXaml(content);
     }
     catch (Exception ex) {
         System.Diagnostics.Debug.WriteLine(ex);
         throw;
     }
 }
        public JSDisposable AddEventHandler(
            JSWrapper elementTarget,
            string name, JSFunction callback, bool?capture)
        {
            Element element = elementTarget.As <Element>();

            var e = element.GetType().GetEvent(name);

            if (e == null)
            {
                var disposable = WAContext.Current.AddEventHandler(element, name, () => {
                    try
                    {
                        callback.Call(null);
                    }
                    catch (Exception ex) {
                        System.Diagnostics.Debug.WriteLine(ex);
                        Engine.ThrowJSException(new JSException(Engine, ex.Message));
                    }
                });
                return(new JSDisposable(Engine, () => {
                    disposable.Dispose();
                }));
            }

            var pe = new AtomDelegate()
            {
                callback = callback
            };

            var handler = Delegate.CreateDelegate(e.EventHandlerType, pe, AtomDelegate.OnEventMethod);

            e.AddEventHandler(element, handler);

            return(new JSDisposable(Engine, () => {
                e.RemoveEventHandler(element, handler);
                pe.callback = null;
            }));
        }
        public static JSWrapper Register(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("Cannot register null");
            }
            if (obj is JSWrapper w)
            {
                return(w);
            }
            JSWrapper wrapper = null;
            string    key     = null;

            if (obj is Element e)
            {
                key = WAContext.GetJSRefKey(e);
                if (key == null)
                {
                    key = GenerateKey(obj);
                    WAContext.SetJSRefKey(e, key);
                    lock (wrappers)
                    {
                        wrappers[key] = wrapper = new JSWrapper(new WeakReference(obj), key);
                    }
                }
                else
                {
                    wrapper = wrappers[key];
                }
                return(wrapper);
            }
            lock (wrappers)
            {
                key           = GenerateKey(obj, true);
                wrappers[key] = wrapper = new JSWrapper(new WeakReference(obj), key);
            }
            return(wrapper);
        }
        public JSValue ElementParent(JSWrapper elementTarget)
        {
            Element element = elementTarget.As <Element>();

            return(element.Parent?.Wrap(Engine));
        }
 public void SetRoot(JSWrapper wrapper)
 {
     WAContext.Current.CurrentPage = wrapper.As <Page>();
 }
        public static object ToType(this JSValue value, Type type)
        {
            if (value != null)
            {
                if ((bool)value.IsNull() || (bool)(value.IsUndefined()))
                {
                    return(null);
                }
            }
            if (type == typeof(int))
            {
                if (value == null)
                {
                    return(0);
                }
                return(value.ToNumber().IntValue());
            }
            if (type == typeof(short))
            {
                if (value == null)
                {
                    return(0);
                }
                return(value.ToNumber().ShortValue());
            }
            if (type == typeof(float))
            {
                if (value == null)
                {
                    return(0);
                }
                return(value.ToNumber().FloatValue());
            }
            if (type == typeof(double))
            {
                if (value == null)
                {
                    return(0);
                }
                return(value.ToNumber().DoubleValue());
            }
            if (type == typeof(bool))
            {
                if (value == null)
                {
                    return(0);
                }
                return((bool)value.ToBoolean());
            }
            if (type == typeof(DateTime))
            {
                if (value == null)
                {
                    return(DateTime.MinValue);
                }
                return((value as JSDate).ToDateTime());
            }
            if (value == null)
            {
                return(null);
            }
            if (type == typeof(string))
            {
                return(value.ToString());
            }
            if (type == typeof(JSFunction) || type.IsSubclassOf(typeof(JSFunction)))
            {
                return(value.ToFunction());
            }
            if (type == typeof(JSWrapper))
            {
                return(JSWrapper.FromKey(value.ToString()));
            }

            if (value is JSArray j)
            {
                if (type == typeof(System.Collections.IEnumerable))
                {
                    return(new AtomEnumerable(j));
                }

                // type is IList...
                var list = Activator.CreateInstance(type) as System.Collections.IList;
                for (int i = 0; i < j.Size(); i++)
                {
                    Type itemType = type.GetGenericArguments()[0];
                    list[i] = (j.Get(i) as JSValue).ToType(itemType);
                }
                return(list);
            }
            if (type == typeof(JSObject))
            {
                return(value.ToObject());
            }
            if (type == typeof(JSValue) || type.IsSubclassOf(typeof(JSValue)))
            {
                return(value);
            }
            return(null);
        }
        public void SetValue(JSWrapper target, string name, JSValue value)
        {
            Element view = target.As <Element>();

            if (view != null && name.Equals("name", StringComparison.OrdinalIgnoreCase))
            {
                WAContext.SetWAName(view, name);
                return;
            }

            bool isNull = (bool)value.IsNull() || (bool)value.IsUndefined();

            var pv = view.GetProperty(name);

            if (isNull)
            {
                pv.SetValue(view, null);
                return;
            }

            var pt = pv.PropertyType;



            if (pt == typeof(string))
            {
                pv.SetValue(view, value.ToString());
                return;
            }

            // check if it is an array
            if ((bool)value.IsArray())
            {
                var old = pv.GetValue(view);
                if (old is IDisposable d)
                {
                    d.Dispose();
                }
                var array = value.ToJSArray();
                pv.SetValue(view, new AtomEnumerable(array));
                return;
            }

            pt = Nullable.GetUnderlyingType(pt) ?? pt;

            if (value is JSDate date)
            {
                // conver to datetime and set...
                pv.SetValue(view, date.ToDateTime());
                return;
            }

            if (pt.IsValueType)
            {
                object clrValue = null;
                // convert...
                if (value.IsBoolean().BooleanValue())
                {
                    clrValue = value.ToBoolean().BooleanValue();
                }
                else if (value.IsNumber().BooleanValue())
                {
                    if (pt == typeof(double) || pt == typeof(float) || pt == typeof(short))
                    {
                        clrValue = value.ToNumber().DoubleValue();
                    }
                    else
                    {
                        clrValue = value.ToNumber().LongValue();
                    }
                }
                var v = Convert.ChangeType(clrValue, pt);
                pv.SetValue(view, v);
                return;
            }
            else
            {
                if (pv.PropertyType == typeof(ICommand))
                {
                    pv.SetValue(view, new AtomCommand(() => {
                        value.ToFunction().Call(null);
                    }));
                }
                else
                {
                    pv.SetValue(view, value.ToObject());
                }
            }
        }