148 lines
5.0 KiB
C#
148 lines
5.0 KiB
C#
using System.Windows;
|
||
using System.Windows.Threading;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using SimpleWiki.Data;
|
||
using SimpleWiki.Models;
|
||
using SimpleWiki.Services;
|
||
|
||
namespace SimpleWiki.Views;
|
||
|
||
public partial class ArticleEditorWindow : Window
|
||
{
|
||
private readonly User _currentUser;
|
||
private readonly int? _articleId;
|
||
private bool _isPreviewBrowserReady;
|
||
private string _pendingPreviewHtml = string.Empty;
|
||
|
||
public ArticleEditorWindow(User currentUser, int? articleId = null)
|
||
{
|
||
InitializeComponent();
|
||
_currentUser = currentUser;
|
||
_articleId = articleId;
|
||
_pendingPreviewHtml = MarkdownService.ToHtmlDocument("Предпросмотр", "# Предпросмотр\n\nПодготовка предпросмотра...");
|
||
Loaded += ArticleEditorWindow_Loaded;
|
||
ContentRendered += ArticleEditorWindow_ContentRendered;
|
||
}
|
||
|
||
|
||
private void ArticleEditorWindow_ContentRendered(object? sender, EventArgs e)
|
||
{
|
||
_isPreviewBrowserReady = true;
|
||
Dispatcher.BeginInvoke(RenderPreviewIfReady, DispatcherPriority.ApplicationIdle);
|
||
}
|
||
|
||
private void ArticleEditorWindow_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
if (_articleId.HasValue)
|
||
{
|
||
using var db = new AppDbContext();
|
||
var article = db.Articles.AsNoTracking().FirstOrDefault(x => x.Id == _articleId.Value);
|
||
if (article is not null)
|
||
{
|
||
TitleTextBox.Text = article.Title;
|
||
SummaryTextBox.Text = article.Summary;
|
||
MarkdownTextBox.Text = article.MarkdownContent;
|
||
}
|
||
}
|
||
|
||
UpdatePreview();
|
||
}
|
||
|
||
private void AnyInput_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
||
{
|
||
UpdatePreview();
|
||
}
|
||
|
||
private void UpdatePreview()
|
||
{
|
||
var title = string.IsNullOrWhiteSpace(TitleTextBox.Text) ? "Новая статья" : TitleTextBox.Text.Trim();
|
||
var content = string.IsNullOrWhiteSpace(MarkdownTextBox.Text)
|
||
? "# Предпросмотр\n\nЗдесь появится отрендеренный markdown."
|
||
: MarkdownTextBox.Text;
|
||
|
||
_pendingPreviewHtml = MarkdownService.ToHtmlDocument(title, content);
|
||
RenderPreviewIfReady();
|
||
}
|
||
|
||
private void RenderPreviewIfReady()
|
||
{
|
||
if (!_isPreviewBrowserReady)
|
||
{
|
||
return;
|
||
}
|
||
|
||
PreviewBrowser.NavigateToString(_pendingPreviewHtml);
|
||
}
|
||
|
||
private void SaveButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
var titleError = InputValidator.ValidateArticleTitle(TitleTextBox.Text);
|
||
var summaryError = InputValidator.ValidateArticleSummary(SummaryTextBox.Text);
|
||
var markdownError = InputValidator.ValidateArticleMarkdown(MarkdownTextBox.Text);
|
||
var errors = InputValidator.JoinErrors(titleError, summaryError, markdownError);
|
||
|
||
if (!string.IsNullOrWhiteSpace(errors))
|
||
{
|
||
MessageBox.Show(errors, "Ошибка валидации", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
using var db = new AppDbContext();
|
||
var slug = SlugHelper.Generate(TitleTextBox.Text);
|
||
|
||
if (_articleId.HasValue)
|
||
{
|
||
var article = db.Articles.FirstOrDefault(x => x.Id == _articleId.Value);
|
||
if (article is null)
|
||
{
|
||
MessageBox.Show("Статья не найдена.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
|
||
var duplicate = db.Articles.AsNoTracking().Any(x => x.Slug == slug && x.Id != article.Id);
|
||
if (duplicate)
|
||
{
|
||
MessageBox.Show("Статья с таким заголовком уже существует.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
|
||
article.Title = TitleTextBox.Text.Trim();
|
||
article.Summary = SummaryTextBox.Text.Trim();
|
||
article.MarkdownContent = MarkdownTextBox.Text.Trim();
|
||
article.Slug = slug;
|
||
article.UpdatedAt = DateTime.UtcNow;
|
||
}
|
||
else
|
||
{
|
||
var duplicate = db.Articles.AsNoTracking().Any(x => x.Slug == slug);
|
||
if (duplicate)
|
||
{
|
||
MessageBox.Show("Статья с таким заголовком уже существует.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
|
||
var article = new Article
|
||
{
|
||
Title = TitleTextBox.Text.Trim(),
|
||
Summary = SummaryTextBox.Text.Trim(),
|
||
MarkdownContent = MarkdownTextBox.Text.Trim(),
|
||
Slug = slug,
|
||
AuthorId = _currentUser.Id,
|
||
CreatedAt = DateTime.UtcNow
|
||
};
|
||
|
||
db.Articles.Add(article);
|
||
}
|
||
|
||
db.SaveChanges();
|
||
DialogResult = true;
|
||
Close();
|
||
}
|
||
|
||
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
DialogResult = false;
|
||
Close();
|
||
}
|
||
}
|