diff --git a/Ooui/Canvas.cs b/Ooui/Canvas.cs index 28906ca..d8e679f 100644 --- a/Ooui/Canvas.cs +++ b/Ooui/Canvas.cs @@ -33,16 +33,16 @@ namespace Ooui } return context2d; } - protected override void SaveStateMessageIfNeeded (Message message) + protected override bool SaveStateMessageIfNeeded (Message message) { - switch (message.MessageType) { - case MessageType.Call when message.Key == "getContext" && message.Value is Array a && a.Length == 1 && "2d".Equals (a.GetValue (0)): - AddStateMessage (message); - break; - default: - base.SaveStateMessageIfNeeded (message); - break; + if (message.TargetId == Id) { + switch (message.MessageType) { + case MessageType.Call when message.Key == "getContext" && message.Value is Array a && a.Length == 1 && "2d".Equals (a.GetValue (0)): + AddStateMessage (message); + break; + } } + return base.SaveStateMessageIfNeeded (message); } } } diff --git a/Ooui/Client.js b/Ooui/Client.js index 6aaaef9..4be5c1b 100644 --- a/Ooui/Client.js +++ b/Ooui/Client.js @@ -1,5 +1,5 @@ -const debug = true; +const debug = false; const nodes = {}; diff --git a/Ooui/EventTarget.cs b/Ooui/EventTarget.cs index d6da403..27db0e4 100644 --- a/Ooui/EventTarget.cs +++ b/Ooui/EventTarget.cs @@ -134,8 +134,7 @@ namespace Ooui { if (message == null) return; - if (message.TargetId == Id) - SaveStateMessageIfNeeded (message); + SaveStateMessageIfNeeded (message); TriggerEventFromMessage (message); } @@ -149,8 +148,11 @@ namespace Ooui lock (stateMessages) updater (stateMessages); } - protected virtual void SaveStateMessageIfNeeded (Message message) + protected virtual bool SaveStateMessageIfNeeded (Message message) { + if (message.TargetId != Id) + return false; + switch (message.MessageType) { case MessageType.Create: AddStateMessage (message); @@ -165,12 +167,15 @@ namespace Ooui AddStateMessage (message); break; } + + return true; } protected virtual bool TriggerEventFromMessage (Message message) { if (message.TargetId != Id) return false; + List handlers = null; lock (eventListeners) { List hs; @@ -178,10 +183,11 @@ namespace Ooui handlers = new List (hs); } } - if (handlers == null) return true; - var args = EventArgs.Empty; - foreach (var h in handlers) { - h.Invoke (this, args); + if (handlers != null) { + var args = EventArgs.Empty; + foreach (var h in handlers) { + h.Invoke (this, args); + } } return true; } diff --git a/Ooui/Input.cs b/Ooui/Input.cs index ae4b6ee..3bd9e1a 100644 --- a/Ooui/Input.cs +++ b/Ooui/Input.cs @@ -64,6 +64,8 @@ namespace Ooui public Input () : base ("input") { + // Subscribe to the change event so we always get up-to-date values + Changed += (s, e) => {}; } public Input (InputType type) @@ -71,6 +73,15 @@ namespace Ooui { Type = type; } + + protected override bool TriggerEventFromMessage (Message message) + { + if (message.TargetId == Id && message.MessageType == MessageType.Event && message.Key == "change") { + Value = message.Value != null ? Convert.ToString (message.Value) : ""; + return true; + } + return base.TriggerEventFromMessage (message); + } } public enum InputType diff --git a/Ooui/Message.cs b/Ooui/Message.cs index a500859..ae9ffb1 100644 --- a/Ooui/Message.cs +++ b/Ooui/Message.cs @@ -29,10 +29,11 @@ namespace Ooui Value = args, }; - public static Message Event (string targetId, string eventType) => new Message { + public static Message Event (string targetId, string eventType, object value = null) => new Message { MessageType = MessageType.Event, TargetId = targetId, Key = eventType, + Value = value, }; } diff --git a/Ooui/Node.cs b/Ooui/Node.cs index 5cd3fcf..b072702 100644 --- a/Ooui/Node.cs +++ b/Ooui/Node.cs @@ -100,49 +100,64 @@ namespace Ooui Send (message); } - protected override void SaveStateMessageIfNeeded (Message message) + protected override bool SaveStateMessageIfNeeded (Message message) { - switch (message.MessageType) { - case MessageType.Call when message.Key == "insertBefore": - AddStateMessage (message); - break; - case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1: - UpdateStateMessages (state => { - var mchild = ma.GetValue (0); - Node nextChild = null; - for (var i = 0; i < state.Count; ) { - var x = state[i]; - if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) { - // Remove any inserts for this node - nextChild = xa.GetValue (1) as Node; - state.RemoveAt (i); + if (message.TargetId == Id) { + switch (message.MessageType) { + case MessageType.Call when message.Key == "insertBefore": + AddStateMessage (message); + break; + case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1: + UpdateStateMessages (state => { + var mchild = ma.GetValue (0); + Node nextChild = null; + for (var i = 0; i < state.Count; ) { + var x = state[i]; + if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) { + // Remove any inserts for this node + nextChild = xa.GetValue (1) as Node; + state.RemoveAt (i); + } + else if (x.Key == "insertBefore" && x.Value is Array ya && ya.Length == 2 && ReferenceEquals (ya.GetValue (1), mchild)) { + // Replace inserts that reference this node + state[i] = Message.Call (Id, "insertBefore", ya.GetValue (0), nextChild); + i++; + } + else { + i++; + } } - else if (x.Key == "insertBefore" && x.Value is Array ya && ya.Length == 2 && ReferenceEquals (ya.GetValue (1), mchild)) { - // Replace inserts that reference this node - state[i] = Message.Call (Id, "insertBefore", ya.GetValue (0), nextChild); - i++; - } - else { - i++; - } - } - }); - break; - default: - base.SaveStateMessageIfNeeded (message); - break; + }); + break; + default: + base.SaveStateMessageIfNeeded (message); + break; + } + return true; + } + else { + var ch = Children; + for (var i = 0; i < ch.Count; i++) { + if (ch[i].SaveStateMessageIfNeeded (message)) + return true; + } + return false; } } protected override bool TriggerEventFromMessage (Message message) { - if (base.TriggerEventFromMessage (message)) - return true; - var ch = Children; - for (var i = 0; i < ch.Count; i++) { - if (ch[i].TriggerEventFromMessage (message)) + if (message.TargetId == Id) { + if (base.TriggerEventFromMessage (message)) return true; } + else { + var ch = Children; + for (var i = 0; i < ch.Count; i++) { + if (ch[i].TriggerEventFromMessage (message)) + return true; + } + } return false; } } diff --git a/Ooui/TextArea.cs b/Ooui/TextArea.cs index c289162..653bcef 100644 --- a/Ooui/TextArea.cs +++ b/Ooui/TextArea.cs @@ -35,6 +35,8 @@ namespace Ooui public TextArea () : base ("textarea") { + // Subscribe to the change event so we always get up-to-date values + Changed += (s, e) => {}; } public TextArea (string text) @@ -42,5 +44,13 @@ namespace Ooui { Text = text; } + + protected override bool TriggerEventFromMessage (Message message) + { + if (message.TargetId == Id && message.MessageType == MessageType.Event && message.Key == "change") { + Value = message.Value != null ? Convert.ToString (message.Value) : ""; + } + return base.TriggerEventFromMessage (message); + } } } diff --git a/Samples/TodoSample.cs b/Samples/TodoSample.cs index d0aff2d..db5757a 100644 --- a/Samples/TodoSample.cs +++ b/Samples/TodoSample.cs @@ -1,21 +1,27 @@ using System; +using System.Collections.Generic; using Ooui; namespace Samples { public class TodoSample { - Button MakeTodo () + + Element MakeTodo () { - var button = new Button ("Click me!"); - button.Style.FontSize = 100; - var count = 0; + var items = new List (); + var input = new Input (); + var button = new Button ("Add the item"); button.Clicked += (s, e) => { - button.Style.FontSize = (int)button.Style.FontSize + 1; - count++; - button.Text = $"Clicked {count} times"; + items.AppendChild (new ListItem { + Text = input.Value + }); }; - return button; + var app = new Div (); + app.AppendChild (input); + app.AppendChild (button); + app.AppendChild (items); + return app; } public void Publish () diff --git a/Tests/NodeTests.cs b/Tests/NodeTests.cs index a12d0cf..a4f4aa7 100644 --- a/Tests/NodeTests.cs +++ b/Tests/NodeTests.cs @@ -51,5 +51,15 @@ namespace Tests p.Receive (Message.Event (b.Id, "click")); Assert.IsTrue (clicked); } + + [TestMethod] + public void ValueBubblesDown () + { + var p = new Div (); + var b = new Input (); + p.AppendChild (b); + p.Receive (Message.Event (b.Id, "change", "please work")); + Assert.AreEqual ("please work", b.Value); + } } }