Merge pull request #76 from praeclarum/issue48
Re-implement Switch without jQuery
This commit is contained in:
commit
313ff9e3da
|
@ -3,7 +3,7 @@ using Xamarin.Forms;
|
|||
|
||||
namespace Ooui.Forms.Renderers
|
||||
{
|
||||
public class SwitchRenderer : ViewRenderer<Switch, Input>
|
||||
public class SwitchRenderer : ViewRenderer<Switch, SwitchRenderer.SwitchElement>
|
||||
{
|
||||
public override SizeRequest GetDesiredSize (double widthConstraint, double heightConstraint)
|
||||
{
|
||||
|
@ -26,10 +26,8 @@ namespace Ooui.Forms.Renderers
|
|||
|
||||
if (e.NewElement != null) {
|
||||
if (Control == null) {
|
||||
var input = new Input (InputType.Checkbox);
|
||||
input.SetAttribute ("data-toggle", "toggle");
|
||||
var input = new SwitchElement ();
|
||||
SetNativeControl (input);
|
||||
input.Call ("$.bootstrapToggle");
|
||||
Control.Change += OnControlValueChanged;
|
||||
}
|
||||
|
||||
|
@ -49,5 +47,52 @@ namespace Ooui.Forms.Renderers
|
|||
{
|
||||
Control.IsChecked = Element.IsToggled;
|
||||
}
|
||||
|
||||
public class SwitchElement : Div
|
||||
{
|
||||
public event EventHandler Change;
|
||||
bool isChecked = false;
|
||||
readonly Div knob = new Div ();
|
||||
public bool IsChecked {
|
||||
get => isChecked;
|
||||
set {
|
||||
isChecked = value;
|
||||
UpdateUI ();
|
||||
}
|
||||
}
|
||||
public SwitchElement ()
|
||||
{
|
||||
AppendChild (knob);
|
||||
knob.Style.Position = "absolute";
|
||||
knob.Style.BorderRadius = "10px";
|
||||
knob.Style.Cursor = "pointer";
|
||||
knob.Style.Top = "2px";
|
||||
knob.Style.Width = "18px";
|
||||
knob.Style.Height = "34px";
|
||||
|
||||
Style.BorderRadius = "10px";
|
||||
Style.Cursor = "pointer";
|
||||
Style.BorderStyle = "solid";
|
||||
Style.BorderWidth = "2px";
|
||||
Click += (s, e) => {
|
||||
IsChecked = !IsChecked;
|
||||
Change?.Invoke (this, EventArgs.Empty);
|
||||
};
|
||||
UpdateUI ();
|
||||
}
|
||||
|
||||
void UpdateUI ()
|
||||
{
|
||||
Style.BackgroundColor = isChecked ? "#337ab7" : "#888";
|
||||
Style.BorderColor = Style.BackgroundColor;
|
||||
knob.Style.BackgroundColor = isChecked ? "#FFF" : "#EEE";
|
||||
if (isChecked) {
|
||||
knob.Style.Left = "34px";
|
||||
}
|
||||
else {
|
||||
knob.Style.Left = "2px";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,19 +84,11 @@ function ooui (rootElementPath) {
|
|||
const messages = JSON.parse (event.data);
|
||||
if (debug) console.log("Messages", messages);
|
||||
if (Array.isArray (messages)) {
|
||||
const jqs = []
|
||||
messages.forEach (function (m) {
|
||||
// console.log('Raw value from server', m.v);
|
||||
m.v = fixupValue (m.v);
|
||||
if (m.k.startsWith ("$.")) {
|
||||
jqs.push (m);
|
||||
}
|
||||
else {
|
||||
processMessage (m);
|
||||
}
|
||||
});
|
||||
// Run jQuery functions last since they usually require a fully built DOM
|
||||
jqs.forEach (processMessage);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -212,15 +204,14 @@ function msgCall (m) {
|
|||
console.error ("Unknown node id", m);
|
||||
return;
|
||||
}
|
||||
const isJQuery = m.k.startsWith ("$.");
|
||||
const target = isJQuery ? $(node) : node;
|
||||
const target = 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];
|
||||
const f = target[m.k];
|
||||
if (debug) console.log ("Call", node, f, m.v);
|
||||
const r = f.apply (target, m.v);
|
||||
if (typeof m.rid === 'string' || m.rid instanceof String) {
|
||||
|
|
|
@ -65,15 +65,47 @@ namespace Ooui
|
|||
if (styleValue == "inherit")
|
||||
return Colors.Clear;
|
||||
|
||||
//if (styleValue[0] == '#' && styleValue.Length == 4) {
|
||||
//}
|
||||
if (styleValue[0] == '#' && styleValue.Length == 4) {
|
||||
var r = ReadHexNibble (styleValue[1]);
|
||||
var g = ReadHexNibble (styleValue[2]);
|
||||
var b = ReadHexNibble (styleValue[3]);
|
||||
return new Color (r, g, b, 255);
|
||||
}
|
||||
|
||||
//if (styleValue[0] == '#' && styleValue.Length == 7) {
|
||||
//}
|
||||
if (styleValue[0] == '#' && styleValue.Length == 7) {
|
||||
var r = ReadHexByte (styleValue[1], styleValue[2]);
|
||||
var g = ReadHexByte (styleValue[3], styleValue[4]);
|
||||
var b = ReadHexByte (styleValue[5], styleValue[6]);
|
||||
return new Color (r, g, b, 255);
|
||||
}
|
||||
|
||||
throw new ArgumentException ($"Cannot parse color string `{styleValue}`", nameof (styleValue));
|
||||
}
|
||||
|
||||
static byte ReadHexByte (char c0, char c1)
|
||||
{
|
||||
var n0 = ReadHex (c0);
|
||||
var n1 = ReadHex (c1);
|
||||
return (byte)((n0 << 4) | n1);
|
||||
}
|
||||
|
||||
static byte ReadHexNibble (char c)
|
||||
{
|
||||
var n = ReadHex (c);
|
||||
return (byte)((n << 4) | n);
|
||||
}
|
||||
|
||||
static byte ReadHex (char c)
|
||||
{
|
||||
if ('0' <= c && c <= '9')
|
||||
return (byte)(c - '0');
|
||||
if ('a' <= c && c <= 'z')
|
||||
return (byte)((c - 'a') + 10);
|
||||
if ('A' <= c && c <= 'Z')
|
||||
return (byte)((c - 'A') + 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
if (A == 255)
|
||||
|
|
|
@ -116,7 +116,7 @@ namespace Ooui
|
|||
protected bool SetBooleanAttributeProperty (string attributeName, bool newValue, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
|
||||
{
|
||||
var old = GetAttribute (attributeName) != null;
|
||||
if (old != newValue)
|
||||
if (old == newValue)
|
||||
return false;
|
||||
if (newValue)
|
||||
SetAttribute (attributeName, string.Empty);
|
||||
|
@ -230,20 +230,6 @@ namespace Ooui
|
|||
SendSet ("style." + Style.GetJsName (e.PropertyName), Style[e.PropertyName]);
|
||||
}
|
||||
|
||||
protected override bool SaveStateMessageIfNeeded (Message message)
|
||||
{
|
||||
if (message.TargetId != Id)
|
||||
return false;
|
||||
|
||||
switch (message.MessageType) {
|
||||
case MessageType.Call when message.Key.StartsWith ("$.", StringComparison.Ordinal):
|
||||
AddStateMessage (message);
|
||||
return true;
|
||||
default:
|
||||
return base.SaveStateMessageIfNeeded (message);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool HtmlNeedsFullEndElement => false;
|
||||
|
||||
public override void WriteOuterHtml (System.Xml.XmlWriter w)
|
||||
|
|
|
@ -182,6 +182,24 @@ namespace Ooui
|
|||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool TriggerEvent (string name)
|
||||
{
|
||||
List<TargetEventHandler> handlers = null;
|
||||
lock (eventListeners) {
|
||||
List<TargetEventHandler> hs;
|
||||
if (eventListeners.TryGetValue (name, out hs)) {
|
||||
handlers = new List<TargetEventHandler> (hs);
|
||||
}
|
||||
}
|
||||
if (handlers != null) {
|
||||
var args = new TargetEventArgs ();
|
||||
foreach (var h in handlers) {
|
||||
h.Invoke (this, args);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool TriggerEventFromMessage (Message message)
|
||||
{
|
||||
if (message.TargetId != Id)
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace Ooui
|
|||
get => GetBooleanAttribute ("checked");
|
||||
set {
|
||||
if (SetBooleanAttributeProperty ("checked", value)) {
|
||||
TriggerEventFromMessage (Message.Event (Id, "change", IsChecked));
|
||||
TriggerEvent ("change");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ namespace Ooui
|
|||
<title>@Title</title>
|
||||
<meta name=""viewport"" content=""width=device-width, initial-scale=1"" />
|
||||
<link rel=""stylesheet"" href=""https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"" />
|
||||
<link rel=""stylesheet"" href=""https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css"" />
|
||||
<style>@Styles</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -49,8 +48,6 @@ namespace Ooui
|
|||
@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>
|
||||
<script src=""/ooui.js""></script>
|
||||
<script>ooui(""@WebSocketPath"");</script>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
using Ooui;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
// From https://github.com/praeclarum/Ooui/issues/48
|
||||
public class SwitchErrorSample : ISample
|
||||
{
|
||||
public string Title => "Xamarin.Forms Switch Error";
|
||||
|
||||
public Ooui.Element CreateElement ()
|
||||
{
|
||||
var layout = new StackLayout();
|
||||
var label = new Xamarin.Forms.Label
|
||||
{
|
||||
Text = "Switch state goes here",
|
||||
HorizontalTextAlignment = TextAlignment.Center
|
||||
};
|
||||
var sw = new Switch
|
||||
{
|
||||
HorizontalOptions = LayoutOptions.CenterAndExpand
|
||||
};
|
||||
sw.Toggled += (sender, args) =>
|
||||
{
|
||||
label.Text = $"Switch state is: {((Switch)sender).IsToggled}";
|
||||
};
|
||||
layout.Children.Add(label);
|
||||
layout.Children.Add(sw);
|
||||
return new ContentPage
|
||||
{
|
||||
Content = layout
|
||||
}.GetOouiElement();
|
||||
}
|
||||
|
||||
public void Publish()
|
||||
{
|
||||
UI.Publish ("/switch", CreateElement);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue