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(); } }