Skip to content

Commit 33e719c

Browse files
authored
Merge pull request #96 from Jcparkyn/dev
Allow inline editing of the Output regex
2 parents 3549074 + b5798c8 commit 33e719c

File tree

11 files changed

+316
-42
lines changed

11 files changed

+316
-42
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
@inject IJSRuntime JS;
2+
3+
<div @ref="divElement"
4+
class="@CssClass"></div>
5+
6+
@code {
7+
8+
[Parameter]
9+
public string Text { get; set; }
10+
11+
[Parameter]
12+
public string CssClass { get; set; }
13+
14+
[Parameter]
15+
public EventCallback<string> TextChanged { get; set; }
16+
17+
ElementReference divElement;
18+
19+
protected string textToDisplay;
20+
21+
protected override void OnInitialized()
22+
{
23+
//Text = Text.Replace(Environment.NewLine, "<br />");
24+
}
25+
26+
//send initial text (if any) to javascript to place in the div
27+
protected override async Task OnAfterRenderAsync(bool firstRender)
28+
{
29+
if (firstRender)
30+
{
31+
await JS.InvokeVoidAsync("contentEditable.initContentEditable", divElement, DotNetObjectReference.Create(this), Text);
32+
}
33+
}
34+
35+
//receive input text from javascript and invoke callback to parent component
36+
[JSInvokable]
37+
public async Task GetUpdatedTextFromJavascript(string textFromJavascript)
38+
{
39+
Text = textFromJavascript;
40+
await TextChanged.InvokeAsync(textFromJavascript);
41+
}
42+
}

Nodexr/Shared/Components/OutputDisplay.razor

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,55 @@
99
<h3 style="margin:6px 10px 7px 7px; display:inline-block;">Output:</h3>
1010

1111
<div class="output-regex-container">
12-
<div class="output-regex">@foreach (var segment in @NodeHandler.CachedOutput.Contents)
13-
{<OutputDisplaySegment Segment="segment" @key="segment"/>@*This must not be surrounded by whitespace*@}</div>
12+
<div class="output-regex">@if (isEditing)
13+
{<OutputEditor StartExpression="@NodeHandler.CachedOutput.Expression"
14+
OnSubmitted="@OnEditSubmitted"
15+
OnCanceled="OnEditCancelled"/>}
16+
else
17+
{
18+
@foreach (var segment in @NodeHandler.CachedOutput.Contents)
19+
{<OutputDisplaySegment Segment="segment" @key="segment"/>@*This must not be surrounded by whitespace*@}
20+
}
21+
</div>
1422

15-
<button title="Copy to clipboard" class="output-regex output-regex-button" @onclick="CopyTextToClipboard"><i class="far fa-clipboard"></i></button>
16-
<button title="Edit" class="output-regex output-regex-button" @onclick="OnEditButtonClick"><i class="fas fa-pencil-alt"></i></button>
17-
<button title="Create shareable link" class="output-regex output-regex-button" @onclick="OnCreateLinkButtonClick"><i class="fas fa-link"></i></button>
23+
<button class="output-regex-button" @onclick="OnEditButtonClick" title="Edit"><i class="fas fa-pencil-alt"></i></button>
24+
<button class="output-regex-button" @onclick="CopyTextToClipboard" title="Copy to clipboard"><i class="far fa-clipboard"></i></button>
25+
<button class="output-regex-button" @onclick="OnCreateLinkButtonClick" title="Create shareable link"><i class="fas fa-link"></i></button>
1826
</div>
1927

2028

2129
@functions{
2230

31+
bool isEditing = false;
32+
2333
protected override void OnInitialized()
2434
{
2535
NodeHandler.OutputChanged += (sender, e) => StateHasChanged();
2636
}
2737

28-
private async Task OnEditButtonClick()
38+
private void OnEditButtonClick()
2939
{
30-
var modalParameters = new ModalParameters();
31-
modalParameters.Add(nameof(EditRegexDialog.previousRegex), NodeHandler.CachedOutput.Expression);
40+
isEditing = !isEditing;
41+
}
3242

33-
var modal = ModalService.Show<EditRegexDialog>("Custom Expression", modalParameters);
34-
var result = await modal.Result;
35-
if (result.Cancelled)
36-
{
37-
Console.WriteLine("Modal was cancelled");
38-
}
39-
else if (result.Data is string customRegex)
40-
{
41-
Console.WriteLine("Custom Regex: " + customRegex);
42-
NodeHandler.TryCreateTreeFromRegex(customRegex);
43-
}
43+
private void OnEditSubmitted(string newExpression)
44+
{
45+
isEditing = false;
46+
NodeHandler.TryCreateTreeFromRegex(newExpression);
47+
}
48+
49+
private void OnEditCancelled()
50+
{
51+
isEditing = false;
52+
StateHasChanged();
4453
}
4554

4655
private async Task OnCreateLinkButtonClick()
4756
{
4857
var urlParams = new Dictionary<string, string>
49-
{
50-
{ "parse", NodeHandler.CachedOutput.Expression }
51-
};
58+
{
59+
{ "parse", NodeHandler.CachedOutput.Expression }
60+
};
5261

5362
if (RegexReplaceHandler.SearchText != RegexReplaceHandler.DefaultSearchText)
5463
{

Nodexr/Shared/Components/OutputDisplaySegment.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@implements IDisposable
22
@inject INodeHandler NodeHandler
33

4-
<span class="output-segment @(NodeHandler.IsNodeSelected(Segment.Node) ? "output-segment-selected" : "")"
4+
<span class="output-regex-text output-segment @(NodeHandler.IsNodeSelected(Segment.Node) ? "output-segment-selected" : "")"
55
style="color:@(Segment.Node?.CssColor ?? "inherit")"
66
@onmouseover="@(() => NodeHandler.SelectNode(Segment.Node))"
77
title="@Segment.Node.Title"
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
<div @onkeypress="OnKeyPress"
3+
@onkeyup="OnKeyUp">
4+
<ContentEditableDiv @bind-Text="expression"
5+
CssClass="output-regex-text"/>
6+
<div class="output-edit-prompt">
7+
Input your own regular expression here to convert it to a node tree.<br />
8+
<button @onclick="Submit">Confirm (Enter)</button>
9+
<button @onclick="Cancel">Cancel</button>
10+
</div>
11+
</div>
12+
13+
@code {
14+
15+
string expression;
16+
17+
[Parameter] public string StartExpression
18+
{
19+
set => expression = value;
20+
}
21+
22+
[Parameter] public EventCallback<string> OnSubmitted { get; set; }
23+
[Parameter] public EventCallback OnCanceled { get; set; }
24+
25+
protected async Task OnKeyPress(KeyboardEventArgs e)
26+
{
27+
if(e.Key == "Enter" && !e.ShiftKey)
28+
{
29+
await Submit();
30+
}
31+
}
32+
33+
protected async Task OnKeyUp(KeyboardEventArgs e)
34+
{
35+
if (e.Key == "Escape")
36+
{
37+
await Cancel();
38+
}
39+
}
40+
41+
protected async Task Submit()
42+
{
43+
await OnSubmitted.InvokeAsync(expression);
44+
}
45+
46+
protected async Task Cancel()
47+
{
48+
await OnCanceled.InvokeAsync(null);
49+
}
50+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@if (!string.IsNullOrEmpty(Info))
2+
{
3+
@Info
4+
}
5+
<button class="toast-button" @onclick="OnButtonClicked" disabled="@hasBeenPressed">@ButtonText</button>
6+
7+
@code {
8+
[Parameter] public Action OnClick { get; set; }
9+
[Parameter] public string ButtonText { get; set; }
10+
[Parameter] public string Info { get; set; }
11+
12+
private bool hasBeenPressed = false;
13+
14+
private void OnButtonClicked()
15+
{
16+
hasBeenPressed = true;
17+
OnClick?.Invoke();
18+
}
19+
20+
public static RenderFragment GetRenderFragment(Action onClick, string buttonText, string info = null)
21+
=> @<ToastButton OnClick="@onClick" ButtonText="@buttonText" Info="@info"/>;
22+
}

Nodexr/Shared/MainLayout.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</div>*@
1212
<BlazoredModal />
1313
<BlazoredToasts Position="ToastPosition.BottomRight"
14-
Timeout="10"/>
14+
Timeout="13"/>
1515
<div class="content">
1616
@Body
1717
</div>

Nodexr/Shared/Services/NodeHandler.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ public interface INodeHandler
2828
void ForceRefreshNoodles();
2929
void SelectNode(INode node);
3030
void DeselectAllNodes();
31-
bool TryCreateTreeFromRegex(string regex);
31+
void TryCreateTreeFromRegex(string regex);
3232
bool IsNodeSelected(INode node);
33+
void RevertPreviousParse();
3334
}
3435

3536
public class NodeHandler : INodeHandler
@@ -74,6 +75,9 @@ private set
7475

7576
private readonly IToastService toastService;
7677

78+
//Stores the previous tree from before the most recent parse, so that the parse can be reverted.
79+
private NodeTree treePrevious;
80+
7781
public NodeHandler(NavigationManager navManager, IToastService toastService)
7882
{
7983
this.toastService = toastService;
@@ -98,25 +102,46 @@ public NodeHandler(NavigationManager navManager, IToastService toastService)
98102
/// </summary>
99103
/// <param name="regex">The regular expression to parse, in string format</param>
100104
/// <returns>Whether or not the parse attempt succeeded</returns>
101-
public bool TryCreateTreeFromRegex(string regex)
105+
public void TryCreateTreeFromRegex(string regex)
102106
{
103107
var parseResult = RegexParser.Parse(regex);
104108

105109
if (parseResult.Success)
106110
{
111+
treePrevious = tree;
107112
Tree = parseResult.Value;
108113
ForceRefreshNodeGraph();
109114
OnOutputChanged(this, EventArgs.Empty);
110-
return true;
115+
116+
if(CachedOutput.Expression == regex)
117+
{
118+
var fragment = Components.ToastButton.GetRenderFragment(RevertPreviousParse, "Revert to previous");
119+
toastService.ShowSuccess(fragment, "Converted to node tree successfully");
120+
}
121+
else
122+
{
123+
var fragment = Components.ToastButton.GetRenderFragment(
124+
RevertPreviousParse,
125+
"Revert to previous",
126+
"Your expression was parsed, but the resulting output is slighty different to your input. " +
127+
"This is most likely due to a simplification that has been performed automatically.\n");
128+
toastService.ShowInfo(fragment, "Converted to node tree");
129+
}
111130
}
112131
else
113132
{
114133
toastService.ShowError(parseResult.Error.ToString(), "Couldn't parse input");
115134
Console.WriteLine("Couldn't parse input: " + parseResult.Error);
116-
return false;
117135
}
118136
}
119137

138+
public void RevertPreviousParse()
139+
{
140+
Tree = treePrevious;
141+
ForceRefreshNodeGraph();
142+
OnOutputChanged(this, EventArgs.Empty);
143+
}
144+
120145
public void ForceRefreshNodeGraph()
121146
{
122147
OnRequireNodeGraphRefresh?.Invoke(this, EventArgs.Empty);

Nodexr/wwwroot/css/node.css

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
padding: 2px 4px 0px 4px;
1919
/*margin-bottom: 0px;*/
2020
border-radius: 8px 8px 0px 0px;
21+
color: var(--col-text-invert);
2122
}
2223
.node .node-title.collapsed {
2324
border-radius: 8px
@@ -34,13 +35,14 @@
3435
border: none;
3536
font-size: 0.8rem;
3637
padding: 0 0 0 7px;
38+
color: inherit;
3739
}
3840

3941
.node .icon-button {
4042
position: relative;
4143
background: none;
4244
border: none;
43-
color: var(--col-text-strong2);
45+
color: inherit;
4446
font-size: 0.9rem;
4547
padding: 1px 0 0 0;
4648
outline: 0 !important;
@@ -206,16 +208,9 @@
206208
padding-left: 7px;
207209
}
208210

209-
210-
211-
212211
.add-button {
213212
position: relative;
214213
margin: 5px 0px 0px 0px;
215-
background-color: rgba(200,200,256,0.09);
216-
border: none;
217-
border-radius: 6px;
218-
color: var(--col-text-medium);
219214
font-size: 0.9rem;
220215
}
221216

0 commit comments

Comments
 (0)