Merge branch 'master' of github.com:praeclarum/Ooui
This commit is contained in:
		
						commit
						8322ddaae3
					
				|  | @ -1,33 +1,56 @@ | |||
| using System; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| 
 | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| 
 | ||||
| namespace Ooui.AspNetCore | ||||
| { | ||||
|     public class ElementResult : ActionResult | ||||
|     { | ||||
|     { | ||||
|         readonly Element element; | ||||
|         readonly string title; | ||||
| 
 | ||||
|         readonly string title; | ||||
| 
 | ||||
|         public ElementResult (Element element, string title = "") | ||||
|         { | ||||
|         { | ||||
|             this.element = element; | ||||
|             this.title = title; | ||||
|             this.title = title; | ||||
|         } | ||||
| 
 | ||||
|         public override async Task ExecuteResultAsync (ActionContext context) | ||||
|         public override async Task ExecuteResultAsync (ActionContext context) | ||||
|         { | ||||
|             var response = context.HttpContext.Response; | ||||
|             response.StatusCode = 200; | ||||
|             response.ContentType = "text/html; charset=utf-8"; | ||||
| 
 | ||||
|             if (element.WantsFullScreen) { | ||||
|                 element.Style.Width = GetCookieDouble (context.HttpContext.Request.Cookies, "oouiWindowWidth", 32, 640, 10000); | ||||
|                 element.Style.Height = GetCookieDouble (context.HttpContext.Request.Cookies, "oouiWindowHeight", 24, 480, 10000); | ||||
|             } | ||||
| 
 | ||||
|             var sessionId = WebSocketHandler.BeginSession (context.HttpContext, element); | ||||
|             var html = UI.RenderTemplate (WebSocketHandler.WebSocketPath + "?id=" + sessionId, title: title); | ||||
|             var initialHtml = element.OuterHtml; | ||||
|             var html = UI.RenderTemplate (WebSocketHandler.WebSocketPath + "?id=" + sessionId, title: title, initialHtml: initialHtml); | ||||
|             var htmlBytes = Encoding.UTF8.GetBytes (html); | ||||
|             response.ContentLength = htmlBytes.Length; | ||||
|             using (var s = response.Body) { | ||||
|                 await s.WriteAsync (htmlBytes, 0, htmlBytes.Length).ConfigureAwait (false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         static double GetCookieDouble (IRequestCookieCollection cookies, string key, double min, double def, double max) | ||||
|         { | ||||
|             if (cookies.TryGetValue (key, out var s)) { | ||||
|                 if (double.TryParse (s, out var d)) { | ||||
|                     if (d < min) return min; | ||||
|                     if (d > max) return max; | ||||
|                     return d; | ||||
|                 } | ||||
|                 return def; | ||||
|             } | ||||
|             else { | ||||
|                 return def; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ namespace Ooui.Forms.Renderers | |||
|         /// </summary> | ||||
|         protected virtual bool ManageNativeControlLifetime => true; | ||||
| 
 | ||||
| 		protected override bool HtmlNeedsFullEndElement => TagName == "div"; | ||||
| 
 | ||||
|         public ViewRenderer (string tagName = "div") | ||||
|             : base (tagName) | ||||
|         { | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ namespace Ooui.Forms.Renderers | |||
| 
 | ||||
|                 if (_iframe != null) | ||||
|                 { | ||||
|                     _iframe.Src = html; | ||||
|                     _iframe.Source = html; | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|  | @ -47,7 +47,7 @@ namespace Ooui.Forms.Renderers | |||
| 
 | ||||
|                 if (_iframe != null) | ||||
|                 { | ||||
|                     _iframe.Src = url; | ||||
|                     _iframe.Source = url; | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|  |  | |||
|  | @ -62,6 +62,8 @@ namespace Ooui.Forms | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         protected override bool HtmlNeedsFullEndElement => TagName == "div"; | ||||
| 
 | ||||
|         public VisualElementRenderer (string tagName = "div") : base (tagName) | ||||
|         { | ||||
|             _propertyChangedHandler = OnElementPropertyChanged; | ||||
|  |  | |||
|  | @ -4,10 +4,9 @@ namespace Ooui | |||
| { | ||||
|     public class Anchor : Element | ||||
|     { | ||||
|         string href = ""; | ||||
|         public string HRef { | ||||
|             get => href; | ||||
|             set => SetProperty (ref href, value ?? "", "href"); | ||||
|             get => GetStringAttribute ("href", ""); | ||||
|             set => SetAttributeProperty ("href", value); | ||||
|         } | ||||
| 
 | ||||
|         public Anchor () | ||||
|  |  | |||
|  | @ -9,8 +9,8 @@ namespace Ooui | |||
|     { | ||||
|         ButtonType typ = ButtonType.Submit; | ||||
|         public ButtonType Type { | ||||
|             get => typ; | ||||
|             set => SetProperty (ref typ, value, "type"); | ||||
|             get => GetAttribute ("type", ButtonType.Submit); | ||||
|             set => SetAttributeProperty ("type", value); | ||||
|         } | ||||
| 
 | ||||
|         public Button () | ||||
|  |  | |||
|  | @ -7,16 +7,14 @@ namespace Ooui | |||
|         CanvasRenderingContext2D context2d = new CanvasRenderingContext2D (); | ||||
|         int gotContext2d = 0; | ||||
| 
 | ||||
|         int width = 300; | ||||
|         public int Width { | ||||
|             get => width; | ||||
|             set => SetProperty (ref width, value <= 0 ? 150 : value, "width"); | ||||
|             get => GetAttribute ("width", 300); | ||||
|             set => SetAttributeProperty ("width", value < 0 ? 0 : value); | ||||
|         } | ||||
| 
 | ||||
|         int height = 150; | ||||
|         public int Height { | ||||
|             get => height; | ||||
|             set => SetProperty (ref height, value <= 0 ? 150 : value, "height"); | ||||
|             get => GetAttribute ("height", 150); | ||||
|             set => SetAttributeProperty ("height", value < 0 ? 0 : value); | ||||
|         } | ||||
| 
 | ||||
|         public Canvas () | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| var debug = false; | ||||
| 
 | ||||
| const nodes = {}; | ||||
| const hasText = {}; | ||||
| 
 | ||||
| let socket = null; | ||||
| 
 | ||||
|  | @ -35,10 +36,27 @@ function getSize () { | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| function setCookie (name, value, days) { | ||||
|     var expires = ""; | ||||
|     if (days) { | ||||
|         var date = new Date (); | ||||
|         date.setTime(date.getTime () + (days*24*60*60*1000)); | ||||
|         expires = "; expires=" + date.toUTCString(); | ||||
|     } | ||||
|     document.cookie = name + "=" + (value || "")  + expires + "; path=/"; | ||||
| } | ||||
| 
 | ||||
| function saveSize (s) { | ||||
|     setCookie ("oouiWindowWidth", s.width, 7); | ||||
|     setCookie ("oouiWindowHeight", s.height, 7); | ||||
| } | ||||
| 
 | ||||
| // Main entrypoint
 | ||||
| function ooui (rootElementPath) { | ||||
| 
 | ||||
|     var initialSize = getSize (); | ||||
|     saveSize (initialSize); | ||||
| 
 | ||||
|     var wsArgs = (rootElementPath.indexOf("?") >= 0 ? "&" : "?") + | ||||
|         "w=" + initialSize.width + "&h=" + initialSize.height; | ||||
| 
 | ||||
|  | @ -123,12 +141,22 @@ function getNode (id) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| function getOrCreateElement (id, tagName) { | ||||
|     var e = document.getElementById (id); | ||||
|     if (e) { | ||||
|         if (e.firstChild && e.firstChild.nodeType == Node.TEXT_NODE) | ||||
|             hasText[e.id] = true; | ||||
|         return e; | ||||
|     } | ||||
|     return document.createElement (tagName); | ||||
| } | ||||
| 
 | ||||
| function msgCreate (m) { | ||||
|     const id = m.id; | ||||
|     const tagName = m.k; | ||||
|     const node = tagName === "#text" ? | ||||
|         document.createTextNode ("") : | ||||
|         document.createElement (tagName); | ||||
|         getOrCreateElement (id, tagName); | ||||
|     if (tagName !== "#text") | ||||
|         node.id = id; | ||||
|     nodes[id] = node; | ||||
|  | @ -164,6 +192,17 @@ function msgSetAttr (m) { | |||
|     if (debug) console.log ("SetAttr", node, m.k, m.v); | ||||
| } | ||||
| 
 | ||||
| function msgRemAttr (m) { | ||||
|     const id = m.id; | ||||
|     const node = getNode (id); | ||||
|     if (!node) { | ||||
|         console.error ("Unknown node id", m); | ||||
|         return; | ||||
|     } | ||||
|     node.removeAttribute(m.k); | ||||
|     if (debug) console.log ("RemAttr", node, m.k); | ||||
| } | ||||
| 
 | ||||
| function msgCall (m) { | ||||
|     const id = m.id; | ||||
|     const node = getNode (id); | ||||
|  | @ -173,6 +212,12 @@ function msgCall (m) { | |||
|     } | ||||
|     const isJQuery = m.k.startsWith ("$."); | ||||
|     const target = isJQuery ? $(node) : node; | ||||
|     if (m.k === "insertBefore" && m.v[0].nodeType == Node.TEXT_NODE && m.v[1] == null && hasText[id]) { | ||||
|         // Text is already set so it clear it first
 | ||||
|         if (target.firstChild) | ||||
|             target.removeChild (target.firstChild); | ||||
|         delete hasText[id]; | ||||
|     } | ||||
|     const f = isJQuery ? target[m.k.slice(2)] : target[m.k]; | ||||
|     if (debug) console.log ("Call", node, f, m.v); | ||||
|     const r = f.apply (target, m.v); | ||||
|  | @ -227,6 +272,9 @@ function processMessage (m) { | |||
|         case "setAttr": | ||||
|             msgSetAttr (m); | ||||
|             break; | ||||
|         case "remAttr": | ||||
|             msgRemAttr (m); | ||||
|             break; | ||||
|         case "call": | ||||
|             msgCall (m); | ||||
|             break; | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ namespace Ooui | |||
| { | ||||
|     public class Div : Element | ||||
|     { | ||||
|         protected override bool HtmlNeedsFullEndElement => true; | ||||
| 
 | ||||
|         public Div () | ||||
|             : base ("div") | ||||
|         { | ||||
|  |  | |||
							
								
								
									
										164
									
								
								Ooui/Element.cs
								
								
								
								
							
							
						
						
									
										164
									
								
								Ooui/Element.cs
								
								
								
								
							|  | @ -1,28 +1,29 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| 
 | ||||
| namespace Ooui | ||||
| { | ||||
|     public abstract class Element : Node | ||||
|     { | ||||
|         string className = ""; | ||||
|         readonly Dictionary<string, object> attributes = new Dictionary<string, object> (); | ||||
| 
 | ||||
|         public string ClassName { | ||||
|             get => className; | ||||
|             set => SetProperty (ref className, value, "className"); | ||||
|             get => GetStringAttribute ("class", ""); | ||||
|             set => SetAttributeProperty ("class", value); | ||||
|         } | ||||
| 
 | ||||
|         public Style Style { get; private set; } = new Style (); | ||||
| 
 | ||||
|         string title = ""; | ||||
|         public string Title { | ||||
|             get => title; | ||||
|             set => SetProperty (ref title, value, "title"); | ||||
|             get => GetStringAttribute ("title", ""); | ||||
|             set => SetAttributeProperty ("title", value); | ||||
|         } | ||||
| 
 | ||||
|         bool hidden = false; | ||||
|         public bool IsHidden { | ||||
|             get => hidden; | ||||
|             set => SetProperty (ref hidden, value, "hidden"); | ||||
|             get => GetBooleanAttribute ("hidden"); | ||||
|             set => SetBooleanAttributeProperty ("hidden", value); | ||||
|         } | ||||
| 
 | ||||
|         public event TargetEventHandler Click { | ||||
|  | @ -102,8 +103,64 @@ namespace Ooui | |||
|             Style.PropertyChanged += HandleStylePropertyChanged; | ||||
|         } | ||||
| 
 | ||||
|         public void SetAttribute (string attributeName, string value) | ||||
|         protected bool SetAttributeProperty (string attributeName, object newValue, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") | ||||
|         { | ||||
|             var old = GetAttribute (attributeName); | ||||
|             if (old != null && old.Equals (newValue)) | ||||
|                 return false; | ||||
|             SetAttribute (attributeName, newValue); | ||||
|             OnPropertyChanged (propertyName); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         protected bool SetBooleanAttributeProperty (string attributeName, bool newValue, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") | ||||
|         { | ||||
|             var old = GetAttribute (attributeName) != null; | ||||
|             if (old != newValue) | ||||
|                 return false; | ||||
|             if (newValue) | ||||
|                 SetAttribute (attributeName, string.Empty); | ||||
|             else | ||||
|                 RemoveAttribute (attributeName); | ||||
|             OnPropertyChanged (propertyName); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         protected bool UpdateAttributeProperty (string attributeName, object newValue, string propertyName) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 if (attributes.TryGetValue (attributeName, out var oldValue)) { | ||||
|                     if (newValue != null && newValue.Equals (oldValue)) | ||||
|                         return false; | ||||
|                 } | ||||
|                 attributes[attributeName] = newValue; | ||||
|             } | ||||
|             OnPropertyChanged (propertyName); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         protected bool UpdateBooleanAttributeProperty (string attributeName, bool newValue, string propertyName) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 var oldValue = attributes.ContainsKey (attributeName); | ||||
|                 if (newValue == oldValue) | ||||
|                     return false; | ||||
|                 if (newValue) { | ||||
|                     attributes[attributeName] = ""; | ||||
|                 } | ||||
|                 else { | ||||
|                     attributes.Remove (attributeName); | ||||
|                 } | ||||
|             } | ||||
|             OnPropertyChanged (propertyName); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public void SetAttribute (string attributeName, object value) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 attributes[attributeName] = value; | ||||
|             } | ||||
|             Send (new Message { | ||||
|                 MessageType = MessageType.SetAttribute, | ||||
|                 TargetId = Id, | ||||
|  | @ -112,6 +169,62 @@ namespace Ooui | |||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public object GetAttribute (string attributeName) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 attributes.TryGetValue (attributeName, out var v); | ||||
|                 return v; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public T GetAttribute<T> (string attributeName, T defaultValue) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 attributes.TryGetValue (attributeName, out var v); | ||||
|                 if (v is T) { | ||||
|                     return (T)v; | ||||
|                 } | ||||
|                 else { | ||||
|                     return defaultValue; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool GetBooleanAttribute (string attributeName) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 return attributes.TryGetValue (attributeName, out var _); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public string GetStringAttribute (string attributeName, string defaultValue) | ||||
|         { | ||||
|             lock (attributes) { | ||||
|                 if (attributes.TryGetValue (attributeName, out var v)) { | ||||
|                     if (v == null) return "null"; | ||||
|                     else return v.ToString (); | ||||
|                 } | ||||
|                 else { | ||||
|                     return defaultValue; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAttribute (string attributeName) | ||||
|         { | ||||
|             bool removed; | ||||
|             lock (attributes) { | ||||
|                 removed = attributes.Remove (attributeName); | ||||
|             } | ||||
|             if (removed) { | ||||
|                 Send (new Message { | ||||
|                     MessageType = MessageType.RemoveAttribute, | ||||
|                     TargetId = Id, | ||||
|                     Key = attributeName, | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void HandleStylePropertyChanged (object sender, PropertyChangedEventArgs e) | ||||
|         { | ||||
|             SendSet ("style." + Style.GetJsName (e.PropertyName), Style[e.PropertyName]); | ||||
|  | @ -130,5 +243,38 @@ namespace Ooui | |||
|                     return base.SaveStateMessageIfNeeded (message); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         protected virtual bool HtmlNeedsFullEndElement => false; | ||||
| 
 | ||||
|         public override void WriteOuterHtml (System.Xml.XmlWriter w) | ||||
|         { | ||||
|             w.WriteStartElement (TagName); | ||||
|             w.WriteAttributeString ("id", Id); | ||||
|             var style = Style.ToString (); | ||||
|             if (style.Length > 0) { | ||||
|                 w.WriteAttributeString ("style", style); | ||||
|             } | ||||
|             lock (attributes) { | ||||
|                 foreach (var a in attributes) { | ||||
|                     var value = (a.Value == null) ? "null" : Convert.ToString (a.Value, System.Globalization.CultureInfo.InvariantCulture); | ||||
|                     w.WriteAttributeString (a.Key, value); | ||||
|                 } | ||||
|             } | ||||
|             WriteInnerHtml (w); | ||||
|             if (HtmlNeedsFullEndElement) { | ||||
|                 w.WriteFullEndElement (); | ||||
|             } | ||||
|             else { | ||||
|                 w.WriteEndElement (); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public virtual void WriteInnerHtml (System.Xml.XmlWriter w) | ||||
|         { | ||||
|             var children = Children; | ||||
|             foreach (var c in children) { | ||||
|                 c.WriteOuterHtml (w); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -83,12 +83,12 @@ namespace Ooui | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         protected bool SetProperty<T> (ref T backingStore, T newValue, string attributeName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") | ||||
|         protected bool SetProperty<T> (ref T backingStore, T newValue, string jsPropertyName, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") | ||||
|         { | ||||
|             if (EqualityComparer<T>.Default.Equals (backingStore, newValue)) | ||||
|                 return false; | ||||
|             backingStore = newValue; | ||||
|             SendSet (attributeName, newValue); | ||||
|             SendSet (jsPropertyName, newValue); | ||||
|             OnPropertyChanged (propertyName); | ||||
|             return true; | ||||
|         } | ||||
|  | @ -120,12 +120,12 @@ namespace Ooui | |||
|             Send (Message.Call (Id, methodName, args)); | ||||
|         } | ||||
| 
 | ||||
|         protected void SendSet (string attributeName, object value) | ||||
|         protected void SendSet (string jsPropertyName, object value) | ||||
|         { | ||||
|             Send (new Message { | ||||
|                 MessageType = MessageType.Set, | ||||
|                 TargetId = Id, | ||||
|                 Key = attributeName, | ||||
|                 Key = jsPropertyName, | ||||
|                 Value = value, | ||||
|             }); | ||||
|         } | ||||
|  | @ -169,6 +169,11 @@ namespace Ooui | |||
|                         state.Add (message); | ||||
|                     }); | ||||
|                     break; | ||||
|                 case MessageType.RemoveAttribute: | ||||
|                     this.UpdateStateMessages (state => { | ||||
|                         state.RemoveAll (x => x.MessageType == MessageType.SetAttribute && x.Key == message.Key); | ||||
|                     }); | ||||
|                     return true; | ||||
|                 case MessageType.Listen: | ||||
|                     AddStateMessage (message); | ||||
|                     break; | ||||
|  |  | |||
							
								
								
									
										14
									
								
								Ooui/Form.cs
								
								
								
								
							
							
						
						
									
										14
									
								
								Ooui/Form.cs
								
								
								
								
							|  | @ -6,20 +6,18 @@ namespace Ooui | |||
|     { | ||||
|         string action = ""; | ||||
|         public string Action { | ||||
|             get => action; | ||||
|             set => SetProperty (ref action, value ?? "", "action"); | ||||
|             get => GetStringAttribute ("action", ""); | ||||
|             set => SetAttributeProperty ("action", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
| 		string method = "GET"; | ||||
| 		public string Method { | ||||
| 			get => method; | ||||
| 			set => SetProperty (ref method, value ?? "", "method"); | ||||
|             get => GetStringAttribute ("method", "GET"); | ||||
|             set => SetAttributeProperty ("method", value ?? ""); | ||||
| 		} | ||||
| 
 | ||||
| 		string enctype = "application/x-www-form-urlencoded"; | ||||
| 		public string EncodingType { | ||||
| 			get => enctype; | ||||
| 			set => SetProperty (ref enctype, value ?? "", "enctype"); | ||||
|             get => GetStringAttribute ("enctype", "application/x-www-form-urlencoded"); | ||||
|             set => SetAttributeProperty ("enctype", value ?? ""); | ||||
| 		} | ||||
| 
 | ||||
| 		public event TargetEventHandler Submit { | ||||
|  |  | |||
|  | @ -4,16 +4,15 @@ namespace Ooui | |||
| { | ||||
|     public abstract class FormControl : Element | ||||
|     { | ||||
|         string name = ""; | ||||
|         public string Name { | ||||
|             get => name; | ||||
|             set => SetProperty (ref name, value, "name"); | ||||
|             get => GetStringAttribute ("name", ""); | ||||
|             set => SetAttributeProperty ("name", value); | ||||
|         } | ||||
| 
 | ||||
|         bool isDisabled = false; | ||||
|         public bool IsDisabled { | ||||
|             get => isDisabled; | ||||
|             set => SetProperty (ref isDisabled, value, "disabled"); | ||||
|             get => GetBooleanAttribute ("disabled"); | ||||
|             set => SetBooleanAttributeProperty ("disabled", value); | ||||
|         } | ||||
| 
 | ||||
|         public FormControl (string tagName) | ||||
|  |  | |||
|  | @ -2,17 +2,15 @@ | |||
| { | ||||
|     public class Iframe : Element | ||||
|     { | ||||
|         public Iframe() | ||||
|                 : base("iframe") | ||||
|         public string Source | ||||
|         { | ||||
| 
 | ||||
|             get => GetStringAttribute ("src", null); | ||||
|             set => SetAttributeProperty ("src", value); | ||||
|         } | ||||
| 
 | ||||
|         string src = null; | ||||
|         public string Src | ||||
|         public Iframe () | ||||
|             : base ("iframe") | ||||
|         { | ||||
|             get => src; | ||||
|             set => SetProperty(ref src, value, "src"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,10 +4,10 @@ namespace Ooui | |||
| { | ||||
|     public class Image : Element | ||||
|     { | ||||
|         string src = ""; | ||||
|         public string Source { | ||||
|             get => src; | ||||
|             set => SetProperty (ref src, value ?? "", "src"); | ||||
|         public string Source | ||||
|         { | ||||
|             get => GetStringAttribute ("src", null); | ||||
|             set => SetAttributeProperty ("src", value); | ||||
|         } | ||||
| 
 | ||||
|         public Image () | ||||
|  |  | |||
|  | @ -7,16 +7,14 @@ namespace Ooui | |||
| { | ||||
|     public class Input : FormControl | ||||
|     { | ||||
|         InputType typ = InputType.Text; | ||||
|         public InputType Type { | ||||
|             get => typ; | ||||
|             set => SetProperty (ref typ, value, "type"); | ||||
|             get => GetAttribute ("type", InputType.Text); | ||||
|             set => SetAttributeProperty ("type", value); | ||||
|         } | ||||
| 
 | ||||
|         string val = ""; | ||||
|         public string Value { | ||||
|             get => val; | ||||
|             set => SetProperty (ref val, value ?? "", "value"); | ||||
|             get => GetStringAttribute ("value", ""); | ||||
|             set => SetAttributeProperty ("value", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
|         public double NumberValue { | ||||
|  | @ -35,37 +33,33 @@ namespace Ooui | |||
|             remove => RemoveEventListener ("change", value); | ||||
|         } | ||||
| 
 | ||||
|         string placeholder = ""; | ||||
|         public string Placeholder { | ||||
|             get => placeholder; | ||||
|             set => SetProperty (ref placeholder, value, "placeholder"); | ||||
|             get => GetStringAttribute ("placeholder", ""); | ||||
|             set => SetAttributeProperty ("placeholder", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
|         bool isChecked = false; | ||||
|         public bool IsChecked { | ||||
|             get => isChecked; | ||||
|             get => GetBooleanAttribute ("checked"); | ||||
|             set { | ||||
|                 SetProperty (ref isChecked, value, "checked"); | ||||
|                 TriggerEventFromMessage (Message.Event (Id, "change", isChecked)); | ||||
|                 if (SetBooleanAttributeProperty ("checked", value)) { | ||||
|                     TriggerEventFromMessage (Message.Event (Id, "change", IsChecked)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         double minimum = 0; | ||||
|         public double Minimum { | ||||
|             get => minimum; | ||||
|             set => SetProperty (ref minimum, value, "min"); | ||||
|             get => GetAttribute ("min", 0.0); | ||||
|             set => SetAttributeProperty ("min", value); | ||||
|         } | ||||
| 
 | ||||
|         double maximum = 100; | ||||
|         public double Maximum { | ||||
|             get => maximum; | ||||
|             set => SetProperty (ref maximum, value, "max"); | ||||
|             get => GetAttribute ("max", 100.0); | ||||
|             set => SetAttributeProperty ("max", value); | ||||
|         } | ||||
| 
 | ||||
|         double step = 1; | ||||
|         public double Step { | ||||
|             get => step; | ||||
|             set => SetProperty (ref step, value, "step"); | ||||
|             get => GetAttribute ("step", 1.0); | ||||
|             set => SetAttributeProperty ("step", value); | ||||
|         } | ||||
| 
 | ||||
|         public Input () | ||||
|  | @ -86,10 +80,10 @@ namespace Ooui | |||
|             if (message.TargetId == Id && message.MessageType == MessageType.Event && (message.Key == "change" || message.Key == "input")) { | ||||
|                 // Don't need to notify here because the base implementation will fire the event | ||||
|                 if (Type == InputType.Checkbox) { | ||||
|                     isChecked = message.Value != null ? Convert.ToBoolean (message.Value) : false; | ||||
|                     UpdateBooleanAttributeProperty ("checked", message.Value != null ? Convert.ToBoolean (message.Value) : false, "IsChecked"); | ||||
|                 } | ||||
|                 else { | ||||
|                     val = message.Value != null ? Convert.ToString (message.Value) : ""; | ||||
|                     UpdateAttributeProperty ("value", message.Value != null ? Convert.ToString (message.Value) : "", "Value"); | ||||
|                 } | ||||
|             } | ||||
|             return base.TriggerEventFromMessage (message); | ||||
|  |  | |||
|  | @ -4,10 +4,9 @@ namespace Ooui | |||
| { | ||||
|     public class Label : Element | ||||
|     { | ||||
|         Element htmlFor = null; | ||||
|         public Element For { | ||||
|             get => htmlFor; | ||||
|             set => SetProperty (ref htmlFor, value, "htmlFor"); | ||||
|             get => GetAttribute<Element> ("for", null); | ||||
|             set => SetAttributeProperty ("for", value); | ||||
|         } | ||||
| 
 | ||||
|         public Label () | ||||
|  |  | |||
|  | @ -48,6 +48,8 @@ namespace Ooui | |||
|         Set, | ||||
|         [EnumMember (Value = "setAttr")] | ||||
|         SetAttribute, | ||||
|         [EnumMember(Value = "remAttr")] | ||||
|         RemoveAttribute, | ||||
|         [EnumMember(Value = "call")] | ||||
|         Call, | ||||
|         [EnumMember(Value = "listen")] | ||||
|  |  | |||
							
								
								
									
										19
									
								
								Ooui/Node.cs
								
								
								
								
							
							
						
						
									
										19
									
								
								Ooui/Node.cs
								
								
								
								
							|  | @ -180,5 +180,24 @@ namespace Ooui | |||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public virtual string OuterHtml { | ||||
|             get { | ||||
|                 using (var stream = new System.IO.MemoryStream ()) { | ||||
|                     var settings = new System.Xml.XmlWriterSettings { | ||||
|                         OmitXmlDeclaration = true, | ||||
|                         ConformanceLevel = System.Xml.ConformanceLevel.Fragment, | ||||
|                         CloseOutput = false, | ||||
|                     }; | ||||
|                     using (var w = System.Xml.XmlWriter.Create (stream, settings)) { | ||||
|                         WriteOuterHtml (w); | ||||
|                     } | ||||
|                     stream.Position = 0; | ||||
|                     return new System.IO.StreamReader (stream).ReadToEnd (); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public abstract void WriteOuterHtml (System.Xml.XmlWriter w); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -4,22 +4,19 @@ namespace Ooui | |||
| { | ||||
|     public class Option : Element | ||||
|     { | ||||
|         string val = ""; | ||||
|         public string Value { | ||||
|             get => val; | ||||
|             set => SetProperty (ref val, value ?? "", "value"); | ||||
|             get => GetStringAttribute ("value", ""); | ||||
|             set => SetAttributeProperty ("value", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
|         string label = ""; | ||||
|         public string Label { | ||||
|             get => label; | ||||
|             set => SetProperty (ref label, value ?? "", "label"); | ||||
|             get => GetStringAttribute ("label", ""); | ||||
|             set => SetAttributeProperty ("label", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
|         bool defaultSelected = false; | ||||
|         public bool DefaultSelected { | ||||
|             get => defaultSelected; | ||||
|             set => SetProperty (ref defaultSelected, value, "defaultSelected"); | ||||
|             get => GetBooleanAttribute ("selected"); | ||||
|             set => SetBooleanAttributeProperty ("selected", value); | ||||
|         } | ||||
| 
 | ||||
|         public Option () | ||||
|  |  | |||
|  | @ -4,10 +4,9 @@ namespace Ooui | |||
| { | ||||
|     public class Select : FormControl | ||||
|     { | ||||
|         string val = ""; | ||||
|         public string Value { | ||||
|             get => val; | ||||
|             set => SetProperty (ref val, value ?? "", "value"); | ||||
|             get => GetStringAttribute ("value", ""); | ||||
|             set => SetAttributeProperty ("value", value ?? ""); | ||||
|         } | ||||
| 
 | ||||
|         public event TargetEventHandler Change { | ||||
|  | @ -35,6 +34,7 @@ namespace Ooui | |||
|         protected override void OnChildInsertedBefore (Node newChild, Node referenceChild) | ||||
|         { | ||||
|             base.OnChildInsertedBefore (newChild, referenceChild); | ||||
|             var val = Value; | ||||
|             if (string.IsNullOrEmpty (val) && newChild is Option o && !string.IsNullOrEmpty (o.Value)) { | ||||
|                 val = o.Value; | ||||
|             } | ||||
|  | @ -43,7 +43,8 @@ namespace Ooui | |||
|         protected override bool TriggerEventFromMessage (Message message) | ||||
|         { | ||||
|             if (message.TargetId == Id && message.MessageType == MessageType.Event && (message.Key == "change" || message.Key == "input")) { | ||||
|                 val = message.Value != null ? Convert.ToString (message.Value) : ""; | ||||
|                 SetAttribute ("value", message.Value != null ? Convert.ToString (message.Value) : ""); | ||||
|                 OnPropertyChanged ("Value"); | ||||
|             } | ||||
|             return base.TriggerEventFromMessage (message); | ||||
|         } | ||||
|  |  | |||
|  | @ -399,7 +399,7 @@ namespace Ooui | |||
|                     o.Append (head); | ||||
|                     o.Append (p.Key); | ||||
|                     o.Append (":"); | ||||
|                     o.Append (String.Format (System.Globalization.CultureInfo.InvariantCulture, "{0}", p.Value)); | ||||
|                     o.Append (Convert.ToString (p.Value, System.Globalization.CultureInfo.InvariantCulture)); | ||||
|                     head = ";"; | ||||
|                 } | ||||
|             } | ||||
|  |  | |||
|  | @ -20,18 +20,19 @@ namespace Ooui | |||
|             set => SetProperty (ref val, value ?? "", "value"); | ||||
|         } | ||||
| 
 | ||||
|         int rows = 2; | ||||
|         public int Rows { | ||||
|             get => rows; | ||||
|             set => SetProperty (ref rows, value, "rows"); | ||||
|             get => GetAttribute ("rows", 2); | ||||
|             set => SetAttributeProperty ("rows", value); | ||||
|         } | ||||
| 
 | ||||
|         int cols = 20; | ||||
|         public int Columns { | ||||
|             get => cols; | ||||
|             set => SetProperty (ref cols, value, "cols"); | ||||
|             get => GetAttribute ("cols", 20); | ||||
|             set => SetAttributeProperty ("cols", value); | ||||
|         } | ||||
| 
 | ||||
|         protected override bool HtmlNeedsFullEndElement => true; | ||||
| 
 | ||||
|         public TextArea () | ||||
|             : base ("textarea") | ||||
|         { | ||||
|  | @ -53,5 +54,10 @@ namespace Ooui | |||
|             } | ||||
|             return base.TriggerEventFromMessage (message); | ||||
|         } | ||||
| 
 | ||||
|         public override void WriteInnerHtml (System.Xml.XmlWriter w) | ||||
|         { | ||||
|             w.WriteString (val ?? ""); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -20,5 +20,10 @@ namespace Ooui | |||
|         { | ||||
|             Text = text; | ||||
|         } | ||||
| 
 | ||||
|         public override void WriteOuterHtml (System.Xml.XmlWriter w) | ||||
|         { | ||||
|             w.WriteString (text); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -44,7 +44,10 @@ namespace Ooui | |||
|   <style>@Styles</style> | ||||
| </head> | ||||
| <body> | ||||
| <div id=""ooui-body"" class=""container-fluid""></div> | ||||
| 
 | ||||
| <div id=""ooui-body"" class=""container-fluid""> | ||||
| @InitialHtml | ||||
| </div> | ||||
| 
 | ||||
| <script type=""text/javascript"" src=""https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js""></script> | ||||
| <script type=""text/javascript"" src=""https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js""></script> | ||||
|  | @ -390,9 +393,9 @@ namespace Ooui | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static string RenderTemplate (string webSocketPath, string title = "") | ||||
|         public static string RenderTemplate (string webSocketPath, string title = "", string initialHtml = "") | ||||
|         { | ||||
|             return Template.Replace ("@WebSocketPath", webSocketPath).Replace ("@Styles", rules.ToString ()).Replace ("@Title", title); | ||||
|             return Template.Replace ("@WebSocketPath", webSocketPath).Replace ("@Styles", rules.ToString ()).Replace ("@Title", title).Replace ("@InitialHtml", initialHtml); | ||||
|         } | ||||
| 
 | ||||
|         class DataHandler : RequestHandler | ||||
|  |  | |||
|  | @ -58,8 +58,8 @@ namespace Tests | |||
|             Assert.AreEqual (480, c.Height); | ||||
|             c.Width = 0; | ||||
|             c.Height = -100; | ||||
|             Assert.AreEqual (150, c.Width); | ||||
|             Assert.AreEqual (150, c.Height); | ||||
|             Assert.AreEqual (0, c.Width); | ||||
|             Assert.AreEqual (0, c.Height); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,95 @@ | |||
| using System; | ||||
| 
 | ||||
| #if NUNIT | ||||
| using NUnit.Framework; | ||||
| using TestClassAttribute = NUnit.Framework.TestFixtureAttribute; | ||||
| using TestMethodAttribute = NUnit.Framework.TestCaseAttribute; | ||||
| #else | ||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
| #endif | ||||
| 
 | ||||
| using Ooui; | ||||
| 
 | ||||
| namespace Tests | ||||
| { | ||||
|     [TestClass] | ||||
|     public class WriteHtmlTests | ||||
|     { | ||||
|         System.Text.RegularExpressions.Regex idre = new System.Text.RegularExpressions.Regex ("\\sid=\"[^\"]*\""); | ||||
| 
 | ||||
|         string OuterHtmlWithoutIds (Element e) | ||||
|         { | ||||
|             return idre.Replace (e.OuterHtml, ""); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void TextAreaWithTextStyled () | ||||
|         { | ||||
|             var e = new TextArea { | ||||
|                 Value = "Hello World!", | ||||
|             }; | ||||
|             e.Style.BackgroundColor = "#18f"; | ||||
|             Assert.AreEqual ("<textarea style=\"background-color:#18f\">Hello World!</textarea>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void TextAreaEmptyStyled () | ||||
|         { | ||||
|             var e = new TextArea (); | ||||
|             e.Style.BackgroundColor = "#18f"; | ||||
|             Assert.AreEqual ("<textarea style=\"background-color:#18f\"></textarea>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void Style () | ||||
|         { | ||||
|             var e = new Div (); | ||||
|             e.Style.BackgroundColor = "#18f"; | ||||
|             Assert.AreEqual ("<div style=\"background-color:#18f\"></div>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void TwoGrandChildren () | ||||
|         { | ||||
|             var e = new Div (new Div (new Anchor (), new Anchor ()), new Paragraph ()); | ||||
|             Assert.AreEqual ("<div><div><a /><a /></div><p /></div>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void Child () | ||||
|         { | ||||
|             var e = new Div (new Anchor ()); | ||||
|             Assert.AreEqual ("<div><a /></div>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void TextChild () | ||||
|         { | ||||
|             var e = new Paragraph ("Hello world!"); | ||||
|             Assert.AreEqual ("<p>Hello world!</p>", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void IdIsFirst () | ||||
|         { | ||||
|             var e = new Anchor (); | ||||
|             Assert.IsTrue (e.OuterHtml.StartsWith ("<a id=\"")); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void EmptyElement () | ||||
|         { | ||||
|             var e = new Anchor (); | ||||
|             Assert.AreEqual ("<a />", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
| 
 | ||||
|         [TestMethod] | ||||
|         public void AnchorHRef () | ||||
|         { | ||||
|             var e = new Anchor { | ||||
|                 HRef = "http://google.com" | ||||
|             }; | ||||
|             Assert.AreEqual ("<a href=\"http://google.com\" />", OuterHtmlWithoutIds (e)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue