@teipublisher/pb-components 1.34.2 → 1.35.1

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.
@@ -754,6 +754,18 @@
754
754
  "type": "array",
755
755
  "default": "[]"
756
756
  },
757
+ {
758
+ "name": "preload",
759
+ "description": "If set, the entire list of possible suggestions will be preloaded upon initialization of the\ncomponent.",
760
+ "type": "boolean",
761
+ "default": "false"
762
+ },
763
+ {
764
+ "name": "substring",
765
+ "description": "By default suggestions are filtered by prefix, i.e. only suggestions starting with the prefix\ntyped by the user are shown. Set this property to true to search for the user-provided string\nanywhere within the suggestion text.",
766
+ "type": "boolean",
767
+ "default": "false"
768
+ },
757
769
  {
758
770
  "name": "subscribe",
759
771
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -828,6 +840,20 @@
828
840
  {
829
841
  "name": "lastSelected"
830
842
  },
843
+ {
844
+ "name": "preload",
845
+ "attribute": "preload",
846
+ "description": "If set, the entire list of possible suggestions will be preloaded upon initialization of the\ncomponent.",
847
+ "type": "boolean",
848
+ "default": "false"
849
+ },
850
+ {
851
+ "name": "substring",
852
+ "attribute": "substring",
853
+ "description": "By default suggestions are filtered by prefix, i.e. only suggestions starting with the prefix\ntyped by the user are shown. Set this property to true to search for the user-provided string\nanywhere within the suggestion text.",
854
+ "type": "boolean",
855
+ "default": "false"
856
+ },
831
857
  {
832
858
  "name": "subscribe",
833
859
  "attribute": "subscribe",
@@ -8258,6 +8284,11 @@
8258
8284
  "type": "string",
8259
8285
  "default": "\"search.placeholder\""
8260
8286
  },
8287
+ {
8288
+ "name": "disable-autocomplete",
8289
+ "type": "boolean",
8290
+ "default": "false"
8291
+ },
8261
8292
  {
8262
8293
  "name": "subscribe",
8263
8294
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -8330,6 +8361,12 @@
8330
8361
  "type": "string",
8331
8362
  "default": "\"search.placeholder\""
8332
8363
  },
8364
+ {
8365
+ "name": "disableAutocomplete",
8366
+ "attribute": "disable-autocomplete",
8367
+ "type": "boolean",
8368
+ "default": "false"
8369
+ },
8333
8370
  {
8334
8371
  "name": "subscribe",
8335
8372
  "attribute": "subscribe",
@@ -10548,6 +10585,10 @@
10548
10585
  {
10549
10586
  "name": "--pb-footnote-font-family",
10550
10587
  "description": "Font family for the footnote marker"
10588
+ },
10589
+ {
10590
+ "name": "--pb-view-scroll-margin-top",
10591
+ "description": "Applied to any element with an id"
10551
10592
  }
10552
10593
  ],
10553
10594
  "cssParts": [
@@ -10981,6 +11022,10 @@
10981
11022
  {
10982
11023
  "name": "--pb-footnote-font-family",
10983
11024
  "description": "Font family for the footnote marker"
11025
+ },
11026
+ {
11027
+ "name": "--pb-view-scroll-margin-top",
11028
+ "description": "Applied to any element with an id"
10984
11029
  }
10985
11030
  ],
10986
11031
  "cssParts": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teipublisher/pb-components",
3
- "version": "1.34.2",
3
+ "version": "1.35.1",
4
4
  "description": "Collection of webcomponents underlying TEI Publisher",
5
5
  "repository": "https://github.com/eeditiones/tei-publisher-components.git",
6
6
  "main": "index.html",
package/pb-elements.json CHANGED
@@ -754,6 +754,18 @@
754
754
  "type": "array",
755
755
  "default": "[]"
756
756
  },
757
+ {
758
+ "name": "preload",
759
+ "description": "If set, the entire list of possible suggestions will be preloaded upon initialization of the\ncomponent.",
760
+ "type": "boolean",
761
+ "default": "false"
762
+ },
763
+ {
764
+ "name": "substring",
765
+ "description": "By default suggestions are filtered by prefix, i.e. only suggestions starting with the prefix\ntyped by the user are shown. Set this property to true to search for the user-provided string\nanywhere within the suggestion text.",
766
+ "type": "boolean",
767
+ "default": "false"
768
+ },
757
769
  {
758
770
  "name": "subscribe",
759
771
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -828,6 +840,20 @@
828
840
  {
829
841
  "name": "lastSelected"
830
842
  },
843
+ {
844
+ "name": "preload",
845
+ "attribute": "preload",
846
+ "description": "If set, the entire list of possible suggestions will be preloaded upon initialization of the\ncomponent.",
847
+ "type": "boolean",
848
+ "default": "false"
849
+ },
850
+ {
851
+ "name": "substring",
852
+ "attribute": "substring",
853
+ "description": "By default suggestions are filtered by prefix, i.e. only suggestions starting with the prefix\ntyped by the user are shown. Set this property to true to search for the user-provided string\nanywhere within the suggestion text.",
854
+ "type": "boolean",
855
+ "default": "false"
856
+ },
831
857
  {
832
858
  "name": "subscribe",
833
859
  "attribute": "subscribe",
@@ -8258,6 +8284,11 @@
8258
8284
  "type": "string",
8259
8285
  "default": "\"search.placeholder\""
8260
8286
  },
8287
+ {
8288
+ "name": "disable-autocomplete",
8289
+ "type": "boolean",
8290
+ "default": "false"
8291
+ },
8261
8292
  {
8262
8293
  "name": "subscribe",
8263
8294
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -8330,6 +8361,12 @@
8330
8361
  "type": "string",
8331
8362
  "default": "\"search.placeholder\""
8332
8363
  },
8364
+ {
8365
+ "name": "disableAutocomplete",
8366
+ "attribute": "disable-autocomplete",
8367
+ "type": "boolean",
8368
+ "default": "false"
8369
+ },
8333
8370
  {
8334
8371
  "name": "subscribe",
8335
8372
  "attribute": "subscribe",
@@ -10548,6 +10585,10 @@
10548
10585
  {
10549
10586
  "name": "--pb-footnote-font-family",
10550
10587
  "description": "Font family for the footnote marker"
10588
+ },
10589
+ {
10590
+ "name": "--pb-view-scroll-margin-top",
10591
+ "description": "Applied to any element with an id"
10551
10592
  }
10552
10593
  ],
10553
10594
  "cssParts": [
@@ -10981,6 +11022,10 @@
10981
11022
  {
10982
11023
  "name": "--pb-footnote-font-family",
10983
11024
  "description": "Font family for the footnote marker"
11025
+ },
11026
+ {
11027
+ "name": "--pb-view-scroll-margin-top",
11028
+ "description": "Applied to any element with an id"
10984
11029
  }
10985
11030
  ],
10986
11031
  "cssParts": [
@@ -6,6 +6,31 @@ import '@polymer/iron-ajax';
6
6
  import '@polymer/iron-icon';
7
7
  import '@cwmr/paper-autocomplete/paper-autocomplete-suggestions.js';
8
8
 
9
+ function _query(datasource, query) {
10
+ const queryResult = [];
11
+ datasource.forEach((item) => {
12
+ let objText, objValue;
13
+
14
+ if (typeof item === 'object') {
15
+ objText = item.text;
16
+ objValue = item.value;
17
+ } else {
18
+ objText = item.toString();
19
+ objValue = objText;
20
+ }
21
+
22
+ if (objText.toLowerCase().indexOf(query) > -1) {
23
+ // NOTE: the structure of the result object matches with the current template. For custom templates, you
24
+ // might need to return more data
25
+ const resultItem = {};
26
+ resultItem.text = objText;
27
+ resultItem.value = objValue;
28
+ queryResult.push(resultItem);
29
+ }
30
+ });
31
+ return queryResult;
32
+ }
33
+
9
34
  /**
10
35
  * Provides an input with attached autocomplete. The autocomplete suggestions can be read
11
36
  * either from a static list or a remote endpoint to which the current user input is sent.
@@ -52,6 +77,13 @@ export class PbAutocomplete extends pbMixin(LitElement) {
52
77
  source: {
53
78
  type: String
54
79
  },
80
+ /**
81
+ * If set, the entire list of possible suggestions will be preloaded upon initialization of the
82
+ * component.
83
+ */
84
+ preload: {
85
+ type: Boolean
86
+ },
55
87
  /**
56
88
  * A static list of suggestions. Use instead of `source`. May either be a flat array of strings,
57
89
  * or an array containing objects of the form `{"text": "", "value": ""}, in which case "value" denotes
@@ -60,6 +92,14 @@ export class PbAutocomplete extends pbMixin(LitElement) {
60
92
  suggestions: {
61
93
  type: Array
62
94
  },
95
+ /**
96
+ * By default suggestions are filtered by prefix, i.e. only suggestions starting with the prefix
97
+ * typed by the user are shown. Set this property to true to search for the user-provided string
98
+ * anywhere within the suggestion text.
99
+ */
100
+ substring: {
101
+ type: Boolean
102
+ },
63
103
  /**
64
104
  * An icon to display next to the input.
65
105
  */
@@ -74,6 +114,8 @@ export class PbAutocomplete extends pbMixin(LitElement) {
74
114
  this.placeholder = 'search.placeholder';
75
115
  this.suggestions = [];
76
116
  this.lastSelected = null;
117
+ this.preload = false;
118
+ this.substring = false;
77
119
  this._hiddenInput = null;
78
120
  this._initialized = false;
79
121
  }
@@ -94,7 +136,14 @@ export class PbAutocomplete extends pbMixin(LitElement) {
94
136
  const autocomplete = this.shadowRoot.getElementById('autocomplete');
95
137
  autocomplete.addEventListener('autocomplete-change', this._autocomplete.bind(this));
96
138
 
97
- if (this.value) {
139
+ if (this.preload && this.source) {
140
+ if (this.substring) {
141
+ autocomplete.queryFn = _query;
142
+ }
143
+ PbAutocomplete.waitOnce('pb-page-ready', () => {
144
+ this._sendRequest();
145
+ });
146
+ } else if (this.value) {
98
147
  if (this.source) {
99
148
  PbAutocomplete.waitOnce('pb-page-ready', () => {
100
149
  //console.log('send autocomplete request for remote source %s on value %s', this.source, this.value);
@@ -140,7 +189,7 @@ export class PbAutocomplete extends pbMixin(LitElement) {
140
189
  always-float-label>
141
190
  ${this.icon ? html`<iron-icon icon="${this.icon}" slot="prefix"></iron-icon>` : null}
142
191
  </paper-input>
143
- <paper-autocomplete-suggestions id="autocomplete" for="search" .source="${this.suggestions}" ?remote-source="${this.source}"
192
+ <paper-autocomplete-suggestions id="autocomplete" for="search" .source="${this.suggestions}" ?remote-source="${!this.preload && this.source}"
144
193
  @autocomplete-selected="${this._autocompleteSelected}"></paper-autocomplete-suggestions>
145
194
 
146
195
  <iron-ajax
@@ -179,7 +228,6 @@ export class PbAutocomplete extends pbMixin(LitElement) {
179
228
  this._sendRequest(search.value);
180
229
  }
181
230
 
182
-
183
231
  _sendRequest(query) {
184
232
  const loader = this.shadowRoot.getElementById('autocompleteLoader');
185
233
  loader.url = this.toAbsoluteURL(this.source);
@@ -195,35 +243,33 @@ export class PbAutocomplete extends pbMixin(LitElement) {
195
243
 
196
244
  _updateSuggestions() {
197
245
  const loader = this.shadowRoot.getElementById('autocompleteLoader');
198
-
199
246
  if (this._initialized) {
200
247
  const autocomplete = this.shadowRoot.getElementById('autocomplete');
201
248
  if (loader.lastResponse) {
202
249
  this.suggestions = loader.lastResponse;
203
250
  autocomplete.suggestions(this.suggestions);
204
251
  }
205
- } else {
206
- if (loader.lastResponse) {
207
- let suggestions = loader.lastResponse;
208
- //console.log('suggestions received', suggestions);
252
+ } else if (loader.lastResponse) {
253
+ const suggestions = loader.lastResponse;
209
254
 
210
- const input = this.shadowRoot.getElementById('search');
211
- const value = suggestions.find((suggestion) => {
212
- if (suggestion.text) {
213
- return suggestion.value === this.value;
214
- }
215
- return suggestion === this.value;
216
- });
217
- if (value) {
218
- input.value = value.text || value;
219
- if (this._hiddenInput) {
220
- this._hiddenInput.value = value.value || value;
221
- }
222
- } else {
223
- if (this._hiddenInput) {
224
- this._hiddenInput.value = this.value;
225
- }
255
+ const input = this.shadowRoot.getElementById('search');
256
+ const value = suggestions.find((suggestion) => {
257
+ if (suggestion.text) {
258
+ return suggestion.value === this.value;
226
259
  }
260
+ return suggestion === this.value;
261
+ });
262
+ if (value) {
263
+ input.value = value.text || value;
264
+ if (this._hiddenInput) {
265
+ this._hiddenInput.value = value.value || value;
266
+ }
267
+ } else if (this._hiddenInput) {
268
+ this._hiddenInput.value = this.value;
269
+ }
270
+
271
+ if (this.preload) {
272
+ this.suggestions = suggestions;
227
273
  }
228
274
  }
229
275
  this._initialized = true;
@@ -242,22 +288,48 @@ export class PbAutocomplete extends pbMixin(LitElement) {
242
288
  _autocompleteSelected(ev) {
243
289
  this.lastSelected = ev.detail.text;
244
290
  const input = this.shadowRoot.getElementById('search');
245
- console.log('autocomplete selected %s', ev.detail.text);
246
291
  input.value = ev.detail.text;
247
292
  this.value = ev.detail.value;
248
293
  if (this._hiddenInput) {
249
294
  this._hiddenInput.value = this.value;
250
295
  }
296
+
297
+ this.emitTo('pb-autocomplete-selected', {
298
+ text: ev.detail.text,
299
+ value: ev.detail.value
300
+ });
251
301
  }
252
302
 
253
303
  _setInput(ev) {
254
304
  const input = this.shadowRoot.getElementById('search');
255
- console.log('Autocomplete set manually to %s', input.value);
256
-
257
305
  this.value = input.value;
306
+
258
307
  if (this._hiddenInput) {
259
308
  this._hiddenInput.value = this.value;
260
309
  }
310
+
311
+ if (ev.keyCode === 13) {
312
+ const entry = this.suggestions.find((suggestion) => {
313
+ if (suggestion.text) {
314
+ return suggestion.value === this.value;
315
+ }
316
+ return suggestion === this.value;
317
+ });
318
+ if (!entry) {
319
+ return;
320
+ }
321
+ if (entry.value) {
322
+ this.emitTo('pb-autocomplete-selected', {
323
+ text: entry.text,
324
+ value: entry.value
325
+ });
326
+ } else {
327
+ this.emitTo('pb-autocomplete-selected', {
328
+ text: entry,
329
+ value: entry
330
+ });
331
+ }
332
+ }
261
333
  }
262
334
 
263
335
 
package/src/pb-search.js CHANGED
@@ -51,6 +51,10 @@ export class PbSearch extends pbMixin(LitElement) {
51
51
  },
52
52
  subforms: {
53
53
  type: String
54
+ },
55
+ disableAutocomplete: {
56
+ type: Boolean,
57
+ attribute: 'disable-autocomplete'
54
58
  }
55
59
  };
56
60
  }
@@ -61,6 +65,7 @@ export class PbSearch extends pbMixin(LitElement) {
61
65
  this.redirect = false;
62
66
  this.submitOnLoad = false;
63
67
  this.placeHolder = 'search.placeholder';
68
+ this.disableAutocomplete = false;
64
69
  }
65
70
 
66
71
  connectedCallback() {
@@ -70,8 +75,10 @@ export class PbSearch extends pbMixin(LitElement) {
70
75
  }
71
76
 
72
77
  firstUpdated() {
73
- const autocomplete = this.shadowRoot.getElementById('autocomplete');
74
- autocomplete.addEventListener('autocomplete-change', this._autocomplete.bind(this));
78
+ if (!this.disableAutocomplete) {
79
+ const autocomplete = this.shadowRoot.getElementById('autocomplete');
80
+ autocomplete.addEventListener('autocomplete-change', this._autocomplete.bind(this));
81
+ }
75
82
  const ironform = this.shadowRoot.getElementById('ironform');
76
83
  ironform.addEventListener('iron-form-response', (event) =>
77
84
  event.detail.completes.then((r) => this.emitTo('pb-search', r.parseResponse()))
package/src/pb-view.js CHANGED
@@ -45,6 +45,7 @@ import '@polymer/paper-dialog-scrollable';
45
45
  * @cssprop --pb-footnote-padding - Padding around a footnote marker
46
46
  * @cssprop --pb-footnote-font-size - Font size for the footnote marker
47
47
  * @cssprop --pb-footnote-font-family - Font family for the footnote marker
48
+ * @cssprop --pb-view-scroll-margin-top - Applied to any element with an id
48
49
  * @csspart content - The root div around the displayed content
49
50
  * @csspart footnotes - div containing the footnotes
50
51
 
@@ -524,7 +525,7 @@ export class PbView extends pbMixin(LitElement) {
524
525
  this._scrollTarget = ev.detail.hash;
525
526
  const target = this.shadowRoot.getElementById(this._scrollTarget);
526
527
  if (target) {
527
- setTimeout(() => target.scrollIntoView());
528
+ setTimeout(() => target.scrollIntoView({block: 'nearest'}));
528
529
  }
529
530
  return;
530
531
  }
@@ -540,6 +541,10 @@ export class PbView extends pbMixin(LitElement) {
540
541
  this.columnSeparator = ev.detail.columnSeparator;
541
542
  }
542
543
  this.view = ev.detail.view || this.view;
544
+ if (ev.detail.xpath) {
545
+ this.xpath = ev.detail.xpath;
546
+ this.nodeId = null;
547
+ }
543
548
  // clear nodeId if set to null
544
549
  if (ev.detail.position === null) {
545
550
  this.nodeId = null;
@@ -595,7 +600,7 @@ export class PbView extends pbMixin(LitElement) {
595
600
 
596
601
  const loadContent = this.shadowRoot.getElementById('loadContent');
597
602
 
598
- if (this.static) {
603
+ if (this.static !== null) {
599
604
  this._staticUrl(params).then((url) => {
600
605
  loadContent.url = url;
601
606
  loadContent.generateRequest();
@@ -707,9 +712,11 @@ export class PbView extends pbMixin(LitElement) {
707
712
  const target = this.shadowRoot.getElementById(this._scrollTarget) ||
708
713
  this.shadowRoot.querySelector(`[node-id="${this._scrollTarget}"]`);
709
714
  if (target) {
710
- setTimeout(() => {
711
- target.scrollIntoView();
712
- }, 100);
715
+ window.requestAnimationFrame(() =>
716
+ setTimeout(() => {
717
+ target.scrollIntoView({block: 'nearest'});
718
+ }, 400)
719
+ );
713
720
  }
714
721
  this._scrollTarget = null;
715
722
  });
@@ -885,7 +892,7 @@ export class PbView extends pbMixin(LitElement) {
885
892
  let link = document.createElement('link');
886
893
  link.setAttribute('rel', 'stylesheet');
887
894
  link.setAttribute('type', 'text/css');
888
- if (this.static) {
895
+ if (this.static !== null) {
889
896
  link.setAttribute('href', `${this.static}/css/${this.getOdd()}.css`);
890
897
  } else {
891
898
  link.setAttribute('href', `${this.getEndpoint()}/transform/${this.getOdd()}.css`);
@@ -1206,6 +1213,10 @@ export class PbView extends pbMixin(LitElement) {
1206
1213
  display: none;
1207
1214
  }
1208
1215
 
1216
+ [id] {
1217
+ scroll-margin-top: var(--pb-view-scroll-margin-top);
1218
+ }
1219
+
1209
1220
  #view {
1210
1221
  position: relative;
1211
1222
  }