feat: populate editor with block content

WIP
This commit is contained in:
Oliver Booth 2024-03-02 05:30:15 +00:00
parent ecf31568c8
commit 430ab2b50e
Signed by: oliverbooth
GPG Key ID: E60B570D1B7557B5
10 changed files with 232 additions and 3 deletions

View File

@ -0,0 +1,14 @@
using System.Text.Json;
using Markdig.Renderers;
using Markdig.Syntax;
namespace OliverBooth.Markdown.Renderers.EditorJs;
public class JsonRenderer : RendererBase
{
/// <inheritdoc />
public override object Render(MarkdownObject markdownObject)
{
return JsonDocument.Parse("""{"blocks": []}""");
}
}

View File

@ -0,0 +1,17 @@
using Markdig.Renderers;
using Markdig.Syntax;
namespace OliverBooth.Markdown.Renderers.EditorJs.ObjectRenderers;
public class HeadingObjectRenderer : IMarkdownObjectRenderer
{
public bool Accept(RendererBase renderer, Type objectType)
{
return renderer.GetType() == typeof(JsonRenderer) && objectType == typeof(HeadingBlock);
}
public void Write(RendererBase renderer, MarkdownObject objectToRender)
{
}
}

View File

@ -0,0 +1,53 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Markdig.Helpers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
namespace OliverBooth.Markdown.Renderers.JsonConverters;
public sealed class HeadingBlockConverter : JsonConverter<HeadingBlock>
{
/// <inheritdoc />
public override HeadingBlock? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var node = JsonNode.Parse(reader.ValueSpan);
if (node is not JsonObject jsonObject)
{
return null;
}
return new HeadingBlock(null!)
{
Level = jsonObject["level"]?.GetValue<int>() ?? 1,
Lines = new StringLineGroup(jsonObject["text"]?.GetValue<string>() ?? string.Empty)
};
}
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, HeadingBlock value, JsonSerializerOptions options)
{
if (value.Inline is not { } containerInline)
{
return;
}
writer.WriteStartObject();
writer.WriteString("type", "header");
writer.WriteNumber("level", value.Level);
writer.WritePropertyName("text");
foreach (Inline inline in containerInline)
{
if (inline is LiteralInline literal)
{
var converter = (JsonConverter<LiteralInline>)options.GetConverter(typeof(LiteralInline));
writer.WriteStringValue(literal.Content.Text);
converter.Write(writer, literal, options);
}
}
writer.WriteEndObject();
}
}

View File

@ -0,0 +1,22 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Markdig.Syntax.Inlines;
namespace OliverBooth.Markdown.Renderers.JsonConverters;
public class LiteralInlineConverter : JsonConverter<LiteralInline>
{
public override LiteralInline? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
ReadOnlySpan<byte> bytes = reader.ValueSpan;
Span<char> chars = stackalloc char[bytes.Length];
Encoding.UTF8.GetChars(bytes, chars);
return new LiteralInline(chars.ToString());
}
public override void Write(Utf8JsonWriter writer, LiteralInline value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Content.Text);
}
}

View File

@ -0,0 +1,57 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Markdig.Syntax;
namespace OliverBooth.Markdown.Renderers.JsonConverters;
public sealed class MarkdownDocumentConverter : JsonConverter<MarkdownDocument>
{
/// <inheritdoc />
public override MarkdownDocument Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var document = new MarkdownDocument();
var blocks = JsonSerializer.Deserialize<Block[]>(ref reader, options) ?? Array.Empty<Block>();
foreach (Block block in blocks)
{
document.Add(block);
}
return document;
}
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, MarkdownDocument value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteStartArray("blocks");
foreach (Block block in value)
{
WriteBlock(writer, options, block);
}
writer.WriteEndArray();
writer.WriteEndObject();
}
private static void WriteBlock(Utf8JsonWriter writer, JsonSerializerOptions options, Block block)
{
switch (block)
{
case ParagraphBlock paragraphBlock:
{
var converter = (JsonConverter<ParagraphBlock>)options.GetConverter(typeof(ParagraphBlock));
converter.Write(writer, paragraphBlock, options);
break;
}
case HeadingBlock headingBlock:
{
var converter = (JsonConverter<HeadingBlock>)options.GetConverter(typeof(HeadingBlock));
converter.Write(writer, headingBlock, options);
break;
}
}
}
}

View File

@ -0,0 +1,35 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Markdig.Helpers;
using Markdig.Syntax;
namespace OliverBooth.Markdown.Renderers.JsonConverters;
public sealed class ParagraphBlockConverter : JsonConverter<ParagraphBlock>
{
/// <inheritdoc />
public override ParagraphBlock? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var node = JsonNode.Parse(reader.ValueSpan);
if (node is not JsonObject jsonObject)
{
return null;
}
return new ParagraphBlock
{
Lines = new StringLineGroup(jsonObject["text"]?.GetValue<string>() ?? string.Empty)
};
}
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, ParagraphBlock value, JsonSerializerOptions options)
{
string text = string.Join('\n', value.Inline);
writer.WriteStartObject();
writer.WriteString("type", "paragraph");
writer.WriteString("text", text);
writer.WriteEndObject();
}
}

View File

@ -1,3 +1,4 @@
@using System.Text.Json
@using OliverBooth.Common.Data.Blog
@using OliverBooth.Common.Services
@implements IDisposable
@ -7,6 +8,17 @@
@code {
private DotNetObjectReference<MarkdownEditor>? _dotNetHelper;
[JSInvokable]
public string GetEditorObject(Guid id)
{
if (!BlogPostService.TryGetPost(id, out IBlogPost? post))
{
return JsonSerializer.Serialize(new { blocks = Array.Empty<object>() });
}
return BlogPostService.GetBlogPostEditorObject(post);
}
[JSInvokable]
public void Save(Guid id, string content)
{

View File

@ -7,13 +7,18 @@ import SaveButtonMode from "./MarkdownEditor/SaveButtonMode";
import EditorJS from "@editorjs/editorjs";
import Header from "@editorjs/header";
import SimpleImage from "./BlockTools/SimpleImage";
import Utility from "../app/Utility";
(() => {
getCurrentBlogPost().then(post => {
getCurrentBlogPost().then(async post => {
if (!post) {
return;
}
await Utility.delay(1000); // hack to wait for setDotNetHelper invocation. TODO fix this shit
const blocks = JSON.parse(await Interop.invoke<string>("GetEditorObject", post.id));
console.log("JSON object is", blocks);
// UI.init();
// UI.addSaveButtonListener(savePost);
@ -29,7 +34,8 @@ import SimpleImage from "./BlockTools/SimpleImage";
}
},
image: SimpleImage
}
},
data: blocks
});
/*const editor = new MarkdownEditor(UI.markdownInput);

View File

@ -16,6 +16,7 @@ class BlogPost {
private readonly _formattedPublishDate: string;
private readonly _formattedUpdateDate: string;
private readonly _tags: string[];
private readonly _blockData: [{ id: string, type: string, data: any }];
constructor(json: any) {
this._id = json.id;
@ -33,6 +34,11 @@ class BlogPost {
this._formattedPublishDate = json.formattedPublishDate;
this._formattedUpdateDate = json.formattedUpdateDate;
this._tags = json.tags;
this._blockData = json.blockData;
}
get blockData(): [{ id: string, type: string, data: any }] {
return this._blockData;
}
get id(): string {
@ -70,7 +76,7 @@ class BlogPost {
get url(): BlogUrl {
return this._url;
}
get tags(): string[] {
return this._tags;
}

7
src/ts/app/Utility.ts Normal file
View File

@ -0,0 +1,7 @@
class Utility {
public static delay(timeout: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, timeout));
}
}
export default Utility;