Browse Source

refactored search, resolve #821

Bachir Soussi Chiadmi 3 năm trước cách đây
mục cha
commit
c29b86a5ae

+ 3 - 3
src/components/nav/Results.vue

@@ -8,7 +8,7 @@
     >
       <header class="col-1">
         <h2>Resultats</h2>
-        <span class="search-keys">{{ keys }}</span><br>
+        <span class="search-keys">{{ searchedKeys }}</span><br>
         <span v-if="resultsQuantity" class="results-count">{{ resultsCount }}</span>
         <v-select
           id="sorting"
@@ -29,8 +29,8 @@
             </li>
             <infinite-loading
               v-if="offset < resultsQuantity.quantity"
-              @infinite="nextResultsBatch"
               :identifier="isloading"
+              @infinite="nextResultsBatch"
             />
           </ul>
         </div>
@@ -68,7 +68,7 @@ export default {
     },
     ...mapState({
       isloading: state => state.Search.isloading,
-      keys: state => state.Search.keys,
+      searchedKeys: state => state.Search.searchedKeys,
       results: state => state.Search.results,
       resultsQuantity: state => state.Search.resultsQuantity,
       offset: state => state.Search.offset,

+ 3 - 2
src/components/nav/Search.vue

@@ -91,6 +91,7 @@ export default {
   data: () => ({
   }),
   computed: {
+    // TODO: do not synch keys instantetly (infinite loading will drop)
     keys: {
       get () { return this.$store.state.Search.keys },
       set (value) { this.$store.commit('Search/setKeys', value) }
@@ -115,15 +116,15 @@ export default {
   },
   methods: {
     ...mapMutations({
+      setSearchTypeValue: 'Search/setSearchTypeValue',
       setActiveFilters: 'Search/setActiveFilters'
     }),
     ...mapActions({
       newSearch: 'Search/newSearch',
-      setSearchTypeValue: 'Search/setSearchTypeValue',
       updateSearch: 'Search/updateSearch'
     }),
     submit () {
-      console.log('submited', this.keys)
+      // console.log('submited', this.keys)
       this.newSearch()
     },
     dropDownMenuPos (dropdownList, component, { width }) {

+ 2 - 1
src/index.js

@@ -22,7 +22,8 @@ Vue.use(InfiniteLoading, {
   },
   slots: {
     noMore: '',
-    noResult: ''
+    noResults: '',
+    error: ''
   }
   // system: {
   //   throttleLimit: 50,

+ 7 - 6
src/store/modules/corpus.js

@@ -34,7 +34,7 @@ export default {
       console.log('corpus editionsbyuuid', state.editionsbyuuid)
     },
     setTocs (state, tocslist) {
-      console.log('setTocs', tocslist)
+      // console.log('setTocs', tocslist)
       tocslist.forEach((toc, i) => {
         state.editionsbyuuid[toc.uuid].toc = Array.isArray(toc.toc) ? toc.toc : [toc.toc]
       })
@@ -58,13 +58,14 @@ export default {
       })
     },
     setPaginations (state, paginationslist) {
-      console.log('setPaginations', paginationslist)
+      // console.log('setPaginations', paginationslist)
       paginationslist.forEach((pagination, i) => {
         state.editionsbyuuid[pagination.uuid].pagination = pagination.pagination
       })
       // console.log('corpus editionsbyuuid', state.editionsbyuuid)
     },
     setCorpusLoaded (state) {
+      console.info('corpusLoaded')
       state.corpusLoaded = true
     }
   },
@@ -76,7 +77,7 @@ export default {
         // get the list of corpuses (aka authors)
         dispatch('getAuthors')
           .then(({ data }) => {
-            console.log('getCorpuses authors data', data)
+            // console.log('getCorpuses authors data', data)
             commit('setAuthors', data.content)
             // get the texts list for each corpus (aka author)
             // let authorsUuids = []
@@ -124,7 +125,7 @@ export default {
       return Promise.all(authors.map(function (author) {
         return REST.get(`${window.apipath}/corpus/` + author.uuid, {})
           .then(({ data }) => {
-            console.log('corpus getEditionsList REST: author, data', author, data)
+            // console.log('corpus getEditionsList REST: author, data', author, data)
             // work arround
             if (!Array.isArray(data.content)) {
               data.content = [data.content]
@@ -145,7 +146,7 @@ export default {
       return Promise.all(state.editionsuuids.map(function (uuid) {
         return REST.get(`${window.apipath}/texts/${uuid}/toc`, {})
           .then(({ data }) => {
-            console.log('corpus getEditionsTocs REST: uuid, data', uuid, data)
+            // console.log('corpus getEditionsTocs REST: uuid, data', uuid, data)
             // work arround
             // if (!Array.isArray(data.content)) {
             //   data.content = [data.content]
@@ -166,7 +167,7 @@ export default {
       return Promise.all(state.editionsuuids.map(function (uuid) {
         return REST.get(`${window.apipath}/texts/${uuid}/pagination`, {})
           .then(({ data }) => {
-            console.log('corpus getEditionsPaginations REST: uuid, data', uuid, data)
+            // console.log('corpus getEditionsPaginations REST: uuid, data', uuid, data)
             // work arround
             // if (!Array.isArray(data.content)) {
             //   data.content = [data.content]

+ 101 - 75
src/store/modules/search.js

@@ -1,11 +1,12 @@
-// import axios from 'axios'
+import axios from 'axios'
 
 import { REST } from 'api/rest-axios'
 import qs from 'querystring'
 
-// const _CancelToken = axios.CancelToken
+const _filterskeys = ['persons', 'places', 'objects']
+const _CancelToken = axios.CancelToken
 // const _cancelTokenSource = _CancelToken.source()
-// let _cancel
+let _cancelTokens = []
 
 export default {
   namespaced: true,
@@ -14,6 +15,7 @@ export default {
   // initial state
   state: {
     keys: '',
+    searchedKeys: '',
     searchTypeOptions: [
       { 'code': 'text', 'label': 'Dans les textes' },
       { 'code': 'persons', 'label': 'Dans les personnes' },
@@ -32,9 +34,6 @@ export default {
     results: [],
     resultsQuantity: null,
     isloading: false,
-    // infiniteLoadingIsLoading: false,
-    // infiniteLoadingCancelToken: null,
-    // infiniteLoadingCancelTokenSource: null,
     limit: 10,
     offset: 0,
     opened: false
@@ -48,11 +47,17 @@ export default {
     setKeys (state, keys) {
       state.keys = keys
     },
+    setSearchKeys (state) {
+      state.searchedKeys = state.keys
+    },
     setResults (state, content) {
       state.results = state.results.concat(content)
     },
     resetResults (state) {
+      console.log('resetResults')
       state.results = []
+    },
+    resetOffset (state) {
       state.offset = 0
     },
     setResultsCount (state, quantity) {
@@ -62,6 +67,7 @@ export default {
       state.offset += state.limit
     },
     setIsloading (state, isloading) {
+      console.log('setIsloading', isloading)
       state.isloading = isloading
     },
     setOpened (state, opened) {
@@ -106,7 +112,7 @@ export default {
       // console.log('state.activeFilters', state.activeFilters)
     },
     resetActiveFilters (state) {
-      for (var index of ['persons', 'places', 'objects']) {
+      for (var index of _filterskeys) {
         state.activeFilters[index] = []
       }
     },
@@ -118,18 +124,23 @@ export default {
 
   // actions
   actions: {
-    getResults ({ dispatch, commit, state }, $infiniteLoadingState = null) {
-      console.log('getResults', state.keys, $infiniteLoadingState)
-      // reset results on new search
-      if (!$infiniteLoadingState) {
+    getResults ({ dispatch, commit, state }, pl) {
+      console.log(`getResults keys: ${pl.keys}, infiniteLoading:`, pl.infiniteLoading)
+
+      if (!pl.infiniteLoading) {
+        // loading indicator unless we are on infiniteloading
         commit('setIsloading', true)
+        commit('resetOffset')
+        // cancel infiniteloading requests
+        _cancelTokens.forEach((ct, i) => {
+          console.log('_cancelTokens forEach ct', ct)
+          ct.cancel('new or updated search fired')
+        })
       }
-      // else {
-      //   state.infiniteLoadingIsLoading = true
-      // }
 
+      // construct params
       let params = {
-        search: `${state.keys}`,
+        search: `${pl.keys}`,
         start: state.offset,
         count: state.limit
       }
@@ -137,7 +148,7 @@ export default {
         params.type = state.searchTypeValue.code
       }
       let f
-      for (var index of ['persons', 'places', 'objects']) {
+      for (var index of _filterskeys) {
         if (state.activeFilters[index].length) {
           f = `filter${index.charAt(0).toUpperCase()}${index.slice(1)}`
           params[f] = []
@@ -146,94 +157,109 @@ export default {
           }
         }
       }
-      // params.filterPersons = ['nomLouisXIII', 'nomChampagnePhilippeDe']
       if (state.sorting) {
         params.sort = state.sorting.code
       }
       // console.log('Search getResults params', params);
       let q = qs.stringify(params)
 
+      // construct options
       let ops = {}
-      // if ($infiniteLoadingState) {
-      //   ops.cancelToken = new _CancelToken(function executor (c) {
-      //     _cancel = c
-      //   })
-      // }
+      if (pl.infiniteLoading) {
+        ops.cancelToken = pl.infiniteLoading.cancelToken
+      }
+
       return REST.get(`${window.apipath}/search?` + q, ops)
         .then(({ data }) => {
-          console.log('search REST: data', data.meta.quantity.quantity, state.offset + state.limit, data)
+          console.log(`search REST quantity: ${data.meta.quantity.quantity}, offset+limit: ${state.offset + state.limit}, data:`, data)
           commit('setResultsCount', data.meta.quantity)
           commit('setFilters', data.meta.filters)
-          if ($infiniteLoadingState) {
-            if (state.isLoading) {
-              // we are in a new search or an update so we dont apply the infinite loading received results
-              $infiniteLoadingState.complete()
-            } else {
-              commit('setResults', data.content)
-              if (state.offset + state.limit > data.meta.quantity.quantity) {
-                console.log('Search infinite completed')
-                // tell to vue-infinite-loading plugin that there si no new page
-                $infiniteLoadingState.complete()
-              } else {
-                console.log('Search infinite loaded')
-                // tell to vue-infinite-loading plugin that newpage is loaded
-                $infiniteLoadingState.loaded()
-              }
-              // state.infiniteLoadingIsLoading = false
-            }
-          } else {
+
+          if (state.isloading) {
+            // a new or updated search has been launched :
+            // we dont apply the infinite loading received results
+            // and we reset the infinite loader
+            // pl.infiniteLoading.$state.reset()
+            _cancelTokens.forEach((ct, i) => {
+              console.log('_cancelTokens forEach AFTER ct', ct)
+              ct.cancel('new or updated search fired')
+              ct.$state.complete()
+            })
+            _cancelTokens = []
+          }
+
+          if (!pl.infiniteLoading) {
+            // we are not on infiniteloading
+            // new or updated search
             commit('resetResults')
+            commit('setSearchKeys')
+            commit('setResults', data.content)
             commit('setIsloading', false)
             commit('setOpened', true)
+          } else {
+            // we are on infiniteloading
+            // normal InfiniteLoading procedure
             commit('setResults', data.content)
+            if (state.offset + state.limit > data.meta.quantity.quantity) {
+              // tell to vue-infinite-loading plugin that there is no new page
+              pl.infiniteLoading.$state.complete()
+            } else {
+              // tell to vue-infinite-loading plugin that newpage is loaded
+              pl.infiniteLoading.$state.loaded()
+            }
           }
         })
         .catch((error) => {
-          console.warn('Issue with search', error)
-          commit('setIsloading', false)
-          // if (axios.isCancel(error)) {
-          //   console.log('Request canceled', error.message)
-          //   if ($infiniteLoadingState) {
-          //     $infiniteLoadingState.complete()
-          //   }
-          // } else {
-          Promise.reject(error)
-          if ($infiniteLoadingState) {
-            $infiniteLoadingState.error()
+          // console.warn('Issue with search', error)
+          if (axios.isCancel(error)) {
+            console.info(`Request canceled, message: ${error.message}`)
+            // TODO: the $state here is probably not the good one
+            // Promise.reject(error)
+            // pl.infiniteLoading.$state.reset()
+          } else {
+            commit('setIsloading', false)
+            if (pl.infiniteLoading) {
+              pl.infiniteLoading.$state.error()
+            }
+            Promise.reject(error)
           }
-          // }
         })
     },
     newSearch ({ dispatch, commit, state }) {
-      // commit('resetResults')
       commit('resetActiveFilters')
-      // if (_cancel) {
-      //   _cancel('new search fired')
-      // }
-      dispatch('getResults')
+      dispatch('getResults', { keys: state.keys })
+      // .then((e) => {
+      //   console.log('dispatch get results then', e)
+      // })
     },
     updateSearch ({ dispatch, commit, state }) {
-      // TODO: wait for new results came to reset results list
-      // TODO: indicate loading state
-      // commit('resetResults')
-      dispatch('getResults')
+      dispatch('getResults', { keys: state.searchedKeys })
     },
     nextResultsBatch ({ dispatch, commit, state }, $infiniteLoadingState) {
-      console.log('nextResultsBatch', $infiniteLoadingState)
-      commit('incrementOffset')
-      if (state.offset < state.resultsQuantity.quantity) {
-        dispatch('getResults', $infiniteLoadingState)
-      } else {
+      console.log(`nextResultsBatch, isloading: ${state.isloading}`, $infiniteLoadingState)
+      if (state.isloading) {
+        // we are loading a new or updated searche
+        // we stop the infinite
         $infiniteLoadingState.complete()
+      } else {
+        commit('incrementOffset')
+        if (state.offset < state.resultsQuantity.quantity) {
+          dispatch('getResults', {
+            keys: state.searchedKeys,
+            infiniteLoading: {
+              $state: $infiniteLoadingState,
+              cancelToken: new _CancelToken((c) => {
+                _cancelTokens.push({
+                  cancel: c,
+                  $state: $infiniteLoadingState
+                })
+              })
+            }
+          })
+        } else {
+          $infiniteLoadingState.complete()
+        }
       }
-    },
-    setSearchTypeValue ({ dispatch, commit, state }, value) {
-      commit('setSearchTypeValue', value)
     }
-    // setSearchActiveFilters ({ dispatch, commit, state }, filters) {
-    //   // console.log('setSearchFiltersValue', filters)
-    //   commit('setActiveFilters', filters)
-    //   dispatch('updateSearch')
-    // }
   }
 }