diff --git a/Ooui/EventTarget.cs b/Ooui/EventTarget.cs index f218d69..2b4cfbc 100644 --- a/Ooui/EventTarget.cs +++ b/Ooui/EventTarget.cs @@ -18,10 +18,10 @@ namespace Ooui public event Action MessageSent; - public IEnumerable StateMessages { + public IReadOnlyList StateMessages { get { lock (stateMessages) { - return new List (stateMessages); + return new List (stateMessages).AsReadOnly (); } } } @@ -37,6 +37,8 @@ namespace Ooui }); } + public override string ToString() => $"<{TagName} id=\"{Id}\" />"; + public virtual EventTarget GetElementById (string id) { if (id == Id) return this; @@ -134,37 +136,30 @@ namespace Ooui TriggerEventFromMessage (message); } - protected void SaveStateMessage (Message message) + protected void AddStateMessage (Message message) { lock (stateMessages) stateMessages.Add (message); } - void LockedReplaceStateMessage (Message old, Message message) + protected void UpdateStateMessages (Action> updater) { - if (old != null) { - stateMessages.Remove (old); - } - stateMessages.Add (message); + lock (stateMessages) updater (stateMessages); } protected virtual void SaveStateMessageIfNeeded (Message message) { switch (message.MessageType) { case MessageType.Create: - SaveStateMessage (message); + AddStateMessage (message); break; case MessageType.Set: - { - lock (stateMessages) { - var old = stateMessages.FirstOrDefault ( - x => x.MessageType == MessageType.Set && - x.Key == message.Key); - LockedReplaceStateMessage (old, message); - } - } + UpdateStateMessages (state => { + state.RemoveAll (x => x.MessageType == MessageType.Set && x.Key == message.Key); + state.Add (message); + }); break; case MessageType.Listen: - SaveStateMessage (message); + AddStateMessage (message); break; } } diff --git a/Ooui/Node.cs b/Ooui/Node.cs index cf19983..cff16eb 100644 --- a/Ooui/Node.cs +++ b/Ooui/Node.cs @@ -103,10 +103,30 @@ namespace Ooui protected override void SaveStateMessageIfNeeded (Message message) { switch (message.MessageType) { - case MessageType.Call when - message.Key == "insertBefore" || - message.Key == "removeChild": - SaveStateMessage (message); + 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++; + } + } + }); break; default: base.SaveStateMessageIfNeeded (message); diff --git a/Tests/EventTargetTests.cs b/Tests/EventTargetTests.cs new file mode 100644 index 0000000..9f19419 --- /dev/null +++ b/Tests/EventTargetTests.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ooui; + +namespace Tests +{ + [TestClass] + public class EventTargetTests + { + [TestMethod] + public void CreationState () + { + var b = new Button (); + Assert.AreEqual (1, b.StateMessages.Count); + } + } +} diff --git a/Tests/NodeTests.cs b/Tests/NodeTests.cs new file mode 100644 index 0000000..32e0da0 --- /dev/null +++ b/Tests/NodeTests.cs @@ -0,0 +1,41 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Ooui; + +namespace Tests +{ + [TestClass] + public class NodeTests + { + [TestMethod] + public void TextState () + { + var b = new Button (); + Assert.AreEqual (1, b.StateMessages.Count); + b.Text = "Hello"; + Assert.AreEqual (2, b.StateMessages.Count); + b.Text = "Bye"; + Assert.AreEqual (2, b.StateMessages.Count); + } + + [TestMethod] + public void InsertBeforeOfRemovedNodeStillWorks () + { + var p = new Div (); + var c0 = new Span (); + var c1 = new Span (); + var c2 = new Span (); + p.InsertBefore (c2, null); + p.InsertBefore (c1, c2); + p.InsertBefore (c0, c1); + p.RemoveChild (c1); + var ms = p.StateMessages; + Assert.AreEqual (3, ms.Count); + var c0s = (Array)ms[2].Value; + Assert.AreEqual (2, c0s.Length); + Assert.AreEqual (c0, c0s.GetValue (0)); + Assert.AreEqual (c2, c0s.GetValue (1)); + } + } +}