diff --git a/Wave/Components/Pages/ArticleView.razor b/Wave/Components/Pages/ArticleView.razor index 0a09123..864e77b 100644 --- a/Wave/Components/Pages/ArticleView.razor +++ b/Wave/Components/Pages/ArticleView.razor @@ -186,7 +186,7 @@ if (Id is not null) { Article = query.AsSingleQuery().FirstOrDefault(a => a.Id == Id); } else if (Date is { } date && Title is { } title) { - string? slug = TitleEncoded == null ? null : Uri.EscapeDataString(TitleEncoded); + string? slug = TitleEncoded == null ? null : Uri.EscapeDataString(TitleEncoded.Replace("-", " ")).Replace("%20", "-"); Article = query.AsSingleQuery().FirstOrDefault(a => a.PublishDate.Date == date.Date && (slug != null && a.Slug == slug || a.Title.ToLower() == title)); diff --git a/Wave/Components/Pages/Partials/ArticleEditorPartial.razor b/Wave/Components/Pages/Partials/ArticleEditorPartial.razor index b62f07b..3f36538 100644 --- a/Wave/Components/Pages/Partials/ArticleEditorPartial.razor +++ b/Wave/Components/Pages/Partials/ArticleEditorPartial.razor @@ -188,13 +188,18 @@ Article.PublishDate = Model.PublishDate.Value; if (Article.Status is ArticleStatus.Published && Article.PublishDate < DateTimeOffset.Now) { // can't change slugs when the article is public - } else if (!string.IsNullOrWhiteSpace(Model.Slug)) { - Article.Slug = WebUtility.UrlEncode(Model.Slug); - } else if (string.IsNullOrWhiteSpace(Article.Slug)) { - Article.Slug = Uri.EscapeDataString(Article.Title.ToLowerInvariant()) - .Replace("-", "+") - .Replace("%20", "-"); - Article.Slug = Article.Slug[..Math.Min(64, Article.Slug.Length)]; + } else if (!string.IsNullOrWhiteSpace(Model.Slug) || string.IsNullOrWhiteSpace(Article.Slug)) { + string baseSlug = Model.Slug ?? Article.Title; + baseSlug = baseSlug.ToLowerInvariant()[..Math.Min(64, baseSlug.Length)]; + string slug = Uri.EscapeDataString(baseSlug).Replace("-", "+").Replace("%20", "-"); + // if our escaping increases the slug length, there is a chance it ends with an escape + // character, so if this overshoot is not divisible by 3, then we risk cutting of the + // escape character, so we need to remove it in it's entirely if that's the case + int escapeTrimOvershoot = Math.Max(0, 3 - (slug.Length - baseSlug.Length) % 3); + // if the slug already fits 64 character, there will be no cutoff in the next operation anyway, + // so we don't need to fix what is described in the previous comment + if (slug.Length <= 64) escapeTrimOvershoot = 0; + Article.Slug = slug[..Math.Min(slug.Length, 64 - escapeTrimOvershoot)]; Model.Slug = Article.Slug; }