Fix bubbling events through nodes

This commit is contained in:
Frank A. Krueger 2017-06-24 13:34:47 -07:00
parent d4bae780d3
commit a780f97578
9 changed files with 118 additions and 59 deletions

View File

@ -33,16 +33,16 @@ namespace Ooui
} }
return context2d; return context2d;
} }
protected override void SaveStateMessageIfNeeded (Message message) protected override bool SaveStateMessageIfNeeded (Message message)
{ {
switch (message.MessageType) { if (message.TargetId == Id) {
case MessageType.Call when message.Key == "getContext" && message.Value is Array a && a.Length == 1 && "2d".Equals (a.GetValue (0)): switch (message.MessageType) {
AddStateMessage (message); case MessageType.Call when message.Key == "getContext" && message.Value is Array a && a.Length == 1 && "2d".Equals (a.GetValue (0)):
break; AddStateMessage (message);
default: break;
base.SaveStateMessageIfNeeded (message); }
break;
} }
return base.SaveStateMessageIfNeeded (message);
} }
} }
} }

View File

@ -1,5 +1,5 @@
const debug = true; const debug = false;
const nodes = {}; const nodes = {};

View File

@ -134,8 +134,7 @@ namespace Ooui
{ {
if (message == null) if (message == null)
return; return;
if (message.TargetId == Id) SaveStateMessageIfNeeded (message);
SaveStateMessageIfNeeded (message);
TriggerEventFromMessage (message); TriggerEventFromMessage (message);
} }
@ -149,8 +148,11 @@ namespace Ooui
lock (stateMessages) updater (stateMessages); 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) { switch (message.MessageType) {
case MessageType.Create: case MessageType.Create:
AddStateMessage (message); AddStateMessage (message);
@ -165,12 +167,15 @@ namespace Ooui
AddStateMessage (message); AddStateMessage (message);
break; break;
} }
return true;
} }
protected virtual bool TriggerEventFromMessage (Message message) protected virtual bool TriggerEventFromMessage (Message message)
{ {
if (message.TargetId != Id) if (message.TargetId != Id)
return false; return false;
List<EventHandler> handlers = null; List<EventHandler> handlers = null;
lock (eventListeners) { lock (eventListeners) {
List<EventHandler> hs; List<EventHandler> hs;
@ -178,10 +183,11 @@ namespace Ooui
handlers = new List<EventHandler> (hs); handlers = new List<EventHandler> (hs);
} }
} }
if (handlers == null) return true; if (handlers != null) {
var args = EventArgs.Empty; var args = EventArgs.Empty;
foreach (var h in handlers) { foreach (var h in handlers) {
h.Invoke (this, args); h.Invoke (this, args);
}
} }
return true; return true;
} }

View File

@ -64,6 +64,8 @@ namespace Ooui
public Input () public Input ()
: base ("input") : base ("input")
{ {
// Subscribe to the change event so we always get up-to-date values
Changed += (s, e) => {};
} }
public Input (InputType type) public Input (InputType type)
@ -71,6 +73,15 @@ namespace Ooui
{ {
Type = type; 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 public enum InputType

View File

@ -29,10 +29,11 @@ namespace Ooui
Value = args, 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, MessageType = MessageType.Event,
TargetId = targetId, TargetId = targetId,
Key = eventType, Key = eventType,
Value = value,
}; };
} }

View File

@ -100,49 +100,64 @@ namespace Ooui
Send (message); Send (message);
} }
protected override void SaveStateMessageIfNeeded (Message message) protected override bool SaveStateMessageIfNeeded (Message message)
{ {
switch (message.MessageType) { if (message.TargetId == Id) {
case MessageType.Call when message.Key == "insertBefore": switch (message.MessageType) {
AddStateMessage (message); case MessageType.Call when message.Key == "insertBefore":
break; AddStateMessage (message);
case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1: break;
UpdateStateMessages (state => { case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1:
var mchild = ma.GetValue (0); UpdateStateMessages (state => {
Node nextChild = null; var mchild = ma.GetValue (0);
for (var i = 0; i < state.Count; ) { Node nextChild = null;
var x = state[i]; for (var i = 0; i < state.Count; ) {
if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) { var x = state[i];
// Remove any inserts for this node if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) {
nextChild = xa.GetValue (1) as Node; // Remove any inserts for this node
state.RemoveAt (i); 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 break;
state[i] = Message.Call (Id, "insertBefore", ya.GetValue (0), nextChild); default:
i++; base.SaveStateMessageIfNeeded (message);
} break;
else { }
i++; return true;
} }
} else {
}); var ch = Children;
break; for (var i = 0; i < ch.Count; i++) {
default: if (ch[i].SaveStateMessageIfNeeded (message))
base.SaveStateMessageIfNeeded (message); return true;
break; }
return false;
} }
} }
protected override bool TriggerEventFromMessage (Message message) protected override bool TriggerEventFromMessage (Message message)
{ {
if (base.TriggerEventFromMessage (message)) if (message.TargetId == Id) {
return true; if (base.TriggerEventFromMessage (message))
var ch = Children;
for (var i = 0; i < ch.Count; i++) {
if (ch[i].TriggerEventFromMessage (message))
return true; return true;
} }
else {
var ch = Children;
for (var i = 0; i < ch.Count; i++) {
if (ch[i].TriggerEventFromMessage (message))
return true;
}
}
return false; return false;
} }
} }

View File

@ -35,6 +35,8 @@ namespace Ooui
public TextArea () public TextArea ()
: base ("textarea") : base ("textarea")
{ {
// Subscribe to the change event so we always get up-to-date values
Changed += (s, e) => {};
} }
public TextArea (string text) public TextArea (string text)
@ -42,5 +44,13 @@ namespace Ooui
{ {
Text = text; 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);
}
} }
} }

View File

@ -1,21 +1,27 @@
using System; using System;
using System.Collections.Generic;
using Ooui; using Ooui;
namespace Samples namespace Samples
{ {
public class TodoSample public class TodoSample
{ {
Button MakeTodo ()
Element MakeTodo ()
{ {
var button = new Button ("Click me!"); var items = new List ();
button.Style.FontSize = 100; var input = new Input ();
var count = 0; var button = new Button ("Add the item");
button.Clicked += (s, e) => { button.Clicked += (s, e) => {
button.Style.FontSize = (int)button.Style.FontSize + 1; items.AppendChild (new ListItem {
count++; Text = input.Value
button.Text = $"Clicked {count} times"; });
}; };
return button; var app = new Div ();
app.AppendChild (input);
app.AppendChild (button);
app.AppendChild (items);
return app;
} }
public void Publish () public void Publish ()

View File

@ -51,5 +51,15 @@ namespace Tests
p.Receive (Message.Event (b.Id, "click")); p.Receive (Message.Event (b.Id, "click"));
Assert.IsTrue (clicked); 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);
}
} }
} }