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; } /// /// Could be use with dict/startIdKey for use on different pages /// 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 selectedPosts = new List(); 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>(url); var res = new List(); 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; } } } } }