Skip to content

Commit

Permalink
Merge pull request #96 from Jcparkyn/dev
Browse files Browse the repository at this point in the history
Allow inline editing of the Output regex
  • Loading branch information
Jcparkyn authored Jul 22, 2020
2 parents 3549074 + b5798c8 commit 33e719c
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 42 deletions.
42 changes: 42 additions & 0 deletions Nodexr/Shared/Components/ContentEditableDiv.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@inject IJSRuntime JS;

<div @ref="divElement"
class="@CssClass"></div>

@code {

[Parameter]
public string Text { get; set; }

[Parameter]
public string CssClass { get; set; }

[Parameter]
public EventCallback<string> TextChanged { get; set; }

ElementReference divElement;

protected string textToDisplay;

protected override void OnInitialized()
{
//Text = Text.Replace(Environment.NewLine, "<br />");
}

//send initial text (if any) to javascript to place in the div
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("contentEditable.initContentEditable", divElement, DotNetObjectReference.Create(this), Text);
}
}

//receive input text from javascript and invoke callback to parent component
[JSInvokable]
public async Task GetUpdatedTextFromJavascript(string textFromJavascript)
{
Text = textFromJavascript;
await TextChanged.InvokeAsync(textFromJavascript);
}
}
53 changes: 31 additions & 22 deletions Nodexr/Shared/Components/OutputDisplay.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,55 @@
<h3 style="margin:6px 10px 7px 7px; display:inline-block;">Output:</h3>

<div class="output-regex-container">
<div class="output-regex">@foreach (var segment in @NodeHandler.CachedOutput.Contents)
{<OutputDisplaySegment Segment="segment" @key="segment"/>@*This must not be surrounded by whitespace*@}</div>
<div class="output-regex">@if (isEditing)
{<OutputEditor StartExpression="@NodeHandler.CachedOutput.Expression"
OnSubmitted="@OnEditSubmitted"
OnCanceled="OnEditCancelled"/>}
else
{
@foreach (var segment in @NodeHandler.CachedOutput.Contents)
{<OutputDisplaySegment Segment="segment" @key="segment"/>@*This must not be surrounded by whitespace*@}
}
</div>

<button title="Copy to clipboard" class="output-regex output-regex-button" @onclick="CopyTextToClipboard"><i class="far fa-clipboard"></i></button>
<button title="Edit" class="output-regex output-regex-button" @onclick="OnEditButtonClick"><i class="fas fa-pencil-alt"></i></button>
<button title="Create shareable link" class="output-regex output-regex-button" @onclick="OnCreateLinkButtonClick"><i class="fas fa-link"></i></button>
<button class="output-regex-button" @onclick="OnEditButtonClick" title="Edit"><i class="fas fa-pencil-alt"></i></button>
<button class="output-regex-button" @onclick="CopyTextToClipboard" title="Copy to clipboard"><i class="far fa-clipboard"></i></button>
<button class="output-regex-button" @onclick="OnCreateLinkButtonClick" title="Create shareable link"><i class="fas fa-link"></i></button>
</div>


@functions{

bool isEditing = false;

protected override void OnInitialized()
{
NodeHandler.OutputChanged += (sender, e) => StateHasChanged();
}

private async Task OnEditButtonClick()
private void OnEditButtonClick()
{
var modalParameters = new ModalParameters();
modalParameters.Add(nameof(EditRegexDialog.previousRegex), NodeHandler.CachedOutput.Expression);
isEditing = !isEditing;
}

var modal = ModalService.Show<EditRegexDialog>("Custom Expression", modalParameters);
var result = await modal.Result;
if (result.Cancelled)
{
Console.WriteLine("Modal was cancelled");
}
else if (result.Data is string customRegex)
{
Console.WriteLine("Custom Regex: " + customRegex);
NodeHandler.TryCreateTreeFromRegex(customRegex);
}
private void OnEditSubmitted(string newExpression)
{
isEditing = false;
NodeHandler.TryCreateTreeFromRegex(newExpression);
}

private void OnEditCancelled()
{
isEditing = false;
StateHasChanged();
}

private async Task OnCreateLinkButtonClick()
{
var urlParams = new Dictionary<string, string>
{
{ "parse", NodeHandler.CachedOutput.Expression }
};
{
{ "parse", NodeHandler.CachedOutput.Expression }
};

if (RegexReplaceHandler.SearchText != RegexReplaceHandler.DefaultSearchText)
{
Expand Down
2 changes: 1 addition & 1 deletion Nodexr/Shared/Components/OutputDisplaySegment.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@implements IDisposable
@inject INodeHandler NodeHandler

<span class="output-segment @(NodeHandler.IsNodeSelected(Segment.Node) ? "output-segment-selected" : "")"
<span class="output-regex-text output-segment @(NodeHandler.IsNodeSelected(Segment.Node) ? "output-segment-selected" : "")"
style="color:@(Segment.Node?.CssColor ?? "inherit")"
@onmouseover="@(() => NodeHandler.SelectNode(Segment.Node))"
title="@Segment.Node.Title"
Expand Down
50 changes: 50 additions & 0 deletions Nodexr/Shared/Components/OutputEditor.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

<div @onkeypress="OnKeyPress"
@onkeyup="OnKeyUp">
<ContentEditableDiv @bind-Text="expression"
CssClass="output-regex-text"/>
<div class="output-edit-prompt">
Input your own regular expression here to convert it to a node tree.<br />
<button @onclick="Submit">Confirm (Enter)</button>
<button @onclick="Cancel">Cancel</button>
</div>
</div>

@code {

string expression;

[Parameter] public string StartExpression
{
set => expression = value;
}

[Parameter] public EventCallback<string> OnSubmitted { get; set; }
[Parameter] public EventCallback OnCanceled { get; set; }

protected async Task OnKeyPress(KeyboardEventArgs e)
{
if(e.Key == "Enter" && !e.ShiftKey)
{
await Submit();
}
}

protected async Task OnKeyUp(KeyboardEventArgs e)
{
if (e.Key == "Escape")
{
await Cancel();
}
}

protected async Task Submit()
{
await OnSubmitted.InvokeAsync(expression);
}

protected async Task Cancel()
{
await OnCanceled.InvokeAsync(null);
}
}
22 changes: 22 additions & 0 deletions Nodexr/Shared/Components/ToastButton.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@if (!string.IsNullOrEmpty(Info))
{
@Info
}
<button class="toast-button" @onclick="OnButtonClicked" disabled="@hasBeenPressed">@ButtonText</button>

@code {
[Parameter] public Action OnClick { get; set; }
[Parameter] public string ButtonText { get; set; }
[Parameter] public string Info { get; set; }

private bool hasBeenPressed = false;

private void OnButtonClicked()
{
hasBeenPressed = true;
OnClick?.Invoke();
}

public static RenderFragment GetRenderFragment(Action onClick, string buttonText, string info = null)
=> @<ToastButton OnClick="@onClick" ButtonText="@buttonText" Info="@info"/>;
}
2 changes: 1 addition & 1 deletion Nodexr/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</div>*@
<BlazoredModal />
<BlazoredToasts Position="ToastPosition.BottomRight"
Timeout="10"/>
Timeout="13"/>
<div class="content">
@Body
</div>
Expand Down
33 changes: 29 additions & 4 deletions Nodexr/Shared/Services/NodeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ public interface INodeHandler
void ForceRefreshNoodles();
void SelectNode(INode node);
void DeselectAllNodes();
bool TryCreateTreeFromRegex(string regex);
void TryCreateTreeFromRegex(string regex);
bool IsNodeSelected(INode node);
void RevertPreviousParse();
}

public class NodeHandler : INodeHandler
Expand Down Expand Up @@ -74,6 +75,9 @@ private set

private readonly IToastService toastService;

//Stores the previous tree from before the most recent parse, so that the parse can be reverted.
private NodeTree treePrevious;

public NodeHandler(NavigationManager navManager, IToastService toastService)
{
this.toastService = toastService;
Expand All @@ -98,25 +102,46 @@ public NodeHandler(NavigationManager navManager, IToastService toastService)
/// </summary>
/// <param name="regex">The regular expression to parse, in string format</param>
/// <returns>Whether or not the parse attempt succeeded</returns>
public bool TryCreateTreeFromRegex(string regex)
public void TryCreateTreeFromRegex(string regex)
{
var parseResult = RegexParser.Parse(regex);

if (parseResult.Success)
{
treePrevious = tree;
Tree = parseResult.Value;
ForceRefreshNodeGraph();
OnOutputChanged(this, EventArgs.Empty);
return true;

if(CachedOutput.Expression == regex)
{
var fragment = Components.ToastButton.GetRenderFragment(RevertPreviousParse, "Revert to previous");
toastService.ShowSuccess(fragment, "Converted to node tree successfully");
}
else
{
var fragment = Components.ToastButton.GetRenderFragment(
RevertPreviousParse,
"Revert to previous",
"Your expression was parsed, but the resulting output is slighty different to your input. " +
"This is most likely due to a simplification that has been performed automatically.\n");
toastService.ShowInfo(fragment, "Converted to node tree");
}
}
else
{
toastService.ShowError(parseResult.Error.ToString(), "Couldn't parse input");
Console.WriteLine("Couldn't parse input: " + parseResult.Error);
return false;
}
}

public void RevertPreviousParse()
{
Tree = treePrevious;
ForceRefreshNodeGraph();
OnOutputChanged(this, EventArgs.Empty);
}

public void ForceRefreshNodeGraph()
{
OnRequireNodeGraphRefresh?.Invoke(this, EventArgs.Empty);
Expand Down
11 changes: 3 additions & 8 deletions Nodexr/wwwroot/css/node.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
padding: 2px 4px 0px 4px;
/*margin-bottom: 0px;*/
border-radius: 8px 8px 0px 0px;
color: var(--col-text-invert);
}
.node .node-title.collapsed {
border-radius: 8px
Expand All @@ -34,13 +35,14 @@
border: none;
font-size: 0.8rem;
padding: 0 0 0 7px;
color: inherit;
}

.node .icon-button {
position: relative;
background: none;
border: none;
color: var(--col-text-strong2);
color: inherit;
font-size: 0.9rem;
padding: 1px 0 0 0;
outline: 0 !important;
Expand Down Expand Up @@ -206,16 +208,9 @@
padding-left: 7px;
}




.add-button {
position: relative;
margin: 5px 0px 0px 0px;
background-color: rgba(200,200,256,0.09);
border: none;
border-radius: 6px;
color: var(--col-text-medium);
font-size: 0.9rem;
}

Expand Down
Loading

0 comments on commit 33e719c

Please sign in to comment.