@teipublisher/pb-components 1.42.7 → 1.43.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.
- package/CHANGELOG.md +7 -0
- package/dist/demo/components.css +12 -0
- package/dist/demo/pb-code-highlight.html +63 -63
- package/dist/demo/pb-table-grid.html +16 -16
- package/dist/pb-code-editor.js +1 -1
- package/dist/pb-component-docs.js +12 -12
- package/dist/pb-components-bundle.js +169 -170
- package/dist/pb-edit-app.js +1 -1
- package/dist/pb-elements.json +610 -597
- package/dist/{pb-i18n-6ad23bcf.js → pb-i18n-dc551878.js} +1 -1
- package/dist/pb-leaflet-map.js +1 -1
- package/dist/{pb-message-0fb0b538.js → pb-message-c4cd7861.js} +1 -1
- package/dist/{pb-mixin-15ff531f.js → pb-mixin-f8b22e51.js} +1 -1
- package/dist/pb-odd-editor.js +1 -1
- package/package.json +1 -1
- package/pb-elements.json +610 -597
- package/src/pb-code-highlight.js +194 -193
- package/src/pb-mixin.js +542 -529
- package/src/pb-page.js +396 -384
- package/src/pb-split-list.js +2 -1
- package/src/pb-table-grid.js +218 -211
- package/src/theming.js +115 -0
- package/src/utils.js +50 -51
package/src/pb-split-list.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LitElement, html, css } from 'lit-element';
|
|
2
2
|
import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
|
|
3
3
|
import { pbMixin } from './pb-mixin.js';
|
|
4
|
+
import { themableMixin } from "./theming.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Implements a list which is split into different categories
|
|
@@ -23,7 +24,7 @@ import { pbMixin } from './pb-mixin.js';
|
|
|
23
24
|
* @fires pb-start-update - sent before the element sends the request to the server
|
|
24
25
|
* @fires pb-end-update - sent after new content has been received
|
|
25
26
|
*/
|
|
26
|
-
export class PbSplitList extends pbMixin(LitElement) {
|
|
27
|
+
export class PbSplitList extends themableMixin(pbMixin(LitElement)) {
|
|
27
28
|
static get properties() {
|
|
28
29
|
return {
|
|
29
30
|
/**
|
package/src/pb-table-grid.js
CHANGED
|
@@ -1,212 +1,219 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit-element';
|
|
2
|
-
import { Grid } from "gridjs";
|
|
3
|
-
import { pbMixin } from './pb-mixin.js';
|
|
4
|
-
import { resolveURL } from './utils.js';
|
|
5
|
-
import
|
|
6
|
-
import '@polymer/
|
|
7
|
-
import '@polymer/iron-
|
|
8
|
-
import '@polymer/
|
|
9
|
-
import '
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* * `
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* <pb-table-column label="
|
|
37
|
-
* <pb-table-column label="
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
90
|
-
this.
|
|
91
|
-
this.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
1
|
+
import { LitElement, html, css } from 'lit-element';
|
|
2
|
+
import { Grid } from "gridjs";
|
|
3
|
+
import { pbMixin } from './pb-mixin.js';
|
|
4
|
+
import { resolveURL } from './utils.js';
|
|
5
|
+
import { loadStylesheet, importStyles } from "./theming.js";
|
|
6
|
+
import '@polymer/paper-input/paper-input';
|
|
7
|
+
import '@polymer/iron-icons';
|
|
8
|
+
import '@polymer/iron-form';
|
|
9
|
+
import '@polymer/paper-icon-button';
|
|
10
|
+
import './pb-table-column.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A table grid based on [gridjs](https://gridjs.io/), which loads its data from a server endpoint
|
|
14
|
+
* specified in `source`. If `source` is a relative URI, it will be resolved relative to the
|
|
15
|
+
* TEI Publisher endpoint.
|
|
16
|
+
*
|
|
17
|
+
* The JSON data returned by the endpoint should be an object with two properties:
|
|
18
|
+
*
|
|
19
|
+
* * `count`: the overall number of rows available on the server
|
|
20
|
+
* * `results`: an array containing each record as an object
|
|
21
|
+
*
|
|
22
|
+
* The parameters send to the server are as follows:
|
|
23
|
+
*
|
|
24
|
+
*
|
|
25
|
+
* Parameter | Description
|
|
26
|
+
* ---------|----------
|
|
27
|
+
* limit | number of records to return for each page
|
|
28
|
+
* start | start offset from which to return records
|
|
29
|
+
* order | the id of the column to sort by
|
|
30
|
+
* dir | sort direction: either 'asc' or 'desc'
|
|
31
|
+
* search | an optional search string entered by the user
|
|
32
|
+
*
|
|
33
|
+
* Table columns are configured via nested `<pb-table-column>` elements:
|
|
34
|
+
*
|
|
35
|
+
* ```html
|
|
36
|
+
* <pb-table-column label="Name" property="name" sort width="33%"></pb-table-column>
|
|
37
|
+
* <pb-table-column label="Born" property="birth"></pb-table-column>
|
|
38
|
+
* <pb-table-column label="Died" property="death"></pb-table-column>
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class PbTableGrid extends pbMixin(LitElement) {
|
|
42
|
+
static get properties() {
|
|
43
|
+
return {
|
|
44
|
+
/**
|
|
45
|
+
* URI of the server-side endpoint to retrieve data from.
|
|
46
|
+
* Relative URIs are resolved relative to the configured TEI Publisher endpoint.
|
|
47
|
+
*/
|
|
48
|
+
source: {
|
|
49
|
+
type: String
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* Path to the gridjs theme CSS files.
|
|
53
|
+
*/
|
|
54
|
+
cssPath: {
|
|
55
|
+
type: String,
|
|
56
|
+
attribute: 'css-path'
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* If specified, columns (without a fixed width) will be resizable.
|
|
60
|
+
*/
|
|
61
|
+
resizable: {
|
|
62
|
+
type: Boolean
|
|
63
|
+
},
|
|
64
|
+
perPage: {
|
|
65
|
+
type: Number,
|
|
66
|
+
attribute: 'per-page'
|
|
67
|
+
},
|
|
68
|
+
height: {
|
|
69
|
+
type: String
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* If specified, enable server-side search.
|
|
73
|
+
*/
|
|
74
|
+
search: {
|
|
75
|
+
type: Boolean
|
|
76
|
+
},
|
|
77
|
+
_params: {
|
|
78
|
+
type: Object
|
|
79
|
+
},
|
|
80
|
+
...super.properties
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
constructor() {
|
|
85
|
+
super();
|
|
86
|
+
this.cssPath = '../css/gridjs';
|
|
87
|
+
this._params = {};
|
|
88
|
+
this.resizable = false;
|
|
89
|
+
this.search = false;
|
|
90
|
+
this.perPage = 10;
|
|
91
|
+
this.height = null;
|
|
92
|
+
this.fixedHeader = false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async connectedCallback() {
|
|
96
|
+
super.connectedCallback();
|
|
97
|
+
|
|
98
|
+
this.subscribeTo('pb-search-resubmit', (ev) => {
|
|
99
|
+
this._params = Object.assign({}, ev.detail.params);
|
|
100
|
+
this._submit();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
window.addEventListener('popstate', (ev) => {
|
|
104
|
+
this._params = ev.state;
|
|
105
|
+
this._submit();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!this.height) {
|
|
109
|
+
const property = getComputedStyle(this).getPropertyValue('--pb-table-grid-height');
|
|
110
|
+
if (property) {
|
|
111
|
+
this.height = property;
|
|
112
|
+
} else {
|
|
113
|
+
this.height = 'auto';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const gridjsTheme = await loadStylesheet(`${resolveURL(this.cssPath)}/mermaid.min.css`);
|
|
118
|
+
const theme = importStyles(this);
|
|
119
|
+
const sheets = [...this.shadowRoot.adoptedStyleSheets, gridjsTheme];
|
|
120
|
+
if (theme) {
|
|
121
|
+
sheets.push(theme);
|
|
122
|
+
}
|
|
123
|
+
this.shadowRoot.adoptedStyleSheets = sheets;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
firstUpdated() {
|
|
127
|
+
const table = this.shadowRoot.getElementById('table');
|
|
128
|
+
|
|
129
|
+
const pbColumns = this.querySelectorAll('pb-table-column');
|
|
130
|
+
const columns = [];
|
|
131
|
+
pbColumns.forEach((column) => columns.push(column.data()));
|
|
132
|
+
PbTableGrid.waitOnce('pb-page-ready', () => {
|
|
133
|
+
this._params = this.getParameters();
|
|
134
|
+
const url = this.toAbsoluteURL(this.source);
|
|
135
|
+
const config = {
|
|
136
|
+
height: this.height,
|
|
137
|
+
fixedHeader: true,
|
|
138
|
+
columns,
|
|
139
|
+
resizable: this.resizable,
|
|
140
|
+
server: {
|
|
141
|
+
url,
|
|
142
|
+
then: data => data.results,
|
|
143
|
+
total: data => data.count
|
|
144
|
+
},
|
|
145
|
+
sort: {
|
|
146
|
+
multiColumn: false,
|
|
147
|
+
enabled: true,
|
|
148
|
+
server: {
|
|
149
|
+
url: (prev, cols) => {
|
|
150
|
+
if (!cols.length) return prev;
|
|
151
|
+
const col = cols[0];
|
|
152
|
+
return `${prev}${prev.indexOf('?') > -1 ? '&' : '?'}order=${columns[col.index].id}&dir=${col.direction === 1 ? 'asc' : 'desc'}`;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
pagination: {
|
|
157
|
+
enabled: true,
|
|
158
|
+
limit: this.perPage,
|
|
159
|
+
server: {
|
|
160
|
+
url: (prev, page, limit) => {
|
|
161
|
+
const form = this.shadowRoot.getElementById('form');
|
|
162
|
+
if (form) {
|
|
163
|
+
Object.assign(this._params, form.serializeForm());
|
|
164
|
+
}
|
|
165
|
+
this._params.limit = limit;
|
|
166
|
+
this._params.start = page * limit + 1;
|
|
167
|
+
this.setParameters(this._params);
|
|
168
|
+
this.pushHistory('grid', this._params);
|
|
169
|
+
|
|
170
|
+
return `${prev}${prev.indexOf('?') > -1 ? '&' : '?'}${new URLSearchParams(this._params).toString()}`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
this.grid = new Grid(config);
|
|
177
|
+
this.grid.on('load', () => {
|
|
178
|
+
this.emitTo('pb-results-received', {
|
|
179
|
+
"params": this._params
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
this.grid.render(table);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_submit() {
|
|
188
|
+
this.grid.forceRender();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
render() {
|
|
192
|
+
return html`
|
|
193
|
+
${
|
|
194
|
+
this.search ? html`
|
|
195
|
+
<iron-form id="form">
|
|
196
|
+
<form action="">
|
|
197
|
+
<paper-input id="search" name="search" label="Search" @keyup="${(e) => e.keyCode == 13 ? this._submit() : null}">
|
|
198
|
+
<paper-icon-button icon="search" @click="${this._submit}" slot="suffix"></paper-icon-button>
|
|
199
|
+
</paper-input>
|
|
200
|
+
</form>
|
|
201
|
+
</iron-form>
|
|
202
|
+
` : null
|
|
203
|
+
}
|
|
204
|
+
<div id="table"></div>
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static get styles() {
|
|
209
|
+
return css`
|
|
210
|
+
:host {
|
|
211
|
+
display: block;
|
|
212
|
+
}
|
|
213
|
+
button {
|
|
214
|
+
border: 0;
|
|
215
|
+
}
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
212
219
|
customElements.define('pb-table-grid', PbTableGrid);
|
package/src/theming.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { waitOnce } from "./pb-mixin.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Maps theme selector to CSSStyleSheet or null.
|
|
5
|
+
*
|
|
6
|
+
* @type {Map<string,(CSSStyleSheet|null)>}
|
|
7
|
+
*/
|
|
8
|
+
const themeMap = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Load a CSS stylesheet from the given URL and return
|
|
12
|
+
* a CSSStyleSheet. The returned stylesheet can be assigned
|
|
13
|
+
* to `adoptedStyleSheets`.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} url absolute URL
|
|
16
|
+
* @returns {Promise<CSSStyleSheet|null>} constructed CSSStyleSheet or null
|
|
17
|
+
*/
|
|
18
|
+
export function loadStylesheet(url) {
|
|
19
|
+
return fetch(url)
|
|
20
|
+
.then(response => {
|
|
21
|
+
if (response.ok) {
|
|
22
|
+
return response.text();
|
|
23
|
+
}
|
|
24
|
+
console.warn('<theming> Component stylesheet not found: %s', url);
|
|
25
|
+
return null;
|
|
26
|
+
})
|
|
27
|
+
.then(text => {
|
|
28
|
+
if (text) {
|
|
29
|
+
const stylesheet = new CSSStyleSheet();
|
|
30
|
+
return stylesheet.replace(text);
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
})
|
|
34
|
+
.catch(error => {
|
|
35
|
+
console.error('<theming> Error loading stylesheet %s: %o', url, error);
|
|
36
|
+
return null;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* From the global component theme, import all rules which would apply to the
|
|
42
|
+
* given element into a new CSSStyleSheet and return it.
|
|
43
|
+
*
|
|
44
|
+
* @param {HTMLElement} elem a web component or HTML element
|
|
45
|
+
* @returns {CSSStyleSheet|null} a new CSSStylesheet or null
|
|
46
|
+
*/
|
|
47
|
+
export function importStyles(elem) {
|
|
48
|
+
const page = document.querySelector('pb-page');
|
|
49
|
+
if (!page) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const theme = page.stylesheet;
|
|
53
|
+
if (!theme) {
|
|
54
|
+
// no component styles defined
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const selectors = getSelectors(elem).join('|');
|
|
59
|
+
if (themeMap.has(selectors)) {
|
|
60
|
+
return themeMap.get(selectors);
|
|
61
|
+
}
|
|
62
|
+
const prefixRegex = new RegExp(`^(${selectors})\\b`);
|
|
63
|
+
let adoptedSheet = null;
|
|
64
|
+
const rules = theme.cssRules;
|
|
65
|
+
for (let i = 0; i < rules.length; i++) {
|
|
66
|
+
const rule = rules[i];
|
|
67
|
+
if (rule instanceof CSSStyleRule) {
|
|
68
|
+
if (prefixRegex.test(rule.selectorText)) {
|
|
69
|
+
const selector = rule.cssText.replace(prefixRegex, `:host($1) `);
|
|
70
|
+
if (!adoptedSheet) {
|
|
71
|
+
adoptedSheet = new CSSStyleSheet();
|
|
72
|
+
}
|
|
73
|
+
adoptedSheet.insertRule(selector);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
console.log('<theming> caching stylesheet for %s', selectors);
|
|
78
|
+
themeMap.set(selectors, adoptedSheet);
|
|
79
|
+
return adoptedSheet;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get a list of selectors, which could match the given component.
|
|
84
|
+
* This will return the local name of the component, a selector for the id
|
|
85
|
+
* and all classes assigned.
|
|
86
|
+
*
|
|
87
|
+
* @param {HTMLElement} component the web component
|
|
88
|
+
* @returns {string[]} list of selectors
|
|
89
|
+
*/
|
|
90
|
+
function getSelectors(component) {
|
|
91
|
+
const prefixes = [component.localName];
|
|
92
|
+
if (component.id) {
|
|
93
|
+
prefixes.push(`#${component.id}`);
|
|
94
|
+
}
|
|
95
|
+
component.classList.forEach((cls) => prefixes.push(`.${cls}`));
|
|
96
|
+
return prefixes;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Implements support for injecting user-defined styles into a web component's shadow DOM.
|
|
101
|
+
* Styles will be copied from the global component theme CSS imported by `pb-page`
|
|
102
|
+
* (see `theme` property on `pb-page`)
|
|
103
|
+
*/
|
|
104
|
+
export const themableMixin = (superclass) => class ThemableMixin extends superclass {
|
|
105
|
+
|
|
106
|
+
connectedCallback() {
|
|
107
|
+
super.connectedCallback();
|
|
108
|
+
waitOnce('pb-page-ready', (options) => {
|
|
109
|
+
const theme = importStyles(this);
|
|
110
|
+
if (theme) {
|
|
111
|
+
this.shadowRoot.adoptedStyleSheets = [...this.shadowRoot.adoptedStyleSheets, theme];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|