@teipublisher/pb-components 2.26.0-next-3.11 → 2.26.0-next-3.13

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.
Files changed (133) hide show
  1. package/.github/workflows/main.yml +3 -3
  2. package/.github/workflows/node.js.yml +3 -3
  3. package/.github/workflows/release.js.yml +3 -3
  4. package/CHANGELOG.md +38 -0
  5. package/Dockerfile +78 -70
  6. package/css/components.css +5 -5
  7. package/dist/demo/components.css +2 -8
  8. package/dist/demo/pb-drawer2.html +1 -1
  9. package/dist/demo/pb-leaflet-map.html +1 -1
  10. package/dist/demo/pb-progress.html +2 -2
  11. package/dist/demo/pb-repeat.html +1 -3
  12. package/dist/demo/pb-view3.html +1 -1
  13. package/dist/{paper-icon-button-0fb125c4.js → paper-icon-button-72125e67.js} +1 -1
  14. package/dist/pb-code-editor.js +25 -20
  15. package/dist/pb-component-docs.js +58 -54
  16. package/dist/pb-components-bundle.js +1937 -1782
  17. package/dist/pb-edit-app.js +167 -107
  18. package/dist/pb-elements.json +45 -45
  19. package/dist/{pb-i18n-0611135a.js → pb-i18n-4cc00bfe.js} +1 -1
  20. package/dist/pb-leaflet-map.js +23 -23
  21. package/dist/pb-mei.js +56 -41
  22. package/dist/{pb-mixin-b1caa22e.js → pb-mixin-886ece32.js} +1 -1
  23. package/dist/pb-odd-editor.js +923 -756
  24. package/dist/pb-tify.js +2 -2
  25. package/dist/{vaadin-element-mixin-6633322b.js → vaadin-element-mixin-84fb7d82.js} +181 -143
  26. package/gh-pages.js +5 -3
  27. package/i18n/common/pl.json +2 -2
  28. package/lib/openseadragon.min.js +1 -1
  29. package/package.json +2 -2
  30. package/pb-elements.json +45 -45
  31. package/src/assets/components.css +5 -5
  32. package/src/authority/airtable.js +20 -21
  33. package/src/authority/anton.js +129 -129
  34. package/src/authority/custom.js +23 -21
  35. package/src/authority/geonames.js +38 -32
  36. package/src/authority/gnd.js +47 -42
  37. package/src/authority/kbga.js +137 -134
  38. package/src/authority/metagrid.js +44 -46
  39. package/src/authority/reconciliation.js +66 -67
  40. package/src/authority/registry.js +4 -4
  41. package/src/docs/pb-component-docs.js +2 -2
  42. package/src/docs/pb-component-view.js +5 -5
  43. package/src/docs/pb-components-list.js +2 -2
  44. package/src/docs/pb-demo-snippet.js +2 -2
  45. package/src/dts-client.js +299 -297
  46. package/src/dts-select-endpoint.js +90 -82
  47. package/src/parse-date-service.js +184 -135
  48. package/src/pb-ajax.js +150 -146
  49. package/src/pb-authority-lookup.js +183 -146
  50. package/src/pb-autocomplete.js +292 -280
  51. package/src/pb-blacklab-highlight.js +264 -259
  52. package/src/pb-blacklab-results.js +236 -221
  53. package/src/pb-browse-docs.js +540 -475
  54. package/src/pb-browse.js +68 -65
  55. package/src/pb-clipboard.js +79 -76
  56. package/src/pb-code-editor.js +110 -102
  57. package/src/pb-code-highlight.js +209 -204
  58. package/src/pb-codepen.js +79 -72
  59. package/src/pb-collapse.js +212 -207
  60. package/src/pb-combo-box.js +190 -190
  61. package/src/pb-components-bundle.js +1 -1
  62. package/src/pb-custom-form.js +151 -149
  63. package/src/pb-dialog.js +96 -60
  64. package/src/pb-document.js +89 -90
  65. package/src/pb-download.js +210 -198
  66. package/src/pb-drawer.js +145 -148
  67. package/src/pb-edit-app.js +301 -229
  68. package/src/pb-edit-xml.js +98 -96
  69. package/src/pb-events.js +114 -107
  70. package/src/pb-facs-link.js +104 -102
  71. package/src/pb-facsimile.js +411 -413
  72. package/src/pb-formula.js +151 -153
  73. package/src/pb-geolocation.js +129 -131
  74. package/src/pb-grid-action.js +53 -56
  75. package/src/pb-grid.js +231 -228
  76. package/src/pb-highlight.js +140 -140
  77. package/src/pb-hotkeys.js +40 -42
  78. package/src/pb-i18n.js +101 -104
  79. package/src/pb-image-strip.js +84 -78
  80. package/src/pb-lang.js +132 -128
  81. package/src/pb-leaflet-map.js +488 -485
  82. package/src/pb-link.js +126 -124
  83. package/src/pb-load.js +431 -426
  84. package/src/pb-login.js +291 -248
  85. package/src/pb-manage-odds.js +364 -318
  86. package/src/pb-map-icon.js +89 -89
  87. package/src/pb-map-layer.js +85 -85
  88. package/src/pb-markdown.js +90 -99
  89. package/src/pb-media-query.js +74 -72
  90. package/src/pb-mei.js +306 -295
  91. package/src/pb-message.js +144 -144
  92. package/src/pb-mixin.js +269 -264
  93. package/src/pb-navigation.js +80 -82
  94. package/src/pb-observable.js +38 -38
  95. package/src/pb-odd-editor.js +1053 -955
  96. package/src/pb-odd-elementspec-editor.js +348 -297
  97. package/src/pb-odd-model-editor.js +1061 -901
  98. package/src/pb-odd-parameter-editor.js +200 -178
  99. package/src/pb-odd-rendition-editor.js +136 -124
  100. package/src/pb-page.js +431 -421
  101. package/src/pb-paginate.js +202 -190
  102. package/src/pb-panel.js +191 -179
  103. package/src/pb-popover-themes.js +7 -5
  104. package/src/pb-popover.js +296 -287
  105. package/src/pb-print-preview.js +127 -127
  106. package/src/pb-progress.js +51 -51
  107. package/src/pb-repeat.js +105 -104
  108. package/src/pb-restricted.js +84 -77
  109. package/src/pb-search.js +252 -241
  110. package/src/pb-select-feature.js +127 -120
  111. package/src/pb-select-odd.js +132 -124
  112. package/src/pb-select-template.js +89 -78
  113. package/src/pb-select.js +251 -227
  114. package/src/pb-split-list.js +179 -174
  115. package/src/pb-svg.js +80 -79
  116. package/src/pb-table-column.js +54 -54
  117. package/src/pb-table-grid.js +221 -203
  118. package/src/pb-tabs.js +61 -63
  119. package/src/pb-tify.js +154 -154
  120. package/src/pb-timeline.js +271 -229
  121. package/src/pb-toggle-feature.js +182 -175
  122. package/src/pb-upload.js +184 -174
  123. package/src/pb-version.js +30 -30
  124. package/src/pb-view-annotate.js +132 -98
  125. package/src/pb-view.js +1289 -1270
  126. package/src/pb-zoom.js +75 -59
  127. package/src/polymer-hack.js +1 -1
  128. package/src/search-result-service.js +256 -223
  129. package/src/seed-element.js +13 -20
  130. package/src/settings.js +4 -4
  131. package/src/theming.js +96 -96
  132. package/src/urls.js +289 -289
  133. package/src/utils.js +53 -51
@@ -1,10 +1,10 @@
1
1
  import { html, css } from 'lit-element';
2
2
  import { PbLoad } from './pb-load.js';
3
3
  import { waitOnce } from './pb-mixin.js';
4
- import { translate } from "./pb-i18n.js";
5
- import { themableMixin } from "./theming.js";
4
+ import { translate } from './pb-i18n.js';
5
+ import { themableMixin } from './theming.js';
6
6
  import { cmpVersion } from './utils.js';
7
- import { registry } from "./urls.js";
7
+ import { registry } from './urls.js';
8
8
 
9
9
  import '@polymer/paper-input/paper-input.js';
10
10
  import '@polymer/paper-button';
@@ -21,520 +21,585 @@ import '@cwmr/paper-autocomplete/paper-autocomplete-suggestions.js';
21
21
  * @slot toolbar - toolbar area
22
22
  * @slot - unnamed default slot
23
23
  * @slot footer - footer area
24
- *
24
+ *
25
25
  * @fires pb-collection - Sent to inform e.g. pb-upload about current collection
26
26
  * @fires pb-search-resubmit - When received, set facet values as received from the event
27
27
  * @fires pb-login - When received, refresh the view if the user changed
28
- *
28
+ *
29
29
  * @cssprop --pb-search-suggestions-background - Background for the autocomplete suggestions for the filter field
30
30
  * @cssprop --pb-search-suggestions-color - Text color for the autocomplete suggestion for the filter field
31
31
  * @cssprop --pb-search-label-color - Determines the color of small label above the sort by/filter by/filter fields
32
32
  * @cssprop --pb-search-input-color - Determines the color of the text in the sort by/filter by/filter fields
33
33
  * @cssprop --pb-search-focus-color - Color of the field labels and underline when in focus
34
34
  * @cssprop --pb-browse-toolbar-justify-content - How to justify the browse toolbar content, following flexbox justify-content property e.g. center, space-evenly, start...
35
- *
35
+ *
36
36
  * @csspart delete-button - the delete button
37
37
  * @csspart sort-dropdown - dropdown for sorting
38
38
  * @csspart filter-dropdown - dropdown for filtering
39
39
  * @csspart filter-input - input for filtering
40
40
  */
41
41
  export class PbBrowseDocs extends themableMixin(PbLoad) {
42
+ static get properties() {
43
+ return {
44
+ ...super.properties,
45
+ sortBy: {
46
+ type: String,
47
+ attribute: 'sort-by',
48
+ },
49
+ sortOptions: {
50
+ type: Array,
51
+ attribute: 'sort-options',
52
+ },
53
+ sortLabel: {
54
+ type: String,
55
+ },
56
+ filter: {
57
+ type: String,
58
+ },
59
+ filterBy: {
60
+ type: String,
61
+ attribute: 'filter-by',
62
+ },
63
+ filterOptions: {
64
+ type: Array,
65
+ attribute: 'filter-options',
66
+ },
67
+ filterByLabel: {
68
+ type: String,
69
+ },
70
+ filterPlaceholderLabel: {
71
+ type: String,
72
+ },
73
+ collection: {
74
+ type: String,
75
+ },
76
+ facets: {
77
+ type: Object,
78
+ },
79
+ /** Id of the pb-login element to connect to */
80
+ login: {
81
+ type: String,
82
+ },
83
+ /**
84
+ * If set, requires the logged in user to be member of
85
+ * the given group.
86
+ */
87
+ group: {
88
+ type: String,
89
+ },
90
+ subforms: {
91
+ type: String,
92
+ },
93
+ /**
94
+ * If set, rewrite URLs to load pages as static HTML files,
95
+ * so no TEI Publisher instance is required
96
+ */
97
+ static: {
98
+ type: Boolean,
99
+ },
100
+ _file: {
101
+ type: String,
102
+ },
103
+ _selected: {
104
+ type: Array,
105
+ },
106
+ _allowModification: {
107
+ type: Boolean,
108
+ },
109
+ _suggestions: {
110
+ type: Array,
111
+ },
112
+ };
113
+ }
114
+
115
+ constructor() {
116
+ super();
117
+ this.sortOptions = [];
118
+ this.sortLabel = 'browse.sort';
119
+ this.sortBy = 'default';
120
+ this.filter = '';
121
+ this.filterOptions = [
122
+ {
123
+ label: 'Title',
124
+ value: 'title',
125
+ },
126
+ ];
127
+ this.filterByLabel = 'browse.filter';
128
+ this.filterPlaceholderLabel = 'browse.filterPlaceholder';
129
+
130
+ this.filterBy = 'title';
131
+ this._allowModification = false;
132
+ this._suggestions = [];
133
+
134
+ this.static = false;
135
+ }
136
+
137
+ connectedCallback() {
138
+ super.connectedCallback();
139
+
140
+ waitOnce('pb-page-ready', () => {
141
+ if (registry.state.sort) {
142
+ this.sortBy = registry.state.sort;
143
+ }
144
+
145
+ if (registry.state.filter) {
146
+ this.filter = registry.state.filter;
147
+ this.filterBy = registry.state.filterBy || this.filterBy;
148
+ }
149
+
150
+ this.facets = {};
151
+ // registry get state by regex
152
+ // this.facets = registry.getParametersMatching(this, /^facet-.*$/)
153
+ Object.keys(registry.state).forEach(key => {
154
+ if (/^facet-.*$/.test(key)) {
155
+ const param = registry.state[key];
156
+ if (this.facets[key]) {
157
+ this.facets[key].push(param);
158
+ } else if (Array.isArray(param)) {
159
+ this.facets[key] = param;
160
+ } else {
161
+ this.facets[key] = [param];
162
+ }
163
+ }
164
+ });
42
165
 
43
- static get properties() {
44
- return {
45
- ...super.properties,
46
- sortBy: {
47
- type: String,
48
- attribute: 'sort-by'
49
- },
50
- sortOptions: {
51
- type: Array,
52
- attribute: 'sort-options'
53
- },
54
- sortLabel: {
55
- type: String
56
- },
57
- filter: {
58
- type: String
59
- },
60
- filterBy: {
61
- type: String,
62
- attribute: 'filter-by'
63
- },
64
- filterOptions: {
65
- type: Array,
66
- attribute: 'filter-options'
67
- },
68
- filterByLabel: {
69
- type: String
70
- },
71
- filterPlaceholderLabel: {
72
- type: String
73
- },
74
- collection: {
75
- type: String
76
- },
77
- facets: {
78
- type: Object
79
- },
80
- /** Id of the pb-login element to connect to */
81
- login: {
82
- type: String
83
- },
84
- /**
85
- * If set, requires the logged in user to be member of
86
- * the given group.
87
- */
88
- group: {
89
- type: String
90
- },
91
- subforms: {
92
- type: String
93
- },
94
- /**
95
- * If set, rewrite URLs to load pages as static HTML files,
96
- * so no TEI Publisher instance is required
97
- */
98
- static: {
99
- type: Boolean
100
- },
101
- _file: {
102
- type: String
103
- },
104
- _selected: {
105
- type: Array
106
- },
107
- _allowModification: {
108
- type: Boolean,
109
- },
110
- _suggestions: {
111
- type: Array
112
- }
113
- };
114
- }
115
-
116
- constructor() {
117
- super();
118
- this.sortOptions = [];
119
- this.sortLabel = 'browse.sort';
120
- this.sortBy = 'default';
121
- this.filter = '';
122
- this.filterOptions = [
123
- {
124
- label: 'Title',
125
- value: 'title'
126
- }
127
- ];
128
- this.filterByLabel = 'browse.filter';
129
- this.filterPlaceholderLabel = 'browse.filterPlaceholder';
130
-
131
- this.filterBy = 'title';
132
- this._allowModification = false;
133
- this._suggestions = [];
134
-
135
- this.static = false;
136
- }
137
-
138
- connectedCallback() {
139
- super.connectedCallback();
166
+ this.collection = registry.state.collection;
140
167
 
141
- waitOnce('pb-page-ready', () => {
142
- if (registry.state.sort) {
143
- this.sortBy = registry.state.sort;
144
- }
145
-
146
- if (registry.state.filter) {
147
- this.filter = registry.state.filter;
148
- this.filterBy = registry.state.filterBy || this.filterBy;
149
- }
150
-
151
- this.facets = {};
152
- // registry get state by regex
153
- // this.facets = registry.getParametersMatching(this, /^facet-.*$/)
154
- Object.keys(registry.state).forEach((key) => {
155
- if (/^facet-.*$/.test(key)) {
156
- const param = registry.state[key];
157
- if (this.facets[key]) {
158
- this.facets[key].push(param);
159
- } else if (Array.isArray(param)) {
160
- this.facets[key] = param;
161
- } else {
162
- this.facets[key] = [param];
163
- }
164
- }
165
- });
166
-
167
- this.collection = registry.state.collection;
168
-
169
- if (this.collection) {
170
- registry.replace(this, {
171
- collection: this.collection
172
- });
173
- }
174
- registry.subscribe(this, (state) => {
175
- this.collection = state.collection;
176
- this.load();
177
- });
178
- });
179
-
180
- this.subscribeTo('pb-search-resubmit', this._facets.bind(this));
181
- this.subscribeTo('pb-login', (ev) => {
182
- if (ev.detail.userChanged) {
183
- this._facets(ev);
184
- }
185
- }, []);
186
- document.addEventListener('pb-i18n-update', () => {
187
- // clear paper-listbox selection after language updates
188
- const lb = this.shadowRoot.getElementById('sort-list');
189
- let old = lb.selected;
190
- lb.selected = undefined;
191
- lb.selected = old;
192
-
193
- const fl = this.shadowRoot.getElementById('filter-list');
194
- old = fl.selected;
195
- fl.selected = undefined;
196
- fl.selected = old;
168
+ if (this.collection) {
169
+ registry.replace(this, {
170
+ collection: this.collection,
197
171
  });
198
- }
199
-
200
- firstUpdated() {
201
- waitOnce('pb-page-ready', (options) => {
202
- const loader = this.shadowRoot.getElementById('autocompleteLoader');
203
- if (cmpVersion(options.apiVersion, '1.0.0') >= 0) {
204
- loader.url = `${options.endpoint}/api/search/autocomplete`;
205
- if (!this.url) {
206
- this.url = 'api/collection';
207
- }
208
- } else {
209
- loader.url = `${options.endpoint}/modules/autocomplete.xql`;
210
- if (!this.url) {
211
- this.url = 'collection/';
212
- }
213
- }
214
- });
215
- this.shadowRoot.getElementById('autocomplete').addEventListener('autocomplete-change', this._autocomplete.bind(this));
216
-
217
- if (this.login) {
218
- const login = document.getElementById(this.login);
219
- if (!login) {
220
- console.error('<pb-browse-docs> connected pb-login element not found!');
221
- } else {
222
- this.subscribeTo('pb-login', (ev) => {
223
- this._allowModification = this._loggedIn(ev.detail.user, ev.detail.group);
224
- }, []);
225
- this._allowModification = login.loggedIn && this._loggedIn(login.user, login.groups);
226
- }
172
+ }
173
+ registry.subscribe(this, state => {
174
+ this.collection = state.collection;
175
+ this.load();
176
+ });
177
+ });
178
+
179
+ this.subscribeTo('pb-search-resubmit', this._facets.bind(this));
180
+ this.subscribeTo(
181
+ 'pb-login',
182
+ ev => {
183
+ if (ev.detail.userChanged) {
184
+ this._facets(ev);
227
185
  }
228
-
229
- this.shadowRoot.getElementById('sort-list').addEventListener('selected-item-changed', this._sort.bind(this));
230
- this.shadowRoot.getElementById('delete').addEventListener('click', this._handleDelete.bind(this));
231
- super.firstUpdated();
232
- }
233
-
234
- render() {
235
- return html`
236
- <custom-style>
237
- <style>
238
- :host {
239
- --suggestions-item: {
240
- color: var(--pb-search-suggestions-color, black);
241
- };
242
- --suggestions-wrapper: {
243
- background: var(--pb-search-suggestions-background, white);
244
- }
245
- }
246
- </style>
247
- </custom-style>
248
- <slot name="header"></slot>
249
- <div class="toolbar">
250
- <paper-dropdown-menu id="sort" label="${translate(this.sortLabel)}" part="sort-dropdown">
251
- <paper-listbox id="sort-list" selected="${this.sortBy}" slot="dropdown-content" class="dropdown-content" attr-for-selected="value">
252
- ${this.sortOptions.map(option =>
253
- html`<paper-item value="${option.value}">${translate(option.label)}</paper-item>`
254
- )}
255
- </paper-listbox>
256
- </paper-dropdown-menu>
257
- <div>
258
- <paper-dropdown-menu id="filterSelect" label="${translate(this.filterByLabel)}" part="filter-dropdown">
259
- <paper-listbox id="filter-list" selected="${this.filterBy}" slot="dropdown-content" class="dropdown-content" attr-for-selected="value" @selected-item-changed="${this._filterChanged}">
260
- ${this.filterOptions.map(option =>
261
- html`<paper-item value="${option.value}">${translate(option.label)}</paper-item>`
262
- )}
263
- </paper-listbox>
264
- </paper-dropdown-menu>
265
- <paper-input id="filterString" type="search" name="filter" label="${translate(this.filterPlaceholderLabel)}" value="${this.filter}"
266
- @keyup="${this._handleEnter}" part="filter-input">
267
- <iron-icon icon="search" @click="${this._filter}" slot="prefix"></iron-icon>
268
- </paper-input>
269
- <paper-autocomplete-suggestions id="autocomplete" for="filterString" source="${this._suggestions}" remote-source></paper-autocomplete-suggestions>
270
- </div>
271
- </div>
272
- <div class="toolbar">
273
- <slot name="toolbar"></slot>
274
- <paper-button id="delete" part="delete-button" title="${translate('browse.delete')}" class="${this._canModify(this._allowModification)}">
275
- <iron-icon icon="delete"></iron-icon>
276
- <span class="label">${translate('browse.delete')}</span>
277
- </paper-button>
278
- </div>
279
- <slot></slot>
280
- <slot name="footer"></slot>
281
-
282
- <iron-ajax
283
- id="loadContent"
284
- verbose
285
- handle-as="text"
286
- method="get"
287
- with-credentials
288
- @response="${this._handleContent}"
289
- @error="${this._handleError}"></iron-ajax>
290
- <iron-ajax
291
- id="autocompleteLoader"
292
- verbose
293
- handle-as="json"
294
- method="get"
295
- with-credentials
296
- @response="${this._updateSuggestions}"></iron-ajax>
297
-
298
- <paper-dialog id="deleteDialog">
299
- <h2>${translate('browse.delete')}</h2>
300
- <paper-dialog-scrollable>
301
- <p>${translate('browse.confirmDeletion', { count: (this._selected ? this._selected.length : 0) })}</p>
302
- </paper-dialog-scrollable>
303
- <div class="buttons">
304
- <paper-button dialog-confirm="dialog-confirm" autofocus @click="${this._confirmDelete}">${translate('dialogs.yes')}</paper-button>
305
- <paper-button dialog-confirm="dialog-cancel">${translate('dialogs.no')}</paper-button>
306
- </div>
307
- </paper-dialog>
308
- <paper-dialog id="errorDialog">
309
- <h2>${translate('dialogs.error')}</h2>
310
- <paper-dialog-scrollable></paper-dialog-scrollable>
311
- <div class="buttons">
312
- <paper-button dialog-confirm="dialog-confirm" autofocus="autofocus">
313
- ${translate('dialogs.close')}
314
- </paper-button>
315
- </div>
316
- </paper-dialog>
317
- `;
186
+ },
187
+ [],
188
+ );
189
+ document.addEventListener('pb-i18n-update', () => {
190
+ // clear paper-listbox selection after language updates
191
+ const lb = this.shadowRoot.getElementById('sort-list');
192
+ let old = lb.selected;
193
+ lb.selected = undefined;
194
+ lb.selected = old;
195
+
196
+ const fl = this.shadowRoot.getElementById('filter-list');
197
+ old = fl.selected;
198
+ fl.selected = undefined;
199
+ fl.selected = old;
200
+ });
201
+ }
202
+
203
+ firstUpdated() {
204
+ waitOnce('pb-page-ready', options => {
205
+ const loader = this.shadowRoot.getElementById('autocompleteLoader');
206
+ if (cmpVersion(options.apiVersion, '1.0.0') >= 0) {
207
+ loader.url = `${options.endpoint}/api/search/autocomplete`;
208
+ if (!this.url) {
209
+ this.url = 'api/collection';
210
+ }
211
+ } else {
212
+ loader.url = `${options.endpoint}/modules/autocomplete.xql`;
213
+ if (!this.url) {
214
+ this.url = 'collection/';
215
+ }
216
+ }
217
+ });
218
+ this.shadowRoot
219
+ .getElementById('autocomplete')
220
+ .addEventListener('autocomplete-change', this._autocomplete.bind(this));
221
+
222
+ if (this.login) {
223
+ const login = document.getElementById(this.login);
224
+ if (!login) {
225
+ console.error('<pb-browse-docs> connected pb-login element not found!');
226
+ } else {
227
+ this.subscribeTo(
228
+ 'pb-login',
229
+ ev => {
230
+ this._allowModification = this._loggedIn(ev.detail.user, ev.detail.group);
231
+ },
232
+ [],
233
+ );
234
+ this._allowModification = login.loggedIn && this._loggedIn(login.user, login.groups);
235
+ }
318
236
  }
319
237
 
320
- static get styles() {
321
- return css`
322
- :host {
323
- display: block;
324
- --paper-input-container-color: var(--pb-search-label-color, var(--paper-grey-500, #303030));
325
- --paper-input-container-input-color: var(--pb-search-input-color, var(--pb-color-primary, #000000));
326
- --paper-input-container-focus-color: var(--pb-search-focus-color, var(--paper-grey-500, #303030));
327
- }
328
-
329
- .toolbar {
330
- display: flex;
331
- justify-content: var(--pb-browse-toolbar-justify-content);
332
- }
333
-
334
- [name="toolbar"] {
335
- flex: 1 0;
336
- }
337
-
338
- #sort {
339
- display: block;
340
- }
341
-
342
- #filterString {
343
- position: relative;
344
- display: inline-block;
345
- vertical-align: bottom;
238
+ this.shadowRoot
239
+ .getElementById('sort-list')
240
+ .addEventListener('selected-item-changed', this._sort.bind(this));
241
+ this.shadowRoot
242
+ .getElementById('delete')
243
+ .addEventListener('click', this._handleDelete.bind(this));
244
+ super.firstUpdated();
245
+ }
246
+
247
+ render() {
248
+ return html`
249
+ <custom-style>
250
+ <style>
251
+ :host {
252
+ --suggestions-item: {
253
+ color: var(--pb-search-suggestions-color, black);
346
254
  }
347
-
348
- .hidden {
349
- display: none;
255
+ --suggestions-wrapper: {
256
+ background: var(--pb-search-suggestions-background, white);
350
257
  }
351
- `;
258
+ }
259
+ </style>
260
+ </custom-style>
261
+ <slot name="header"></slot>
262
+ <div class="toolbar">
263
+ <paper-dropdown-menu id="sort" label="${translate(this.sortLabel)}" part="sort-dropdown">
264
+ <paper-listbox
265
+ id="sort-list"
266
+ selected="${this.sortBy}"
267
+ slot="dropdown-content"
268
+ class="dropdown-content"
269
+ attr-for-selected="value"
270
+ >
271
+ ${this.sortOptions.map(
272
+ option =>
273
+ html`<paper-item value="${option.value}">${translate(option.label)}</paper-item>`,
274
+ )}
275
+ </paper-listbox>
276
+ </paper-dropdown-menu>
277
+ <div>
278
+ <paper-dropdown-menu
279
+ id="filterSelect"
280
+ label="${translate(this.filterByLabel)}"
281
+ part="filter-dropdown"
282
+ >
283
+ <paper-listbox
284
+ id="filter-list"
285
+ selected="${this.filterBy}"
286
+ slot="dropdown-content"
287
+ class="dropdown-content"
288
+ attr-for-selected="value"
289
+ @selected-item-changed="${this._filterChanged}"
290
+ >
291
+ ${this.filterOptions.map(
292
+ option =>
293
+ html`<paper-item value="${option.value}">${translate(option.label)}</paper-item>`,
294
+ )}
295
+ </paper-listbox>
296
+ </paper-dropdown-menu>
297
+ <paper-input
298
+ id="filterString"
299
+ type="search"
300
+ name="filter"
301
+ label="${translate(this.filterPlaceholderLabel)}"
302
+ value="${this.filter}"
303
+ @keyup="${this._handleEnter}"
304
+ part="filter-input"
305
+ >
306
+ <iron-icon icon="search" @click="${this._filter}" slot="prefix"></iron-icon>
307
+ </paper-input>
308
+ <paper-autocomplete-suggestions
309
+ id="autocomplete"
310
+ for="filterString"
311
+ source="${this._suggestions}"
312
+ remote-source
313
+ ></paper-autocomplete-suggestions>
314
+ </div>
315
+ </div>
316
+ <div class="toolbar">
317
+ <slot name="toolbar"></slot>
318
+ <paper-button
319
+ id="delete"
320
+ part="delete-button"
321
+ title="${translate('browse.delete')}"
322
+ class="${this._canModify(this._allowModification)}"
323
+ >
324
+ <iron-icon icon="delete"></iron-icon>
325
+ <span class="label">${translate('browse.delete')}</span>
326
+ </paper-button>
327
+ </div>
328
+ <slot></slot>
329
+ <slot name="footer"></slot>
330
+
331
+ <iron-ajax
332
+ id="loadContent"
333
+ verbose
334
+ handle-as="text"
335
+ method="get"
336
+ with-credentials
337
+ @response="${this._handleContent}"
338
+ @error="${this._handleError}"
339
+ ></iron-ajax>
340
+ <iron-ajax
341
+ id="autocompleteLoader"
342
+ verbose
343
+ handle-as="json"
344
+ method="get"
345
+ with-credentials
346
+ @response="${this._updateSuggestions}"
347
+ ></iron-ajax>
348
+
349
+ <paper-dialog id="deleteDialog">
350
+ <h2>${translate('browse.delete')}</h2>
351
+ <paper-dialog-scrollable>
352
+ <p>
353
+ ${translate('browse.confirmDeletion', {
354
+ count: this._selected ? this._selected.length : 0,
355
+ })}
356
+ </p>
357
+ </paper-dialog-scrollable>
358
+ <div class="buttons">
359
+ <paper-button dialog-confirm="dialog-confirm" autofocus @click="${this._confirmDelete}"
360
+ >${translate('dialogs.yes')}</paper-button
361
+ >
362
+ <paper-button dialog-confirm="dialog-cancel">${translate('dialogs.no')}</paper-button>
363
+ </div>
364
+ </paper-dialog>
365
+ <paper-dialog id="errorDialog">
366
+ <h2>${translate('dialogs.error')}</h2>
367
+ <paper-dialog-scrollable></paper-dialog-scrollable>
368
+ <div class="buttons">
369
+ <paper-button dialog-confirm="dialog-confirm" autofocus="autofocus">
370
+ ${translate('dialogs.close')}
371
+ </paper-button>
372
+ </div>
373
+ </paper-dialog>
374
+ `;
375
+ }
376
+
377
+ static get styles() {
378
+ return css`
379
+ :host {
380
+ display: block;
381
+ --paper-input-container-color: var(--pb-search-label-color, var(--paper-grey-500, #303030));
382
+ --paper-input-container-input-color: var(
383
+ --pb-search-input-color,
384
+ var(--pb-color-primary, #000000)
385
+ );
386
+ --paper-input-container-focus-color: var(
387
+ --pb-search-focus-color,
388
+ var(--paper-grey-500, #303030)
389
+ );
390
+ }
391
+
392
+ .toolbar {
393
+ display: flex;
394
+ justify-content: var(--pb-browse-toolbar-justify-content);
395
+ }
396
+
397
+ [name='toolbar'] {
398
+ flex: 1 0;
399
+ }
400
+
401
+ #sort {
402
+ display: block;
403
+ }
404
+
405
+ #filterString {
406
+ position: relative;
407
+ display: inline-block;
408
+ vertical-align: bottom;
409
+ }
410
+
411
+ .hidden {
412
+ display: none;
413
+ }
414
+ `;
415
+ }
416
+
417
+ getURL(params) {
418
+ if (this.static) {
419
+ // use a static URL
420
+ return `collections/${this.collection ? `${this.collection}/` : ''}${
421
+ params.start || '1'
422
+ }.html`;
352
423
  }
353
-
354
- getURL(params) {
355
- if (this.static) {
356
- // use a static URL
357
- return `collections/${this.collection ? this.collection + '/' : ''}${params.start || '1'}.html`;
358
- }
359
- const url = super.getURL(params);
360
- return this.collection ? `${url}/${this.collection}` : url;
424
+ const url = super.getURL(params);
425
+ return this.collection ? `${url}/${this.collection}` : url;
426
+ }
427
+
428
+ prepareParameters(params) {
429
+ params = this._paramsFromSubforms(params);
430
+ params.sort = this.sortBy;
431
+ if (this.filter) {
432
+ params.filter = this.filter;
433
+ params.browse = this.filterBy;
361
434
  }
362
-
363
- prepareParameters(params) {
364
- params = this._paramsFromSubforms(params);
365
- params.sort = this.sortBy;
366
- if (this.filter) {
367
- params.filter = this.filter;
368
- params.browse = this.filterBy;
369
- }
370
- if (this.facets) {
371
- params = Object.assign(params, this.facets);
372
- }
373
- return params;
435
+ if (this.facets) {
436
+ params = Object.assign(params, this.facets);
374
437
  }
375
-
376
- _paramsFromSubforms(params) {
377
- if (this.subforms) {
378
- document.querySelectorAll(this.subforms).forEach((form) => {
379
- if (form.serializeForm) {
380
- Object.assign(params, form.serializeForm());
381
- }
382
- });
438
+ return params;
439
+ }
440
+
441
+ _paramsFromSubforms(params) {
442
+ if (this.subforms) {
443
+ document.querySelectorAll(this.subforms).forEach(form => {
444
+ if (form.serializeForm) {
445
+ Object.assign(params, form.serializeForm());
383
446
  }
384
- return params;
447
+ });
385
448
  }
386
-
387
- /**
388
- * returns selected documents.
389
- *
390
- * @returns {Array}
391
- */
392
- getSelected() {
393
- const selected = [];
394
- if (this.container) {
395
- document.querySelectorAll(this.container).forEach((container) =>
396
- container.querySelectorAll('.document-select paper-checkbox[checked]').forEach((checkbox) => {
397
- selected.push(checkbox.value);
398
- })
399
- );
400
- } else {
401
- this.querySelectorAll('.document-select paper-checkbox[checked]').forEach((checkbox) => {
402
- selected.push(checkbox.value);
403
- });
404
- }
405
- return selected;
449
+ return params;
450
+ }
451
+
452
+ /**
453
+ * returns selected documents.
454
+ *
455
+ * @returns {Array}
456
+ */
457
+ getSelected() {
458
+ const selected = [];
459
+ if (this.container) {
460
+ document.querySelectorAll(this.container).forEach(container =>
461
+ container.querySelectorAll('.document-select paper-checkbox[checked]').forEach(checkbox => {
462
+ selected.push(checkbox.value);
463
+ }),
464
+ );
465
+ } else {
466
+ this.querySelectorAll('.document-select paper-checkbox[checked]').forEach(checkbox => {
467
+ selected.push(checkbox.value);
468
+ });
406
469
  }
407
-
408
- _filter() {
409
- const filter = this.shadowRoot.getElementById('filterString').value;
410
- const filterBy = this.shadowRoot.getElementById('filter-list').selected;
411
- if (typeof filter !== 'undefined') {
412
- console.log('<pb-browse-docs> Filter by %s', filter);
413
- this.filter = filter;
414
- registry.commit(this, { filter, filterBy })
415
- this.load();
416
- }
470
+ return selected;
471
+ }
472
+
473
+ _filter() {
474
+ const filter = this.shadowRoot.getElementById('filterString').value;
475
+ const filterBy = this.shadowRoot.getElementById('filter-list').selected;
476
+ if (typeof filter !== 'undefined') {
477
+ console.log('<pb-browse-docs> Filter by %s', filter);
478
+ this.filter = filter;
479
+ registry.commit(this, { filter, filterBy });
480
+ this.load();
417
481
  }
482
+ }
418
483
 
419
- _filterChanged() {
420
- const filterBy = this.shadowRoot.getElementById('filter-list').selected;
421
- if (filterBy && filterBy !== this.filterBy) {
422
- console.log('<pb-browse-docs> Filtering on %s', filterBy);
423
- this.filterBy = filterBy;
424
- }
484
+ _filterChanged() {
485
+ const filterBy = this.shadowRoot.getElementById('filter-list').selected;
486
+ if (filterBy && filterBy !== this.filterBy) {
487
+ console.log('<pb-browse-docs> Filtering on %s', filterBy);
488
+ this.filterBy = filterBy;
425
489
  }
490
+ }
426
491
 
427
- _sort() {
428
- const sortBy = this.shadowRoot.getElementById('sort-list').selected;
429
- if (sortBy && sortBy !== this.sortBy) {
430
- console.log('<pb-browse-docs> Sorting by %s', sortBy);
431
- this.sortBy = sortBy;
432
- registry.commit(this, { sort: sortBy })
492
+ _sort() {
493
+ const sortBy = this.shadowRoot.getElementById('sort-list').selected;
494
+ if (sortBy && sortBy !== this.sortBy) {
495
+ console.log('<pb-browse-docs> Sorting by %s', sortBy);
496
+ this.sortBy = sortBy;
497
+ registry.commit(this, { sort: sortBy });
433
498
 
434
- this.load();
435
- }
499
+ this.load();
436
500
  }
437
-
438
- _facets(ev) {
439
- if (ev.detail && ev.detail.params) {
440
- registry.clearParametersMatching(this, /^(all-|facet-).*/);
441
- this.facets = ev.detail.params;
442
- this.start = 1;
443
- registry.commit(this, ev.detail.params)
444
- }
445
- this.load();
501
+ }
502
+
503
+ _facets(ev) {
504
+ if (ev.detail && ev.detail.params) {
505
+ registry.clearParametersMatching(this, /^(all-|facet-).*/);
506
+ this.facets = ev.detail.params;
507
+ this.start = 1;
508
+ registry.commit(this, ev.detail.params);
446
509
  }
447
-
448
- _onLoad(content) {
449
- window.scrollTo(0, 0);
450
- const div = content.querySelector('[data-root]');
451
- const collection = div && div.getAttribute('data-root');
452
- const writable = div && div.classList.contains('writable');
453
- this.emitTo('pb-collection', {
454
- writable,
455
- collection
456
- });
457
- document.querySelectorAll('[can-write]').forEach((elem) => {
458
- elem.disabled = !writable;
459
- });
460
- content.querySelectorAll('[data-collection]').forEach(link => {
461
- link.addEventListener('click', (ev) => {
462
- ev.preventDefault();
463
- this.collection = link.getAttribute('data-collection');
464
- this.start = 1;
465
- registry.commit(this, { collection: this.collection });
466
- console.log('<pb-browse-docs> loading collection %s', this.collection);
467
- this.load();
468
- });
469
- });
470
- }
471
-
472
- _handleDelete(target, ev) {
473
- const deleteDialog = this.shadowRoot.getElementById('deleteDialog');
474
- const selected = this.getSelected();
475
- if (selected.length > 0) {
476
- this._selected = selected;
477
- deleteDialog.open();
478
- }
479
- }
480
-
481
- _confirmDelete() {
482
- if (!(this._file || this._selected)) {
483
- return;
484
- }
485
-
486
- let files;
487
- if (this._selected) {
488
- files = this._selected;
489
- } else {
490
- files = [this._file];
491
- }
492
- console.log('<pb-browse-docs> Deleting %o', this._file);
493
- const params = {
494
- action: 'delete',
495
- 'docs[]': files
496
- };
497
- this._file = null;
498
- this._selected = null;
499
- this.load(params);
510
+ this.load();
511
+ }
512
+
513
+ _onLoad(content) {
514
+ window.scrollTo(0, 0);
515
+ const div = content.querySelector('[data-root]');
516
+ const collection = div && div.getAttribute('data-root');
517
+ const writable = div && div.classList.contains('writable');
518
+ this.emitTo('pb-collection', {
519
+ writable,
520
+ collection,
521
+ });
522
+ document.querySelectorAll('[can-write]').forEach(elem => {
523
+ elem.disabled = !writable;
524
+ });
525
+ content.querySelectorAll('[data-collection]').forEach(link => {
526
+ link.addEventListener('click', ev => {
527
+ ev.preventDefault();
528
+ this.collection = link.getAttribute('data-collection');
529
+ this.start = 1;
530
+ registry.commit(this, { collection: this.collection });
531
+ console.log('<pb-browse-docs> loading collection %s', this.collection);
532
+ this.load();
533
+ });
534
+ });
535
+ }
536
+
537
+ _handleDelete(target, ev) {
538
+ const deleteDialog = this.shadowRoot.getElementById('deleteDialog');
539
+ const selected = this.getSelected();
540
+ if (selected.length > 0) {
541
+ this._selected = selected;
542
+ deleteDialog.open();
500
543
  }
544
+ }
501
545
 
502
- _loggedIn(user, groups) {
503
- if (user == null) {
504
- return false;
505
- }
506
- if (this.group) {
507
- if (!groups) {
508
- return false;
509
- }
510
- return groups.indexOf(this.group) > -1;
511
- }
512
- return true;
546
+ _confirmDelete() {
547
+ if (!(this._file || this._selected)) {
548
+ return;
513
549
  }
514
550
 
515
- _canModify(allowModification) {
516
- return allowModification ? '' : 'hidden';
551
+ let files;
552
+ if (this._selected) {
553
+ files = this._selected;
554
+ } else {
555
+ files = [this._file];
517
556
  }
518
-
519
- _autocomplete(ev) {
520
- const autocompleteLoader = this.shadowRoot.getElementById('autocompleteLoader');
521
- autocompleteLoader.params = {
522
- query: ev.detail.option.text,
523
- field: this.filterBy
524
- };
525
- autocompleteLoader.generateRequest();
557
+ console.log('<pb-browse-docs> Deleting %o', this._file);
558
+ const params = {
559
+ action: 'delete',
560
+ 'docs[]': files,
561
+ };
562
+ this._file = null;
563
+ this._selected = null;
564
+ this.load(params);
565
+ }
566
+
567
+ _loggedIn(user, groups) {
568
+ if (user == null) {
569
+ return false;
526
570
  }
527
-
528
- _updateSuggestions() {
529
- const autocomplete = this.shadowRoot.getElementById('autocomplete');
530
- const autocompleteLoader = this.shadowRoot.getElementById('autocompleteLoader');
531
- autocomplete.suggestions(autocompleteLoader.lastResponse);
571
+ if (this.group) {
572
+ if (!groups) {
573
+ return false;
574
+ }
575
+ return groups.indexOf(this.group) > -1;
532
576
  }
533
-
534
- _handleEnter(e) {
535
- if (e.keyCode === 13) {
536
- this._filter();
537
- }
577
+ return true;
578
+ }
579
+
580
+ _canModify(allowModification) {
581
+ return allowModification ? '' : 'hidden';
582
+ }
583
+
584
+ _autocomplete(ev) {
585
+ const autocompleteLoader = this.shadowRoot.getElementById('autocompleteLoader');
586
+ autocompleteLoader.params = {
587
+ query: ev.detail.option.text,
588
+ field: this.filterBy,
589
+ };
590
+ autocompleteLoader.generateRequest();
591
+ }
592
+
593
+ _updateSuggestions() {
594
+ const autocomplete = this.shadowRoot.getElementById('autocomplete');
595
+ const autocompleteLoader = this.shadowRoot.getElementById('autocompleteLoader');
596
+ autocomplete.suggestions(autocompleteLoader.lastResponse);
597
+ }
598
+
599
+ _handleEnter(e) {
600
+ if (e.keyCode === 13) {
601
+ this._filter();
538
602
  }
603
+ }
539
604
  }
540
- customElements.define('pb-browse-docs', PbBrowseDocs);
605
+ customElements.define('pb-browse-docs', PbBrowseDocs);