From e0b544fc7e0c04bad3348408616c02d3a0028454 Mon Sep 17 00:00:00 2001 From: "John R. Supplee" Date: Mon, 1 Mar 2021 20:18:44 +0200 Subject: [PATCH] Add new Blaze search component --- client/components/main/myCards.js | 2 +- client/lib/cardSearch.js | 174 ++++++++++++++++++++++++++++++ models/usersessiondata.js | 2 +- server/publications/cards.js | 1 - 4 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 client/lib/cardSearch.js diff --git a/client/components/main/myCards.js b/client/components/main/myCards.js index 54aa8f505..03af8b561 100644 --- a/client/components/main/myCards.js +++ b/client/components/main/myCards.js @@ -1,4 +1,4 @@ -import {CardSearchPagedComponent} from "../../lib/cardSearch"; +import { CardSearchPagedComponent } from '../../lib/cardSearch'; const subManager = new SubsManager(); diff --git a/client/lib/cardSearch.js b/client/lib/cardSearch.js new file mode 100644 index 000000000..aea5b1188 --- /dev/null +++ b/client/lib/cardSearch.js @@ -0,0 +1,174 @@ +export class CardSearchPagedComponent extends BlazeComponent { + onCreated() { + this.searching = new ReactiveVar(false); + this.hasResults = new ReactiveVar(false); + this.hasQueryErrors = new ReactiveVar(false); + this.query = new ReactiveVar(''); + this.resultsHeading = new ReactiveVar(''); + this.searchLink = new ReactiveVar(null); + this.results = new ReactiveVar([]); + this.hasNextPage = new ReactiveVar(false); + this.hasPreviousPage = new ReactiveVar(false); + this.resultsCount = 0; + this.totalHits = 0; + this.queryErrors = null; + this.resultsPerPage = 25; + } + + resetSearch() { + this.searching.set(false); + this.results.set([]); + this.hasResults.set(false); + this.hasQueryErrors.set(false); + this.resultsHeading.set(''); + this.resultsCount = 0; + this.totalHits = 0; + this.queryErrors = null; + } + + getSessionData() { + return SessionData.findOne({ + userId: Meteor.userId(), + sessionId: SessionData.getSessionId(), + }); + } + + getResults() { + // eslint-disable-next-line no-console + // console.log('getting results'); + const sessionData = this.getSessionData(); + // eslint-disable-next-line no-console + // console.log('selector:', sessionData.getSelector()); + console.log('session data:', sessionData); + const projection = sessionData.getProjection(); + projection.skip = 0; + const cards = Cards.find({ _id: { $in: sessionData.cards } }, projection); + this.queryErrors = sessionData.errors; + if (this.queryErrors.length) { + this.hasQueryErrors.set(true); + return null; + } + + if (cards) { + this.totalHits = sessionData.totalHits; + this.resultsCount = cards.count(); + this.resultsStart = sessionData.lastHit - this.resultsCount + 1; + this.resultsEnd = sessionData.lastHit; + this.resultsHeading.set(this.getResultsHeading()); + this.results.set(cards); + this.hasNextPage.set(sessionData.lastHit < sessionData.totalHits); + this.hasPreviousPage.set( + sessionData.lastHit - sessionData.resultsCount > 0, + ); + return cards; + } + + this.resultsCount = 0; + return null; + } + + autorunGlobalSearch(params) { + this.searching.set(true); + + this.autorun(() => { + const handle = Meteor.subscribe( + 'globalSearch', + SessionData.getSessionId(), + params, + ); + Tracker.nonreactive(() => { + Tracker.autorun(() => { + if (handle.ready()) { + this.getResults(); + this.searching.set(false); + this.hasResults.set(true); + } + }); + }); + }); + } + + queryErrorMessages() { + const messages = []; + + this.queryErrors.forEach(err => { + let value = err.color ? TAPi18n.__(`color-${err.value}`) : err.value; + if (!value) { + value = err.value; + } + messages.push(TAPi18n.__(err.tag, value)); + }); + + return messages; + } + + nextPage() { + const sessionData = this.getSessionData(); + + this.autorun(() => { + const handle = Meteor.subscribe('nextPage', sessionData.sessionId); + Tracker.nonreactive(() => { + Tracker.autorun(() => { + if (handle.ready()) { + this.getResults(); + this.searching.set(false); + this.hasResults.set(true); + } + }); + }); + }); + } + + previousPage() { + const sessionData = this.getSessionData(); + + this.autorun(() => { + const handle = Meteor.subscribe('previousPage', sessionData.sessionId); + Tracker.nonreactive(() => { + Tracker.autorun(() => { + if (handle.ready()) { + this.getResults(); + this.searching.set(false); + this.hasResults.set(true); + } + }); + }); + }); + } + + getResultsHeading() { + if (this.resultsCount === 0) { + return TAPi18n.__('no-cards-found'); + } else if (this.resultsCount === 1) { + return TAPi18n.__('one-card-found'); + } else if (this.resultsCount === this.totalHits) { + return TAPi18n.__('n-cards-found', this.resultsCount); + } + + return TAPi18n.__('n-n-of-n-cards-found', { + start: this.resultsStart, + end: this.resultsEnd, + total: this.totalHits, + }); + } + + getSearchHref() { + const baseUrl = window.location.href.replace(/([?#].*$|\s*$)/, ''); + return `${baseUrl}?q=${encodeURIComponent(this.query.get())}`; + } + + events() { + return [ + { + 'click .js-next-page'(evt) { + evt.preventDefault(); + this.nextPage(); + }, + 'click .js-previous-page'(evt) { + evt.preventDefault(); + this.previousPage(); + }, + }, + ]; + } +} diff --git a/models/usersessiondata.js b/models/usersessiondata.js index 97f507402..7d7189ca1 100644 --- a/models/usersessiondata.js +++ b/models/usersessiondata.js @@ -184,7 +184,7 @@ function pickleValue(value) { if (value === null) { return null; } else if (typeof value === 'object') { - switch(value.constructor.name) { + switch (value.constructor.name) { case 'RegExp': return { $$class: 'RegExp', diff --git a/server/publications/cards.js b/server/publications/cards.js index a7b3f699c..af1778486 100644 --- a/server/publications/cards.js +++ b/server/publications/cards.js @@ -6,7 +6,6 @@ Meteor.publish('card', cardId => { }); Meteor.publish('myCards', function(sessionId) { - const queryParams = { users: [Meteor.user().username], // limit: 25,