Implemented reading input from the textbox instead of connectors
This commit is contained in:
@@ -31,6 +31,19 @@ namespace Nodify.Calculator
|
||||
.Then(() => ValueObservers.ForEach(o => o.Value = value));
|
||||
}
|
||||
|
||||
private string _userInput = string.Empty;
|
||||
/// <summary>
|
||||
/// Free-form text the user types directly into the connector's input textbox
|
||||
/// (visible only when the connector is not connected). Used by handlers like
|
||||
/// NEW_OBJECT to read non-numeric values (strings, bools, JSON snippets, ...)
|
||||
/// that <see cref="Value"/> (a double) cannot represent.
|
||||
/// </summary>
|
||||
public string UserInput
|
||||
{
|
||||
get => _userInput;
|
||||
set => SetProperty(ref _userInput, value);
|
||||
}
|
||||
|
||||
private ConnectorShape _shape;
|
||||
public ConnectorShape Shape
|
||||
{
|
||||
|
||||
@@ -273,7 +273,8 @@
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Title}"
|
||||
Margin="0 0 5 0" />
|
||||
<TextBox Text="{Binding Value}"
|
||||
<TextBox Text="{Binding UserInput, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinWidth="60"
|
||||
Visibility="{Binding IsConnected, Converter={shared:BooleanToVisibilityConverter Negate=True}}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -95,10 +95,23 @@ namespace Nodify.Calculator.Execution.Handlers
|
||||
var propPath = parenIdx > 0 ? title.Substring(0, parenIdx).Trim() : title.Trim();
|
||||
if (string.IsNullOrEmpty(propPath)) continue;
|
||||
|
||||
var val = ctx.ReadInput(inp);
|
||||
// If a wire is connected → read from upstream node.
|
||||
// Otherwise fall back to whatever the user typed in the inline TextBox (UserInput).
|
||||
// If neither is provided, skip the field so the JSON only carries explicit values.
|
||||
string val;
|
||||
if (inp.IsConnected)
|
||||
{
|
||||
val = ctx.ReadInput(inp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(inp.UserInput)) continue;
|
||||
val = inp.UserInput;
|
||||
}
|
||||
|
||||
ctx.Log($"[NEW OBJECT] {propPath} = {(val?.Length > 80 ? val.Substring(0, 80) + "..." : val ?? "null")}");
|
||||
|
||||
SetNestedValue(root, propPath, val);
|
||||
SetNestedValue(root, propPath, val, inp.DataType);
|
||||
}
|
||||
|
||||
var json = root.ToString(Formatting.None);
|
||||
@@ -109,9 +122,10 @@ namespace Nodify.Calculator.Execution.Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value at a dot-notation path in a JObject, creating intermediate objects as needed.
|
||||
/// e.g., "Address.Street" with value "Main St" → { "Address": { "Street": "Main St" } }
|
||||
/// The leaf token is coerced according to <paramref name="dataType"/> so that string fields
|
||||
/// remain JSON strings, numeric fields remain JSON numbers, etc.
|
||||
/// </summary>
|
||||
private static void SetNestedValue(JObject root, string path, string val)
|
||||
private static void SetNestedValue(JObject root, string path, string val, string dataType)
|
||||
{
|
||||
var parts = path.Split('.');
|
||||
var current = root;
|
||||
@@ -129,14 +143,56 @@ namespace Nodify.Calculator.Execution.Handlers
|
||||
}
|
||||
|
||||
var leaf = parts[parts.Length - 1];
|
||||
if (val != null)
|
||||
{
|
||||
try { current[leaf] = JToken.Parse(val); }
|
||||
catch { current[leaf] = val; }
|
||||
current[leaf] = CoerceValue(val, dataType);
|
||||
}
|
||||
else
|
||||
|
||||
private static JToken CoerceValue(string val, string dataType)
|
||||
{
|
||||
current[leaf] = null;
|
||||
if (val == null) return JValue.CreateNull();
|
||||
|
||||
var dt = (dataType ?? "").Trim().ToLowerInvariant();
|
||||
|
||||
// Lists / nested objects / unspecified — try JSON parse first, fall back to string.
|
||||
if (dt.StartsWith("list<") || dt == "object" || string.IsNullOrEmpty(dt))
|
||||
{
|
||||
try { return JToken.Parse(val); }
|
||||
catch { return new JValue(val); }
|
||||
}
|
||||
|
||||
switch (dt)
|
||||
{
|
||||
case "string":
|
||||
case "char":
|
||||
case "guid":
|
||||
case "datetime":
|
||||
return new JValue(val);
|
||||
|
||||
case "bool":
|
||||
case "boolean":
|
||||
if (bool.TryParse(val, out var b)) return new JValue(b);
|
||||
return new JValue(val);
|
||||
|
||||
case "int":
|
||||
case "long":
|
||||
case "short":
|
||||
case "byte":
|
||||
if (long.TryParse(val, System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out var l))
|
||||
return new JValue(l);
|
||||
return new JValue(val);
|
||||
|
||||
case "double":
|
||||
case "float":
|
||||
case "decimal":
|
||||
if (double.TryParse(val, System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out var d))
|
||||
return new JValue(d);
|
||||
return new JValue(val);
|
||||
|
||||
default:
|
||||
// Custom model type referenced by name → expect a JSON object string.
|
||||
try { return JToken.Parse(val); }
|
||||
catch { return new JValue(val); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user