@teipublisher/pb-components 2.26.0-next-3.5 → 2.26.0-next-3.7

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/src/pb-search.js CHANGED
@@ -2,13 +2,8 @@ import { LitElement, html, css } from 'lit-element';
2
2
  import { pbMixin, waitOnce } from './pb-mixin.js';
3
3
  import { registry } from "./urls.js";
4
4
  import { translate } from "./pb-i18n.js";
5
- import '@polymer/paper-input/paper-input.js';
6
- import '@polymer/paper-checkbox';
7
5
  import '@polymer/iron-ajax';
8
- import '@polymer/iron-form';
9
- import '@polymer/paper-button';
10
- import '@polymer/iron-icon';
11
- import '@cwmr/paper-autocomplete';
6
+ import {themableMixin} from "./theming.js";
12
7
 
13
8
  /**
14
9
  * Implements a basic search form, which can be extended with additional inputs.
@@ -26,7 +21,7 @@ import '@cwmr/paper-autocomplete';
26
21
  * @fires pb-paginate - When received, triggers the search again with the new value of the start property
27
22
  * @fires pb-search-resubmit - When received, triggers the search again
28
23
  */
29
- export class PbSearch extends pbMixin(LitElement) {
24
+ export class PbSearch extends themableMixin(pbMixin(LitElement)) {
30
25
  static get properties() {
31
26
  return {
32
27
  ...super.properties,
@@ -67,7 +62,7 @@ export class PbSearch extends pbMixin(LitElement) {
67
62
  /**
68
63
  * Optional URL to query for suggestions. If relative, it is interpreted
69
64
  * relative to the endpoint defined on a surrounding `pb-page`.
70
- *
65
+ *
71
66
  * Upon autocomplete, the current input by the user will be sent with a query parameter
72
67
  * `query`. The name/values of form controls nested within `pb-search` or subforms will also be
73
68
  * appended to the request as parameters. This allows the server side code to distinguish
@@ -112,14 +107,6 @@ export class PbSearch extends pbMixin(LitElement) {
112
107
  }
113
108
 
114
109
  firstUpdated() {
115
- if (!this.disableAutocomplete) {
116
- const autocomplete = this.shadowRoot.getElementById('autocomplete');
117
- autocomplete.addEventListener('autocomplete-change', this._autocomplete.bind(this));
118
- }
119
- const ironform = this.shadowRoot.getElementById('ironform');
120
- ironform.addEventListener('iron-form-response', (event) =>
121
- event.detail.completes.then((r) => this.emitTo('pb-search', r.parseResponse()))
122
- );
123
110
  waitOnce('pb-page-ready', (options) => {
124
111
  const loader = this.shadowRoot.getElementById('autocompleteLoader');
125
112
  const url = this.source || "api/search/autocomplete";
@@ -152,36 +139,28 @@ export class PbSearch extends pbMixin(LitElement) {
152
139
  }
153
140
  });
154
141
  }
155
-
142
+
156
143
  render() {
157
144
  return html`
158
- <custom-style>
159
- <style>
160
- :host {
161
- --suggestions-item: {
162
- color: var(--pb-search-suggestions-color, black);
163
- };
164
- --suggestions-wrapper: {
165
- background: var(--pb-search-suggestions-background, white);
166
- }
167
- }
168
- </style>
169
- </custom-style>
170
- <iron-form id="ironform" allow-redirect="${this.redirect}">
171
- <form id="searchPageForm" method="get" action="${this.action}" accept="text/html">
172
- <slot name="beforeInput"></slot>
173
- <paper-input id="search" type="search" name="query" @keyup="${this._handleEnter}" label="${translate(this.placeHolder)}"
174
- value="${this.value}" always-float-label>
175
- <iron-icon icon="search" @click="${this._doSearch}" slot="prefix"></iron-icon>
176
- </paper-input>
177
- <paper-autocomplete-suggestions id="autocomplete" for="search" source="${this._suggestions}" remote-source></paper-autocomplete-suggestions>
178
- <slot></slot>
179
-
180
- <slot name="searchButton"></slot>
145
+ <form id="searchPageForm" method="get" action="${this.action}" accept="text/html" @submit="${this._handleSubmit}">
146
+ <slot name="beforeInput"></slot>
147
+ <div class="input-wrapper">
148
+ <input
149
+ id="search"
150
+ name="query"
151
+ type="search"
152
+ placeholder="${translate(this.placeHolder)}"
153
+ .value="${this.value}"
154
+ @keyup="${this._handleEnter}"
155
+ list="suggestions"
156
+ part="input"
157
+ />
158
+ <datalist id="suggestions"></datalist>
159
+ <slot name="searchButton" part="search-button"></slot>
181
160
  <slot name="resetButton"></slot>
182
-
183
- </form>
184
- </iron-form>
161
+ </div>
162
+ <slot></slot>
163
+ </form>
185
164
  <iron-ajax
186
165
  id="autocompleteLoader"
187
166
  verbose
@@ -195,32 +174,54 @@ export class PbSearch extends pbMixin(LitElement) {
195
174
  static get styles() {
196
175
  return css`
197
176
  :host {
198
- --paper-input-container-color: var(--pb-search-label-color, var(--paper-grey-500, #303030));
199
- --paper-input-container-input-color: var(--pb-search-input-color, var(--pb-color-primary, #000000));
200
- --paper-input-container-focus-color: var(--pb-search-focus-color, var(--paper-grey-500, #303030));
177
+ display: inline-block;
201
178
  }
202
- a{
203
- padding:1rem;
204
- color:var(--pb-reset-color);
179
+ .input-wrapper {
180
+ display: flex;
181
+ align-items: center;
205
182
  }
206
- .buttons{
207
- margin-top:1rem;
208
- }
209
- form {
210
- margin: 0;
183
+ #search {
184
+ flex: 2;
211
185
  }
212
186
  `;
213
187
  }
214
188
 
189
+ _serializeForm() {
190
+ const form = this.shadowRoot.getElementById('searchPageForm');
191
+ const formData = new FormData(form);
192
+ const json = {};
193
+ // @ts-ignore - FormData.entries() is supported in modern browsers
194
+ for (let [key, value] of formData.entries()) {
195
+ json[key] = value;
196
+ }
197
+
198
+ // Also collect form controls from slots
199
+ const formControls = this.querySelectorAll('input, select, textarea');
200
+ formControls.forEach(control => {
201
+ if (control.name && control.type !== 'button' && control.type !== 'submit' && control.type !== 'reset') {
202
+ if (control.type === 'checkbox' || control.type === 'radio') {
203
+ if (control.checked) {
204
+ json[control.name] = control.value;
205
+ }
206
+ } else {
207
+ json[control.name] = control.value;
208
+ }
209
+ }
210
+ });
211
+
212
+ return json;
213
+ }
214
+
215
215
  _doSearch(pagination = false) {
216
- let json = this.shadowRoot.getElementById('ironform').serializeForm();
216
+ let json = this._serializeForm();
217
217
  json = this._paramsFromSubforms(json);
218
- // remove unnecessary param added by autocomplete
219
- delete json['autocomplete-custom-template'];
220
- // always start on first result after submitting new search
221
218
  json.start = pagination ? this.start : 1;
222
219
  if (this.redirect) {
223
- window.location.href = `${this.action}?${new URLSearchParams(json)}`;
220
+ const params = new URLSearchParams();
221
+ Object.keys(json).forEach(key => {
222
+ params.append(key, json[key]);
223
+ });
224
+ window.location.href = `${this.action}?${params}`;
224
225
  } else {
225
226
  registry.commit(this, json);
226
227
  this.emitTo('pb-load', {
@@ -230,6 +231,11 @@ export class PbSearch extends pbMixin(LitElement) {
230
231
  }
231
232
  }
232
233
 
234
+ _handleSubmit(e) {
235
+ e.preventDefault();
236
+ this._doSearch();
237
+ }
238
+
233
239
  _paramsFromSubforms(params) {
234
240
  if (this.subforms) {
235
241
  document.querySelectorAll(this.subforms).forEach((form) => {
@@ -243,32 +249,43 @@ export class PbSearch extends pbMixin(LitElement) {
243
249
 
244
250
  _handleEnter(e) {
245
251
  if (e.keyCode === 13) {
246
- this._doSearch();
252
+ return this._doSearch();
253
+ }
254
+ const value = this.shadowRoot.getElementById('search').value;
255
+ if (value.length > 2) {
256
+ const loader = this.shadowRoot.getElementById('autocompleteLoader');
257
+ loader.params = {
258
+ query: value
259
+ };
260
+ loader.generateRequest();
247
261
  }
248
262
  }
249
263
 
250
264
  _doSubmit() {
251
- this.shadowRoot.getElementById('ironform').submit();
265
+ this._doSearch();
252
266
  }
253
267
 
254
- _reset(){
255
- this.shadowRoot.getElementById('ironform').reset();
256
- }
257
-
258
- _autocomplete(ev) {
259
- const params = this.shadowRoot.getElementById('ironform').serializeForm();
260
- const loader = this.shadowRoot.getElementById('autocompleteLoader');
261
- loader.params = params;
262
- loader.generateRequest();
268
+ _reset() {
269
+ const form = this.shadowRoot.getElementById('searchPageForm');
270
+ form.reset();
271
+ registry.commit(this, {}, true);
263
272
  }
264
273
 
265
274
  _updateSuggestions() {
266
- const autocomplete = this.shadowRoot.getElementById('autocomplete');
267
275
  const loader = this.shadowRoot.getElementById('autocompleteLoader');
276
+ const datalist = this.shadowRoot.getElementById('suggestions');
268
277
  if (loader.lastResponse) {
269
- autocomplete.suggestions(loader.lastResponse);
278
+ datalist.innerHTML = '';
279
+ loader.lastResponse.forEach(({text, value}) => {
280
+ const option = document.createElement('option');
281
+ option.value = value;
282
+ option.innerText = text;
283
+ datalist.appendChild(option);
284
+ });
270
285
  }
271
286
  }
272
-
273
287
  }
274
- customElements.define('pb-search', PbSearch);
288
+ if (!customElements.get('pb-search')) {
289
+ customElements.define('pb-search', PbSearch);
290
+ }
291
+