Add EventTarget

This commit is contained in:
Frank A. Krueger 2017-06-14 18:24:59 -07:00
parent 4c8c4e2b03
commit 44ae8c96f3
4 changed files with 132 additions and 91 deletions

120
Ooui/EventTarget.cs Normal file
View File

@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ooui
{
public abstract class EventTarget
{
public string Id { get; private set; } = GenerateId ();
public Mapping Mapping { get; private set; }
readonly List<Message> stateMessages = new List<Message> ();
public event Action<Message> MessageSent;
public IEnumerable<Message> StateMessages => stateMessages;
public EventTarget ()
{
Mapping = Mapping.Get (GetType ());
}
protected bool SetProperty<T> (ref T backingStore, T newValue, string attributeName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (!backingStore.Equals (newValue)) {
backingStore = newValue;
SendSet (attributeName, newValue);
return true;
}
return false;
}
static long idCounter = 0;
static string GenerateId ()
{
var id = System.Threading.Interlocked.Increment (ref idCounter);
return "n" + id;
}
public virtual void Send (Message message)
{
SaveStateMessage (message);
MessageSent?.Invoke (message);
}
protected void SendCreate ()
{
Send (new Message {
MessageType = MessageType.Create,
TargetId = Id,
Key = Mapping.TagName,
});
}
protected void SendCall (string methodName, params object[] args)
{
Send (new Message {
MessageType = MessageType.Call,
TargetId = Id,
Key = methodName,
Value = args,
});
}
protected void SendSet (string attributeName, object value)
{
Send (new Message {
MessageType = MessageType.Set,
TargetId = Id,
Key = attributeName,
Value = value,
});
}
public virtual void Receive (Message message)
{
if (message == null)
return;
if (message.TargetId != Id)
return;
SaveStateMessageIfNeeded (message);
TriggerEventFromMessage (message);
}
protected void SaveStateMessage (Message message)
{
stateMessages.Add (message);
}
protected void ReplaceStateMessage (Message old, Message message)
{
if (old != null) {
stateMessages.Remove (old);
}
stateMessages.Add (message);
}
protected virtual void SaveStateMessageIfNeeded (Message message)
{
switch (message.MessageType) {
case MessageType.Create:
SaveStateMessage (message);
break;
case MessageType.Set:
{
var old = stateMessages.FirstOrDefault (
x => x.MessageType == MessageType.Set &&
x.Key == message.Key);
ReplaceStateMessage (old, message);
}
break;
}
}
protected virtual void TriggerEventFromMessage (Message message)
{
}
}
}

View File

@ -35,8 +35,8 @@ namespace Ooui
} }
return na; return na;
} }
else if (v is Node n) { else if (v is EventTarget t) {
return "\u2999" + n.Id; return "\u2999" + t.Id;
} }
return v; return v;
} }

View File

@ -4,21 +4,13 @@ using System.Linq;
namespace Ooui namespace Ooui
{ {
public abstract class Node public abstract class Node : EventTarget
{ {
public string Id { get; private set; } = GenerateId ();
public Mapping Mapping { get; private set; }
readonly List<Node> children = new List<Node> (); readonly List<Node> children = new List<Node> ();
readonly List<Message> messages = new List<Message> ();
readonly List<Message> stateMessages = new List<Message> ();
public event Action<Message> MessageLogged; public IEnumerable<Message> AllStateMessages =>
StateMessages
public IEnumerable<Message> AllMessages => .Concat (from c in children from m in c.AllStateMessages select m)
messages
.Concat (from c in children from m in c.AllMessages select m)
.OrderBy (x => x.Id); .OrderBy (x => x.Id);
public virtual string Text { public virtual string Text {
@ -30,8 +22,7 @@ namespace Ooui
public Node () public Node ()
{ {
Mapping = Mapping.Get (GetType ()); SendCreate ();
LogCreate ();
} }
public Node AppendChild (Node newChild) public Node AppendChild (Node newChild)
@ -54,7 +45,7 @@ namespace Ooui
children.Insert (index, newChild); children.Insert (index, newChild);
} }
newChild.ParentNode = this; newChild.ParentNode = this;
LogCall ("insertBefore", newChild, referenceChild); SendCall ("insertBefore", newChild, referenceChild);
return newChild; return newChild;
} }
@ -64,7 +55,7 @@ namespace Ooui
throw new ArgumentException ("Child not contained in this element", nameof(child)); throw new ArgumentException ("Child not contained in this element", nameof(child));
} }
child.ParentNode = null; child.ParentNode = null;
LogCall ("removeChild", child); SendCall ("removeChild", child);
return child; return child;
} }
@ -75,75 +66,5 @@ namespace Ooui
RemoveChild (c); RemoveChild (c);
InsertBefore (newNode, null); InsertBefore (newNode, null);
} }
protected void Log (Message message)
{
messages.Add (message);
switch (message.MessageType) {
case MessageType.Create:
stateMessages.Add (message);
break;
case MessageType.Set:
{
var old = stateMessages.FirstOrDefault (
x => x.MessageType == MessageType.Set &&
x.Key == message.Key);
if (old != null) {
stateMessages.Remove (old);
}
stateMessages.Add (message);
}
break;
}
MessageLogged?.Invoke (message);
}
protected void LogCreate ()
{
Log (new Message {
MessageType = MessageType.Create,
TargetId = Id,
Key = Mapping.TagName,
});
}
protected void LogCall (string methodName, params object[] args)
{
Log (new Message {
MessageType = MessageType.Call,
TargetId = Id,
Key = methodName,
Value = args,
});
}
protected void LogSet (string attributeName, object value)
{
Log (new Message {
MessageType = MessageType.Set,
TargetId = Id,
Key = attributeName,
Value = value,
});
}
protected bool SetProperty<T> (ref T backingStore, T newValue, string attributeName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (!backingStore.Equals (newValue)) {
backingStore = newValue;
LogSet (attributeName, newValue);
return true;
}
return false;
}
static long idCounter = 0;
static string GenerateId ()
{
var id = System.Threading.Interlocked.Increment (ref idCounter);
return "n" + id;
}
} }
} }

View File

@ -191,12 +191,12 @@ namespace Ooui
// //
// Send message history, start sending updates, and add it to the body // Send message history, start sending updates, and add it to the body
// //
foreach (var m in element.AllMessages) { foreach (var m in element.AllStateMessages) {
if (webSocket.State == WebSocketState.Open) { if (webSocket.State == WebSocketState.Open) {
await SendMessageAsync (webSocket, m, token); await SendMessageAsync (webSocket, m, token);
} }
} }
element.MessageLogged += onElementMessage; element.MessageSent += onElementMessage;
await SendMessageAsync (webSocket, new Message { await SendMessageAsync (webSocket, new Message {
TargetId = "document.body", TargetId = "document.body",
MessageType = MessageType.Call, MessageType = MessageType.Call,
@ -243,7 +243,7 @@ namespace Ooui
Error ("Failed to process web socket", ex); Error ("Failed to process web socket", ex);
} }
finally { finally {
element.MessageLogged -= onElementMessage; element.MessageSent -= onElementMessage;
webSocket?.Dispose (); webSocket?.Dispose ();
} }
} }