@teipublisher/pb-components 3.0.9 → 3.2.0

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.
@@ -10909,6 +10909,12 @@
10909
10909
  "type": "boolean",
10910
10910
  "default": "false"
10911
10911
  },
10912
+ {
10913
+ "name": "pagination-top",
10914
+ "description": "If specified, render the pagination controls above the table instead of below.",
10915
+ "type": "boolean",
10916
+ "default": "false"
10917
+ },
10912
10918
  {
10913
10919
  "name": "per-page",
10914
10920
  "type": "number",
@@ -10918,6 +10924,11 @@
10918
10924
  "name": "height",
10919
10925
  "type": "string"
10920
10926
  },
10927
+ {
10928
+ "name": "visible-columns",
10929
+ "description": "Optional list of column ids/properties to show. If empty or undefined, all columns are visible.",
10930
+ "type": "array"
10931
+ },
10921
10932
  {
10922
10933
  "name": "subscribe",
10923
10934
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -10983,6 +10994,13 @@
10983
10994
  "type": "boolean",
10984
10995
  "default": "false"
10985
10996
  },
10997
+ {
10998
+ "name": "paginationTop",
10999
+ "attribute": "pagination-top",
11000
+ "description": "If specified, render the pagination controls above the table instead of below.",
11001
+ "type": "boolean",
11002
+ "default": "false"
11003
+ },
10986
11004
  {
10987
11005
  "name": "perPage",
10988
11006
  "attribute": "per-page",
@@ -10999,6 +11017,12 @@
10999
11017
  "type": "boolean",
11000
11018
  "default": "false"
11001
11019
  },
11020
+ {
11021
+ "name": "visibleColumns",
11022
+ "attribute": "visible-columns",
11023
+ "description": "Optional list of column ids/properties to show. If empty or undefined, all columns are visible.",
11024
+ "type": "array"
11025
+ },
11002
11026
  {
11003
11027
  "name": "subscribe",
11004
11028
  "attribute": "subscribe",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teipublisher/pb-components",
3
- "version": "3.0.9",
3
+ "version": "3.2.0",
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
@@ -10909,6 +10909,12 @@
10909
10909
  "type": "boolean",
10910
10910
  "default": "false"
10911
10911
  },
10912
+ {
10913
+ "name": "pagination-top",
10914
+ "description": "If specified, render the pagination controls above the table instead of below.",
10915
+ "type": "boolean",
10916
+ "default": "false"
10917
+ },
10912
10918
  {
10913
10919
  "name": "per-page",
10914
10920
  "type": "number",
@@ -10918,6 +10924,11 @@
10918
10924
  "name": "height",
10919
10925
  "type": "string"
10920
10926
  },
10927
+ {
10928
+ "name": "visible-columns",
10929
+ "description": "Optional list of column ids/properties to show. If empty or undefined, all columns are visible.",
10930
+ "type": "array"
10931
+ },
10921
10932
  {
10922
10933
  "name": "subscribe",
10923
10934
  "description": "The name of the channel to subscribe to. Only events on a channel corresponding\nto this property are listened to.",
@@ -10983,6 +10994,13 @@
10983
10994
  "type": "boolean",
10984
10995
  "default": "false"
10985
10996
  },
10997
+ {
10998
+ "name": "paginationTop",
10999
+ "attribute": "pagination-top",
11000
+ "description": "If specified, render the pagination controls above the table instead of below.",
11001
+ "type": "boolean",
11002
+ "default": "false"
11003
+ },
10986
11004
  {
10987
11005
  "name": "perPage",
10988
11006
  "attribute": "per-page",
@@ -10999,6 +11017,12 @@
10999
11017
  "type": "boolean",
11000
11018
  "default": "false"
11001
11019
  },
11020
+ {
11021
+ "name": "visibleColumns",
11022
+ "attribute": "visible-columns",
11023
+ "description": "Optional list of column ids/properties to show. If empty or undefined, all columns are visible.",
11024
+ "type": "array"
11025
+ },
11002
11026
  {
11003
11027
  "name": "subscribe",
11004
11028
  "attribute": "subscribe",
package/src/pb-page.js CHANGED
@@ -394,6 +394,10 @@ export class PbPage extends pbMixin(LitElement) {
394
394
  this._i18nInstance = i18next.createInstance();
395
395
  this._i18nInstance.use(LanguageDetector).use(Backend);
396
396
  this._i18nInstance.init(options).then(t => {
397
+ if (!this._i18nInstance) {
398
+ // We got deconstructed already
399
+ return;
400
+ }
397
401
  initTranslation(t);
398
402
  // initialized and ready to go!
399
403
  this._updateI18n(t);
@@ -1,6 +1,5 @@
1
1
  import { LitElement } from 'lit-element';
2
2
  import { html } from 'gridjs';
3
- import './pb-popover.js';
4
3
 
5
4
  /**
6
5
  * Defines a column within `pb-table-grid`.
@@ -1,14 +1,15 @@
1
1
  import { LitElement, html, css } from 'lit-element';
2
- import { Grid } from 'gridjs';
2
+ import { Grid, PluginPosition } from 'gridjs';
3
3
  import { pbMixin, waitOnce } from './pb-mixin.js';
4
4
  import { resolveURL } from './utils.js';
5
- import { loadStylesheets, importStyles } from './theming.js';
5
+ import { importStyles, loadStylesheets, themableMixin } from './theming.js';
6
6
  import '@polymer/paper-input/paper-input';
7
7
  import '@polymer/iron-icons';
8
8
  import '@polymer/iron-form';
9
9
  import '@polymer/paper-icon-button';
10
10
  import './pb-table-column.js';
11
11
  import { registry } from './urls.js';
12
+ import { translate } from './pb-i18n.js';
12
13
 
13
14
  /**
14
15
  * A table grid based on [gridjs](https://gridjs.io/), which loads its data from a server endpoint
@@ -39,7 +40,7 @@ import { registry } from './urls.js';
39
40
  * <pb-table-column label="Died" property="death"></pb-table-column>
40
41
  * ```
41
42
  */
42
- export class PbTableGrid extends pbMixin(LitElement) {
43
+ export class PbTableGrid extends themableMixin(pbMixin(LitElement)) {
43
44
  static get properties() {
44
45
  return {
45
46
  /**
@@ -78,6 +79,20 @@ export class PbTableGrid extends pbMixin(LitElement) {
78
79
  search: {
79
80
  type: Boolean,
80
81
  },
82
+ /**
83
+ * If specified, render the pagination controls above the table instead of below.
84
+ */
85
+ paginationTop: {
86
+ type: Boolean,
87
+ attribute: 'pagination-top',
88
+ },
89
+ /**
90
+ * Optional list of column ids/properties to show. If empty or undefined, all columns are visible.
91
+ */
92
+ visibleColumns: {
93
+ type: Array,
94
+ attribute: 'visible-columns',
95
+ },
81
96
  _params: {
82
97
  type: Object,
83
98
  },
@@ -91,13 +106,21 @@ export class PbTableGrid extends pbMixin(LitElement) {
91
106
  this._params = {};
92
107
  this.resizable = false;
93
108
  this.search = false;
109
+ this.paginationTop = false;
94
110
  this.perPage = 10;
95
111
  this.height = null;
96
112
  this.fixedHeader = false;
113
+ this.visibleColumns = null;
114
+ this._pbColumns = [];
115
+ this._columns = [];
116
+ this._selectedRow = null;
117
+ this._onTableClick = this._onTableClick.bind(this);
118
+ this._onDocumentClick = this._onDocumentClick.bind(this);
97
119
  }
98
120
 
99
121
  async connectedCallback() {
100
122
  super.connectedCallback();
123
+ document.addEventListener('click', this._onDocumentClick);
101
124
 
102
125
  this.subscribeTo('pb-search-resubmit', ev => {
103
126
  this._submit();
@@ -130,20 +153,29 @@ export class PbTableGrid extends pbMixin(LitElement) {
130
153
  }
131
154
 
132
155
  const gridjsTheme = await loadStylesheets([`${resolveURL(this.cssPath)}/mermaid.min.css`]);
133
- const theme = importStyles(this);
134
156
  const sheets = [...this.shadowRoot.adoptedStyleSheets, gridjsTheme];
157
+ // Manually import styles for backwards compatibility with pb-components < 3 importStyles
158
+ // extracts any relevant styling rules to this element and wraps them in `:host`. Which you can
159
+ // (and should) do manually anyway
160
+ const theme = importStyles(this);
135
161
  if (theme) {
136
162
  sheets.push(theme);
137
163
  }
164
+
138
165
  this.shadowRoot.adoptedStyleSheets = sheets;
139
166
  }
140
167
 
168
+ disconnectedCallback() {
169
+ document.removeEventListener('click', this._onDocumentClick);
170
+ super.disconnectedCallback();
171
+ }
172
+
141
173
  firstUpdated() {
142
174
  const table = this.shadowRoot.getElementById('table');
175
+ table.addEventListener('click', this._onTableClick);
143
176
 
144
- const pbColumns = this.querySelectorAll('pb-table-column');
145
- const columns = [];
146
- pbColumns.forEach(column => columns.push(column.data()));
177
+ this._pbColumns = Array.from(this.querySelectorAll('pb-table-column'));
178
+ this._columns = this._getColumnsConfig();
147
179
  waitOnce('pb-page-ready', data => {
148
180
  if (data && data.language) {
149
181
  this.language = data.language;
@@ -153,7 +185,7 @@ export class PbTableGrid extends pbMixin(LitElement) {
153
185
  const config = {
154
186
  height: this.height,
155
187
  fixedHeader: true,
156
- columns,
188
+ columns: this._columns,
157
189
  resizable: this.resizable,
158
190
  server: {
159
191
  url,
@@ -168,7 +200,7 @@ export class PbTableGrid extends pbMixin(LitElement) {
168
200
  if (!cols.length) return prev;
169
201
  const col = cols[0];
170
202
  return `${prev}${prev.indexOf('?') > -1 ? '&' : '?'}order=${
171
- columns[col.index].id
203
+ this._columns[col.index].id
172
204
  }&dir=${col.direction === 1 ? 'asc' : 'desc'}`;
173
205
  },
174
206
  },
@@ -206,16 +238,93 @@ export class PbTableGrid extends pbMixin(LitElement) {
206
238
  };
207
239
 
208
240
  this.grid = new Grid(config);
241
+ if (this.paginationTop) {
242
+ this.grid.plugin.get('pagination').position = PluginPosition.Header;
243
+ }
209
244
  this.grid.on('load', () => {
245
+ this._clearRowSelection();
210
246
  this.emitTo('pb-results-received', {
211
247
  params: this._params,
212
248
  });
249
+ this._applyColumnVisibilityToDom();
213
250
  });
214
251
 
215
252
  this.grid.render(table);
216
253
  });
217
254
  }
218
255
 
256
+ updated(changedProperties) {
257
+ if (changedProperties.has('visibleColumns') && this.grid) {
258
+ this._columns = this._getColumnsConfig();
259
+ this._applyColumnVisibilityToDom();
260
+ }
261
+ }
262
+
263
+ _visibleColumnsAsSet() {
264
+ return Array.isArray(this.visibleColumns) ? new Set(this.visibleColumns) : null;
265
+ }
266
+
267
+ _columnId(pbColumn, config) {
268
+ return config.id || pbColumn.property || pbColumn.label;
269
+ }
270
+
271
+ _getColumnsConfig() {
272
+ const visibleSet = this._visibleColumnsAsSet();
273
+ return this._pbColumns.map(pbColumn => {
274
+ const config = pbColumn.data();
275
+ const id = this._columnId(pbColumn, config);
276
+ return visibleSet ? { ...config, hidden: !visibleSet.has(id) } : config;
277
+ });
278
+ }
279
+
280
+ _applyColumnVisibilityToDom() {
281
+ const visibleSet = this._visibleColumnsAsSet();
282
+ const table = this.shadowRoot.querySelector('.gridjs-table');
283
+ if (!table) {
284
+ return;
285
+ }
286
+ this._columns.forEach((column, index) => {
287
+ const id = column.id || this._pbColumns[index]?.property || this._pbColumns[index]?.label;
288
+ const hidden = visibleSet ? !visibleSet.has(id) : false;
289
+ const cells = table.querySelectorAll(`th:nth-child(${index + 1}), td:nth-child(${index + 1})`);
290
+ cells.forEach(cell => {
291
+ cell.style.display = hidden ? 'none' : '';
292
+ });
293
+ });
294
+ }
295
+
296
+ _onTableClick(event) {
297
+ const row = event.target.closest('tbody tr');
298
+ if (!row) {
299
+ return;
300
+ }
301
+ this._toggleRowSelection(row);
302
+ }
303
+
304
+ _onDocumentClick(event) {
305
+ const path = event.composedPath();
306
+ if (!path.includes(this)) {
307
+ this._clearRowSelection();
308
+ }
309
+ }
310
+
311
+ _toggleRowSelection(row) {
312
+ if (this._selectedRow === row) {
313
+ this._clearRowSelection();
314
+ return;
315
+ }
316
+ this._clearRowSelection();
317
+ this._selectedRow = row;
318
+ this._selectedRow.classList.add('grid-row-selected');
319
+ }
320
+
321
+ _clearRowSelection() {
322
+ if (this._selectedRow) {
323
+ this._selectedRow.classList.remove('grid-row-selected');
324
+ this._selectedRow = null;
325
+ }
326
+ }
327
+
219
328
  _submit() {
220
329
  this.grid.forceRender();
221
330
  }
@@ -240,9 +349,9 @@ export class PbTableGrid extends pbMixin(LitElement) {
240
349
  <paper-input
241
350
  id="search"
242
351
  name="search"
243
- label="Search"
352
+ label="${translate('search.search')}"
244
353
  value="${this._params.search || ''}"
245
- @keyup="${e => (e.keyCode == 13 ? this._submit() : null)}"
354
+ @keyup="${e => (e.keyCode === 13 ? this._submit() : null)}"
246
355
  >
247
356
  <paper-icon-button
248
357
  icon="search"
@@ -263,6 +372,9 @@ export class PbTableGrid extends pbMixin(LitElement) {
263
372
  :host {
264
373
  display: block;
265
374
  }
375
+ .grid-row-selected td.gridjs-td {
376
+ background-color: var(--pb-table-grid-selected-row-background-color, #e8f0fe);
377
+ }
266
378
  button {
267
379
  border: 0;
268
380
  }