@ecomplus/widget-search-engine 1.0.0-beta.13 → 1.0.0-beta.132

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecomplus/widget-search-engine",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.132",
4
4
  "description": "Storefront plugin & Vue component for dynamic search page",
5
5
  "module": "src/index.js",
6
6
  "browser": "dist/widget-search-engine.min.js",
@@ -8,7 +8,7 @@
8
8
  "jsdelivr": "dist/public/widget-search-engine.var.min.js",
9
9
  "unpkg": "dist/public/widget-search-engine.var.min.js",
10
10
  "scripts": {
11
- "build": "NODE_ENV=production webpack",
11
+ "build": "cross-env NODE_ENV=production webpack",
12
12
  "serve": "webpack-dev-server"
13
13
  },
14
14
  "repository": {
@@ -29,12 +29,13 @@
29
29
  },
30
30
  "homepage": "https://github.com/ecomplus/storefront/tree/master/@ecomplus/widget-search-engine#readme",
31
31
  "peerDependencies": {
32
- "@ecomplus/utils": "^1.4.0",
32
+ "@ecomplus/utils": "^1.4.1",
33
33
  "core-js": "3.x",
34
34
  "vue": ">=2 <4"
35
35
  },
36
36
  "dependencies": {
37
- "@ecomplus/storefront-components": "^1.0.0-beta.16"
37
+ "@ecomplus/storefront-components": "^1.0.0-beta.133",
38
+ "@ecomplus/storefront-twbs": "^7.3.0"
38
39
  },
39
40
  "webpackOutput": {
40
41
  "library": "widgetSearchEngine",
package/src/index.js CHANGED
@@ -4,27 +4,39 @@
4
4
  * Released under the MIT License.
5
5
  */
6
6
 
7
+ import { $ } from '@ecomplus/storefront-twbs'
7
8
  import Vue from 'vue'
8
9
  import SearchEngine from '#components/SearchEngine.vue'
9
10
 
10
- export default (options = {}, elId = 'search-engine') => {
11
+ export default (options = {}, elId = 'search-engine', paginationElId = 'search-pagination') => {
11
12
  const $searchEngine = document.getElementById(elId)
12
13
  if ($searchEngine) {
14
+ const $dock = document.getElementById(`${elId}-dock`)
15
+ let $productItems
13
16
  const getScopedSlots = window.storefront && window.storefront.getScopedSlots
17
+ const { dataset } = $searchEngine
14
18
 
15
19
  const urlParams = new URLSearchParams(window.location.search)
16
20
  const props = {
17
21
  ...options.props,
18
22
  term: urlParams.get('term'),
19
- page: parseInt(urlParams.get('page'), 10) || 1,
20
23
  brands: urlParams.getAll('brands[]'),
21
- categories: urlParams.getAll('categories[]')
24
+ categories: urlParams.getAll('categories[]'),
25
+ defaultFilters: urlParams.getAll('filters[]').reduce((filters, gridAndOption) => {
26
+ const [gridId, option] = gridAndOption.split(':')
27
+ if (!filters[gridId]) {
28
+ filters[gridId] = []
29
+ }
30
+ filters[gridId].push(option)
31
+ return filters
32
+ }, {}),
33
+ defaultSort: dataset.sort || urlParams.get('sort')
22
34
  }
23
35
 
24
36
  ;['brands', 'categories'].forEach(resource => {
25
- if ($searchEngine.dataset[resource]) {
37
+ if (dataset[resource]) {
26
38
  try {
27
- props[resource] = JSON.parse($searchEngine.dataset[resource])
39
+ props[resource] = JSON.parse(dataset[resource])
28
40
  } catch (err) {
29
41
  console.error(err)
30
42
  return
@@ -32,21 +44,172 @@ export default (options = {}, elId = 'search-engine') => {
32
44
  if (props[resource] && props[resource].length < 2) {
33
45
  props[`isFixed${resource.charAt(0).toUpperCase()}${resource.slice(1)}`] = true
34
46
  }
35
- props.defaultSort = 'sales'
36
47
  props.hasPopularItems = false
37
48
  }
38
49
  })
39
50
 
40
- new Vue({
41
- render: h => h(SearchEngine, {
42
- attrs: {
43
- id: elId
44
- },
45
- props,
46
- scopedSlots: typeof getScopedSlots === 'function'
47
- ? getScopedSlots($searchEngine, h)
48
- : undefined
49
- })
50
- }).$mount($searchEngine)
51
+ const { resource } = window.document.body.dataset
52
+ switch (resource) {
53
+ case 'brands':
54
+ case 'categories':
55
+ if (!props[resource] || !props[resource].length) {
56
+ console.error(new Error(`Skipping SearchEngine with empty '${resource}' filter`))
57
+ return
58
+ }
59
+ }
60
+
61
+ const pageTitle = document.title
62
+ const updatePageUrl = () => {
63
+ const term = urlParams.get('term')
64
+ let title = term ? `${term} ~ ${pageTitle}` : pageTitle
65
+ const page = urlParams.get('page')
66
+ if (page > 1) {
67
+ title += ` (${page}) `
68
+ }
69
+ if (window.history) {
70
+ const query = urlParams.toString()
71
+ const { pathname } = window.location
72
+ window.history.pushState({
73
+ pathname,
74
+ query
75
+ }, title, pathname + (query ? `?${query}` : ''))
76
+ }
77
+ document.title = title
78
+ }
79
+ updatePageUrl()
80
+
81
+ const vueApp = new Vue({
82
+ data: {
83
+ countRequests: 0,
84
+ canShowItems: !$dock,
85
+ term: props.term,
86
+ page: parseInt(urlParams.get('page'), 10) || 1,
87
+ totalItems: 0
88
+ },
89
+
90
+ render (createElement) {
91
+ const vm = this
92
+ if (options.pagination) {
93
+ import('#components/APagination.vue')
94
+ .then(pagination => {
95
+ new Vue({
96
+ render: h => h(pagination.default, {
97
+ props: {
98
+ totalItems: vm.totalItems,
99
+ page: vm.page
100
+ },
101
+ on: {
102
+ 'update:page' (page) {
103
+ vm.page = page
104
+ urlParams.set('page', page)
105
+ updatePageUrl()
106
+ window.scroll({
107
+ top: 0,
108
+ behavior: 'smooth'
109
+ })
110
+ }
111
+ }
112
+ })
113
+ }).$mount(document.getElementById(paginationElId))
114
+ })
115
+ }
116
+
117
+ return createElement(SearchEngine, {
118
+ attrs: {
119
+ id: $dock ? null : elId
120
+ },
121
+ props: {
122
+ ...props,
123
+ term: vm.term,
124
+ page: vm.page,
125
+ canLoadMore: !options.pagination && !dataset.disableLoadMore,
126
+ canShowItems: vm.canShowItems,
127
+ loadMoreSelector: $dock ? '#search-engine-load' : null,
128
+ isFilterable: !dataset.disableFilters
129
+ },
130
+
131
+ on: {
132
+ 'update:term' (term) {
133
+ vm.term = term
134
+ urlParams.set('term', term)
135
+ updatePageUrl()
136
+ },
137
+
138
+ fetch ({ ecomSearch, fetching, isPopularItems }) {
139
+ fetching.then(result => {
140
+ if (!isPopularItems) {
141
+ vm.totalItems = ecomSearch.getTotalCount()
142
+ }
143
+ if ($dock) {
144
+ vm.countRequests++
145
+ const renderNewItems = () => {
146
+ vm.canShowItems = true
147
+ const $searchSnap = $searchEngine.querySelector('#search-engine-snap')
148
+ const $nextSearchResults = $searchEngine.querySelector('.search-engine__results')
149
+ $nextSearchResults.style.minHeight = $searchSnap.offsetHeight + 'px'
150
+ $searchSnap.remove()
151
+ setTimeout(() => {
152
+ $nextSearchResults.style.minHeight = null
153
+ }, 600)
154
+ }
155
+ if (!vm.canShowItems) {
156
+ if (vm.countRequests > 1) {
157
+ renderNewItems()
158
+ } else if (result && result.hits) {
159
+ if (!$productItems || $productItems.length !== result.hits.hits.length) {
160
+ renderNewItems()
161
+ } else {
162
+ let isSameItems = true
163
+ const { hits } = result.hits
164
+ for (let i = 0; i < hits.length; i++) {
165
+ if (!$productItems.find(`[data-product-id="${hits[i]._id}"]`).length) {
166
+ isSameItems = false
167
+ break
168
+ }
169
+ }
170
+ if (!isSameItems) {
171
+ renderNewItems()
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ })
178
+ }
179
+ },
180
+
181
+ scopedSlots: typeof getScopedSlots === 'function'
182
+ ? getScopedSlots($searchEngine, createElement, !$dock)
183
+ : undefined
184
+ })
185
+ }
186
+ })
187
+
188
+ if ($dock) {
189
+ $($searchEngine).append($('<div>', {
190
+ id: 'search-engine-load'
191
+ }))
192
+
193
+ const mount = () => vueApp.$mount($dock)
194
+ $productItems = $('#search-engine-snap .product-item')
195
+ if ($productItems.length) {
196
+ const observer = new window.MutationObserver(() => {
197
+ clearTimeout(fallbackTimer)
198
+ observer.disconnect()
199
+ setTimeout(mount, 150)
200
+ })
201
+ observer.observe($productItems[0], {
202
+ childList: true
203
+ })
204
+ const fallbackTimer = setTimeout(() => {
205
+ observer.disconnect()
206
+ mount()
207
+ }, 3000)
208
+ } else {
209
+ mount()
210
+ }
211
+ } else {
212
+ vueApp.$mount($searchEngine)
213
+ }
51
214
  }
52
215
  }
@@ -0,0 +1 @@
1
+ module.exports = require('../../webpack.config')