massive update

This commit is contained in:
Michael Becker 2024-08-19 15:32:31 -04:00
parent 96df91bd53
commit f0542c03f9
15 changed files with 352 additions and 48 deletions

View File

@ -1,22 +1,36 @@
using System.Text;
using System.Xml;
using MBS.Core.Drawing;
using MBS.Web.UI;
namespace MBS.Web;
public abstract class Control : IWebHandler
{
public class ControlCollection
: System.Collections.ObjectModel.Collection<Control>
private WebContext? _Context = null;
public WebContext? Context
{
get { return _Context; }
internal set
{
bool changed = _Context != value;
_Context = value;
if (changed)
{
OnContextChanged(EventArgs.Empty);
}
}
}
protected virtual void OnContextChanged(EventArgs e)
{
}
public WebContext? Context { get; internal set; } = null;
public Dictionary<string, string> PathVariables { get; } = new Dictionary<string, string>();
public Dictionary<string, string> StyleProperties { get; } = new Dictionary<string, string>();
public bool Visible { get; set; } = true;
public Measurement Width { get; set; } = Measurement.Empty;
public Control(Dictionary<string, string>? pathVariables = null)
{
@ -44,10 +58,14 @@ public abstract class Control : IWebHandler
return new string[0];
}
private IReadOnlyDictionary<string, string> _emptyStyleProperties = new Dictionary<string, string>();
protected virtual IReadOnlyDictionary<string, string> GetStyleProperties()
{
return _emptyStyleProperties;
Dictionary<string, string> styleProperties = new Dictionary<string, string>();
if (Width != Measurement.Empty)
{
styleProperties["width"] = Width.ToString();
}
return styleProperties;
}
private bool _initted = false;

View File

@ -1,5 +1,6 @@
using MBS.Core;
using MBS.Core.Collections.Generic;
namespace MBS.Web.UI.HtmlControls;
@ -9,10 +10,19 @@ public class HtmlAnchor : HtmlGenericControl
public string? TargetFrame { get; set; }
public string TargetUrl { get; set; }
public HtmlAnchor(string targetUrl, string? targetFrame = null) : base("a")
public HtmlAnchor(string targetUrl, string? targetFrame = null, string? content = null, IEnumerable<KeyValuePair<string, string>>? attributes = null, IEnumerable<string>? classes = null, IEnumerable<KeyValuePair<string, string>>? styleProperties = null) : base("a", attributes, classes, content)
{
TargetUrl = targetUrl;
TargetFrame = targetFrame;
Content = content;
if (attributes != null)
{
Attributes.AddRange(attributes);
}
if (styleProperties != null)
{
StyleProperties.AddRange(styleProperties);
}
}
protected override IDictionary<string, string> GetControlAttributes()

View File

@ -11,27 +11,17 @@ public class HtmlGenericControl : Container
public string? Content { get; set; } = null;
public HtmlGenericControl(string tagName)
public HtmlGenericControl(string tagName, IEnumerable<KeyValuePair<string, string>>? attributes = null, IEnumerable<string>? classes = null, string? content = null)
{
_tagName = tagName;
}
public HtmlGenericControl(string tagName, IEnumerable<KeyValuePair<string, string>> attributes, IList<string> classes, string? content = null)
{
_tagName = tagName;
Attributes.AddRange(attributes);
ClassList.AddRange(classes);
Content = content;
}
public HtmlGenericControl(string tagName, IEnumerable<KeyValuePair<string, string>> attributes, string? content = null)
{
_tagName = tagName;
Attributes.AddRange(attributes);
Content = content;
}
public HtmlGenericControl(string tagName, IEnumerable<string> classes, string? content = null)
{
_tagName = tagName;
ClassList.AddRange(classes);
if (attributes != null)
{
Attributes.AddRange(attributes);
}
if (classes != null)
{
ClassList.AddRange(classes);
}
Content = content;
}

View File

@ -29,6 +29,10 @@ public abstract class WebControl : Control
case ThemeColorPreset.Warning: styleClasses.Add("uwt-color-warning"); break;
case ThemeColorPreset.Danger: styleClasses.Add("uwt-color-danger"); break;
}
if (Visible)
{
styleClasses.Add("uwt-visible");
}
return styleClasses;
}

View File

@ -9,14 +9,57 @@ public class Button : WebControlWithMnemonic
protected override string TagName => "button"; // UseSubmitBehavior ? "input" : "button";
public Button() : base("") { }
public Button(string text) : base(text) { }
public Control? DropDown { get; set; } = null;
protected override IEnumerable<string> GetStyleClasses()
{
if (DropDown != null)
{
return base.GetStyleClasses().Union(["uwt-button-dropdownbutton"]);
}
return base.GetStyleClasses();
}
protected override void RenderBeginTag(XmlWriter writer)
{
if (DropDown != null)
{
writer.WriteStartElement("div");
writer.WriteAttributeString("class", "uwt-button");
writer.WriteStartElement("span");
writer.WriteAttributeString("class", "uwt-title");
writer.WriteEndElement();
}
base.RenderBeginTag(writer);
}
protected override void RenderContents(XmlWriter writer)
{
// if (!UseSubmitBehavior)
{
WriteTextWithMnemonic(writer);
}
}
}
protected override void RenderEndTag(XmlWriter writer)
{
base.RenderEndTag(writer);
if (DropDown != null)
{
writer.WriteStartElement("div");
writer.WriteAttributeString("class", "uwt-popup");
DropDown.Context = Context;
DropDown.Render(writer);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
protected override IDictionary<string, string> GetControlAttributes()

View File

@ -1,3 +1,5 @@
using MBS.Core.Collections.Generic;
namespace MBS.Web.UI.WebControls;
public class Container : ContainerBase
@ -8,12 +10,20 @@ public class Container : ContainerBase
public Container()
{
}
public Container(string tagName)
public Container(string tagName, IEnumerable<string> classList = null, IEnumerable<Control> controls = null)
{
_tagName = tagName;
if (classList != null)
{
ClassList.AddRange(classList);
}
if (controls != null)
{
Controls.AddRange(controls);
}
}
public Control.ControlCollection Controls { get; } = new Control.ControlCollection();
public IList<Control> Controls { get; set; } = new List<Control>();
protected override IList<Control> GetChildControls()
{

View File

@ -4,13 +4,22 @@ namespace MBS.Web.UI.WebControls;
public abstract class ContainerBase : WebControl
{
private List<Control> _list = new List<Control>();
protected virtual IList<Control> GetChildControls()
private IEnumerable<Control> _list = [ ];
protected virtual IEnumerable<Control> GetChildControls()
{
return _list;
}
private IList<Control>? _childControls = null;
private IEnumerable<Control>? _childControls = null;
protected override void OnContextChanged(EventArgs e)
{
base.OnContextChanged(e);
foreach (Control ctl in GetChildControls())
{
ctl.Context = Context;
}
}
protected override void RenderContents(XmlWriter writer)
{

View File

@ -0,0 +1,63 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using System.Xml;
using MBS.Core;
namespace MBS.Web.UI.WebControls;
public class DockableContainer : Container
{
protected override void RenderBeginTag(XmlWriter writer)
{
base.RenderBeginTag(writer);
writer.WriteStartElement("div");
writer.WriteAttributeString("class", "uwt-gripper");
writer.WriteEndElement();
/*
writer.WriteStartElement("div");
writer.WriteAttributeString("class", "uwt-header");
writer.WriteEndElement();
*/
writer.WriteStartElement("div");
writer.WriteAttributeString("class", "uwt-content");
}
protected override void RenderEndTag(XmlWriter writer)
{
writer.WriteEndElement();
base.RenderEndTag(writer);
}
public CardinalDirection Position { get; set; } = CardinalDirection.Bottom;
protected override IEnumerable<string> GetStyleClasses()
{
string uwtDockPosition = "";
switch (Position)
{
case CardinalDirection.Top: uwtDockPosition = "uwt-dock-top"; break;
case CardinalDirection.Left: uwtDockPosition = "uwt-dock-left"; break;
case CardinalDirection.Right: uwtDockPosition = "uwt-dock-right"; break;
case CardinalDirection.Bottom: uwtDockPosition = "uwt-dock-bottom"; break;
}
return base.GetStyleClasses().Union([ "uwt-dockable", uwtDockPosition ]);
}
}

View File

@ -14,9 +14,9 @@ public class FormView : ContainerBase
}
public string Title { get; set; }
public WebControl Control { get; set; }
public Control Control { get; set; }
public FormViewItem(string title, WebControl control)
public FormViewItem(string title, Control control)
{
Title = title;
Control = control;
@ -51,7 +51,7 @@ public class FormView : ContainerBase
tdContent.ClassList.Add("uwt-formview-item-content");
if (lbl.HasMnemonic)
{
item.Control.Attributes.Add("accesskey", lbl.MnemonicChar.ToString());
item.Control.Attributes["accesskey"] = lbl.MnemonicChar.ToString();
}
tdContent.Controls.Add(item.Control);
tr.Controls.Add(tdContent);

View File

@ -0,0 +1,44 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace MBS.Web.UI.WebControls;
public class Image : WebControl
{
protected override string TagName => "img";
public Image()
{
}
public Image(string targetUrl)
{
TargetUrl = targetUrl;
}
public string TargetUrl { get; set; } = "";
protected override IDictionary<string, string> GetControlAttributes()
{
IDictionary<string, string> dict = base.GetControlAttributes();
dict["src"] = Context.ExpandRelativePath(TargetUrl);
return dict;
}
}

View File

@ -1,11 +1,31 @@
namespace MBS.Web.UI.WebControls;
public class Menu : WebControl
public class Menu : ContainerBase
{
protected override string TagName => "ul";
protected override IEnumerable<string> GetStyleClasses()
{
return [ "uwt-menu" ];
}
}
private IEnumerable<MenuItem>? _items = null;
public Menu()
{
}
public Menu(IEnumerable<MenuItem> items)
{
_items = items;
}
protected override IEnumerable<Control> GetChildControls()
{
if (_items != null)
{
return _items;
}
return [];
}
}

View File

@ -0,0 +1,61 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace MBS.Web.UI.WebControls;
using System.Collections.Generic;
using MBS.Web.UI;
using MBS.Web.UI.HtmlControls;
public abstract class MenuItem : ContainerBase
{
protected override string TagName => "li";
protected override IEnumerable<string> GetStyleClasses()
{
return base.GetStyleClasses().Union(["uwt-menu-item"]);
}
}
public class CommandMenuItem : MenuItem
{
protected override IEnumerable<string> GetStyleClasses()
{
return base.GetStyleClasses().Union(["uwt-menu-item-command"]);
}
public string Text { get; set; }
public bool UseMnemonic { get; set; } = false;
public string TargetUrl { get; set; } = "";
public CommandMenuItem(string text, string targetUrl = "")
{
Text = text;
TargetUrl = targetUrl;
}
protected override IEnumerable<Control> GetChildControls()
{
HtmlAnchor a = new HtmlAnchor("#") { Content = Text };
if (!String.IsNullOrEmpty(TargetUrl))
{
a.TargetUrl = TargetUrl;
}
return [a];
}
}

View File

@ -19,6 +19,7 @@ public class TextBox : WebControl
protected override string TagName => "input";
public string Name { get; set; }
public string? Value { get; set; } = null;
private string GetTextBoxType()
{
@ -35,6 +36,10 @@ public class TextBox : WebControl
IDictionary<string, string> dict = base.GetControlAttributes();
dict["type"] = GetTextBoxType();
dict["name"] = Name;
if (Value != null)
{
dict["value"] = Value;
}
return dict;
}
}

View File

@ -9,11 +9,13 @@ public class WebPage : Control
public WebPage(Dictionary<string, string>? pathVariables = null) : base(pathVariables) { }
public Control.ControlCollection HeaderControls { get; } = new Control.ControlCollection();
public Control.ControlCollection Controls { get; } = new Control.ControlCollection();
public IList<Control> HeaderControls { get; set; } = new List<Control>();
public IList<Control> Controls { get; set; } = new List<Control>();
public WebStyleSheet.WebStyleSheetCollection StyleSheets { get; } = new WebStyleSheet.WebStyleSheetCollection();
public string Title { get; set; } = "";
private bool ChildControlsCreated { get; set; } = false;
protected virtual void CreateChildControls()
{
@ -47,7 +49,7 @@ public class WebPage : Control
writer.WriteStartElement(TagName, "http://www.w3.org/1999/xhtml");
writer.WriteStartElement("head");
writer.WriteElementString("title", "Mocha Application");
writer.WriteElementString("title", Title);
if (MobileFriendly)
{
@ -70,7 +72,7 @@ public class WebPage : Control
}
else if (ss.Content != null)
{
ctls.Add(new HtmlGenericControl("style", new KeyValuePair<string, string>[] { new KeyValuePair<string, string>("type", ss.ContentType) }, ss.Content));
ctls.Add(new HtmlGenericControl("style", new KeyValuePair<string, string>[] { new KeyValuePair<string, string>("type", ss.ContentType) }, null, ss.Content));
}
}
@ -84,6 +86,21 @@ public class WebPage : Control
writer.WriteStartElement("body");
List<string> styleClasses = GetStyleClasses().ToList();
if (styleClasses.Count > 0)
{
writer.WriteStartAttribute("class");
for (int i = 0; i < styleClasses.Count; i++)
{
writer.WriteValue(styleClasses[i]);
if (i < styleClasses.Count - 1)
{
writer.WriteValue(" ");
}
}
writer.WriteEndAttribute();
}
writer.WriteStartElement("form");
writer.WriteAttributeString("method", "POST");
}

View File

@ -173,7 +173,7 @@ public class WebServer
*/
// client.ReceiveTimeout = 5000;
// client.SendTimeout = 5000;
NetworkStream st = client.GetStream();
StreamReader sr = new StreamReader(st);
string line = sr.ReadLine();
@ -219,7 +219,7 @@ public class WebServer
}
Dictionary<string, string> form = new Dictionary<string, string>();
string contentLength = headers["Content-Length"];
if (contentLength != "")
{
@ -227,7 +227,7 @@ public class WebServer
char[] buffer = new char[contentLengthInt];
sr.ReadBlock(buffer, 0, contentLengthInt);
string content = new string(buffer);
if (!String.IsNullOrEmpty(content))
{
@ -245,7 +245,7 @@ public class WebServer
if (headers[HttpRequestHeader.Cookie] != null)
{
cookie = headers[HttpRequestHeader.Cookie];
string[] cookieParts = cookie.Split(new char[] { ';' });
if (cookieParts.Length >= 1)
{
@ -277,7 +277,7 @@ public class WebServer
bool found = false;
Dictionary<string, string> pathVariables = new Dictionary<string, string>();
WebContext context = new WebContext((WebApplication)Application.Instance, new WebRequest(version, requestMethod, path, headers, pathVariables, form), new WebResponse(), session);
context.Response.Cookies.Add("JSESSIONID", cookieValue, WebCookieScope.FromPath("/"), WebCookieSecurity.Secure | WebCookieSecurity.HttpOnly, WebCookieSameSite.None);
@ -291,7 +291,14 @@ public class WebServer
}
List<WebRoute> sortedRoutes = new List<WebRoute>(Routes);
sortedRoutes.Sort(new Comparison<WebRoute>((left, right) => CoalesceVariables(right.PathTemplate).Length.CompareTo(CoalesceVariables(left.PathTemplate).Length)));
sortedRoutes.Sort(new Comparison<WebRoute>(delegate (WebRoute left, WebRoute right)
{
if (left == null || right == null)
return (left == right) ? 0 : 1;
return CoalesceVariables(right.PathTemplate).Length.CompareTo(CoalesceVariables(left.PathTemplate).Length);
}));
foreach (WebRoute route in sortedRoutes)
{
// !!! FIXME !!! /super/d/~/super/d/login.htmld/... falsely maps to ~/{tenant} route
@ -302,6 +309,7 @@ public class WebServer
{
lock (route.Handler)
{
// OnProcessRequest(new WebServerProcessRequestEventArgs(this, client, context));
route.Handler.ProcessRequest(context);
WriteResponse(context, client.GetStream());
@ -344,6 +352,8 @@ public class WebServer
Console.Error.WriteLine("caught exception of type {0}", ex.GetType().FullName);
Console.Error.WriteLine(ex.Message);
}
client.Close();
}
private bool _Stopping = false;