266 lines
7.5 KiB
C#
266 lines
7.5 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
using Blog3000.Shared;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Net.Http;
|
|
using Microsoft.JSInterop;
|
|
|
|
namespace Blog3000.Client.Shared
|
|
{
|
|
public partial class PostFinder : IDisposable
|
|
{
|
|
|
|
public class State
|
|
{
|
|
public int StartIdx;
|
|
public string Search;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Could be use with dict/startIdKey for use on different pages
|
|
/// </summary>
|
|
private static State CurrentState = new State();
|
|
|
|
|
|
|
|
[Inject]
|
|
private BlogDb BlogDb { get; set; }
|
|
|
|
[Inject]
|
|
private NetworkStatus NetworkStatus { get; set; }
|
|
|
|
[Inject]
|
|
private HttpClient Http { get; set; }
|
|
|
|
[Inject]
|
|
private IJSRuntime JSRuntime { get; set; }
|
|
|
|
private string errorMsg { get; set; }
|
|
private string dispMode { get; set; }
|
|
|
|
private string PageInfo
|
|
{
|
|
get
|
|
{
|
|
var res = $"{StartIdx + 1}-{StartIdx + 0 + pageSize} ";
|
|
if (totalPostsFound != null)
|
|
{
|
|
if (totalPostsFound == 1)
|
|
{
|
|
res += $"(of 1)";
|
|
}
|
|
else if (totalPostsFound > 1)
|
|
{
|
|
res += $"(of {totalPostsFound})";
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
|
|
private ElementReference ScrollAnchorElement;
|
|
|
|
private string SearchText { get; set; }
|
|
|
|
private int StartIdx
|
|
{
|
|
get
|
|
{
|
|
return startIdx;
|
|
}
|
|
set
|
|
{
|
|
startIdx = value;
|
|
OnStartIdxChanged();
|
|
}
|
|
}
|
|
private int startIdx = 0;
|
|
|
|
private int pageSize = 6;
|
|
|
|
private int pageMaxSize = 6;
|
|
|
|
private int? totalPostsFound = null;
|
|
|
|
private List<BlogPostHeader> selectedPosts = new List<BlogPostHeader>();
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
BlogDb.BlogPostsChanged -= BlogDb_BlogPostsChanged;
|
|
|
|
}
|
|
|
|
|
|
public async void StartSearch(string searchString)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"Got searchstring {searchString}");
|
|
SearchText = searchString;
|
|
// await SelectPosts();
|
|
// StateHasChanged();
|
|
UpdateSearch();
|
|
}
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
|
|
StartIdx = CurrentState.StartIdx;
|
|
SearchText = CurrentState.Search;
|
|
|
|
BlogDb.BlogPostsChanged += BlogDb_BlogPostsChanged;
|
|
|
|
await SelectPosts();
|
|
}
|
|
|
|
private async void BlogDb_BlogPostsChanged(object sender, EventArgs e)
|
|
{
|
|
await SelectPosts();
|
|
this.StateHasChanged();
|
|
}
|
|
|
|
private void GotoFirst()
|
|
{
|
|
System.Diagnostics.Debug.WriteLine("Goto first");
|
|
StartIdx = 0;
|
|
}
|
|
|
|
private void GotoNext()
|
|
{
|
|
StartIdx += pageMaxSize;
|
|
}
|
|
|
|
private void GotoPrev()
|
|
{
|
|
StartIdx -= pageMaxSize;
|
|
}
|
|
|
|
|
|
private async void ClearSearch()
|
|
{
|
|
errorMsg = null;
|
|
SearchText = "";
|
|
startIdx = 0;
|
|
totalPostsFound = null;
|
|
await SelectPosts();
|
|
StateHasChanged();
|
|
CurrentState.StartIdx = StartIdx;
|
|
CurrentState.Search = "";
|
|
}
|
|
|
|
private async void UpdateSearch()
|
|
{
|
|
errorMsg = null;
|
|
startIdx = 0;
|
|
totalPostsFound = null;
|
|
await SelectPosts();
|
|
StateHasChanged();
|
|
CurrentState.StartIdx = StartIdx;
|
|
CurrentState.Search = SearchText;
|
|
_ = JSRuntime.InvokeVoidAsync("scrollElmIntoView", ScrollAnchorElement);
|
|
}
|
|
|
|
|
|
private async void OnStartIdxChanged()
|
|
{
|
|
if (startIdx < 0) startIdx = 0;
|
|
await SelectPosts();
|
|
if (selectedPosts.Count == 0 && startIdx > 0)
|
|
{
|
|
// Too far, go back one page
|
|
StartIdx -= pageMaxSize;
|
|
await SelectPosts();
|
|
|
|
// Bad input? instruct DB to find last page
|
|
if (selectedPosts.Count == 0 && startIdx > 0)
|
|
{
|
|
await SelectPosts(true);
|
|
}
|
|
}
|
|
StateHasChanged();
|
|
CurrentState.StartIdx = StartIdx;
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task SelectPosts(bool findLastPage = false)
|
|
{
|
|
|
|
bool fulltextIsLocallyAvail = await BlogDb.IsEagerLoading();
|
|
bool isOnline = NetworkStatus.IsOnline;
|
|
|
|
var bps = new BlogPostSearch(() => BlogDb.GetCachedPostsAsync(), () => BlogDb.GetHeadersAsync(), SearchText);
|
|
|
|
if (!bps.IsNonEmptyTerm)
|
|
{
|
|
dispMode = "Last posts";
|
|
}
|
|
else
|
|
{
|
|
// Brutal fulltext search.. Should be good for the first 100 articles or so...
|
|
dispMode = "Search";
|
|
}
|
|
|
|
if (!bps.IsNonEmptyTerm)
|
|
{
|
|
var res = await bps.ExecAsync(startIdx, pageMaxSize, findLastPage);
|
|
pageSize = res.Count;
|
|
totalPostsFound = await BlogDb.GetHeadersAsync()
|
|
.Where(a => "PUBLIC".Equals(a.Access))
|
|
.Where(p => (p.StickyMenuPos ?? -1) < 0)
|
|
.CountAsync();
|
|
|
|
selectedPosts = res;
|
|
}
|
|
else
|
|
{
|
|
bool needsFullText = bps.RequiresFullText;
|
|
|
|
if (!fulltextIsLocallyAvail && needsFullText)
|
|
{
|
|
if (!isOnline)
|
|
{
|
|
errorMsg = "Offline, search not possible";
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
var url = $"/BlogPosts/search?searchTerm={System.Net.WebUtility.UrlEncode(SearchText)}&startIdx={startIdx}&pageMaxSize={pageMaxSize}&findLastPage={findLastPage}";
|
|
var ids = await Http.GetJsonAsync<List<String>>(url);
|
|
var res = new List<BlogPostHeader>();
|
|
foreach (var id in ids)
|
|
{
|
|
var bp = await BlogDb.GetHeaderAsync(id);
|
|
if (bp != null)
|
|
{
|
|
res.Add(bp);
|
|
}
|
|
await Task.Yield();
|
|
}
|
|
pageSize = res.Count;
|
|
selectedPosts = res;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"Exception during search: {ex}");
|
|
errorMsg = $"Error during search: {ex.Message}";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var efetch = BlogDb.GetCachedPostsAsync();
|
|
var res = await bps.ExecAsync(startIdx, pageMaxSize, findLastPage);
|
|
pageSize = res.Count;
|
|
selectedPosts = res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|