@teipublisher/pb-components 2.26.1-next.3 → 3.0.0-next-4.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.
Files changed (262) hide show
  1. package/.github/workflows/docker-cypress.yml +54 -0
  2. package/.github/workflows/main.yml +6 -4
  3. package/.github/workflows/node.js.yml +56 -21
  4. package/.github/workflows/release.js.yml +19 -17
  5. package/.releaserc.json +1 -1
  6. package/CHANGELOG.md +346 -11
  7. package/Dockerfile +78 -70
  8. package/README.md +112 -4
  9. package/css/components.css +5 -5
  10. package/css/gridjs/mermaid.min.css +1 -1
  11. package/css/leaflet/Control.Geocoder.css +1 -126
  12. package/css/leaflet/images/layers.png +0 -0
  13. package/css/tify/tify.css +6 -5
  14. package/css/tom-select/tom-select.bootstrap4.min.css +1 -1
  15. package/css/tom-select/tom-select.bootstrap5.min.css +1 -1
  16. package/css/tom-select/tom-select.default.min.css +1 -1
  17. package/css/tom-select/tom-select.default.min.css.map +1 -0
  18. package/css/tom-select/tom-select.min.css +1 -1
  19. package/cypress.config.js +84 -0
  20. package/dist/api.html +1 -1
  21. package/dist/css/design-system.css +607 -0
  22. package/dist/demo/bundle-test.html +4 -3
  23. package/dist/demo/components.css +46 -1
  24. package/dist/demo/design-system.html +710 -0
  25. package/dist/demo/dts-client.html +2 -2
  26. package/dist/demo/pb-autocomplete.html +23 -11
  27. package/dist/demo/pb-autocomplete2.html +66 -55
  28. package/dist/demo/pb-autocomplete3.html +17 -8
  29. package/dist/demo/pb-blacklab-highlight.html +28 -11
  30. package/dist/demo/pb-blacklab-results.html +3 -2
  31. package/dist/demo/pb-browse-docs.html +24 -24
  32. package/dist/demo/pb-browse-docs2.html +3 -3
  33. package/dist/demo/pb-clipboard.html +32 -28
  34. package/dist/demo/pb-code-editor.html +6 -6
  35. package/dist/demo/pb-code-highlight.html +63 -63
  36. package/dist/demo/pb-codepen.html +1 -1
  37. package/dist/demo/pb-collapse.html +1 -1
  38. package/dist/demo/pb-collapse2.html +2 -2
  39. package/dist/demo/pb-combo-box.html +135 -130
  40. package/dist/demo/pb-custom-form.html +64 -55
  41. package/dist/demo/pb-dialog.html +12 -6
  42. package/dist/demo/pb-document.html +1 -1
  43. package/dist/demo/pb-download.html +68 -59
  44. package/dist/demo/pb-drawer.html +67 -46
  45. package/dist/demo/pb-drawer2.html +65 -58
  46. package/dist/demo/pb-edit-app.html +2 -2
  47. package/dist/demo/pb-edit-xml.html +1 -1
  48. package/dist/demo/pb-facsimile-2.html +26 -11
  49. package/dist/demo/pb-facsimile-3.html +25 -10
  50. package/dist/demo/pb-facsimile-dedup-test-2.html +48 -0
  51. package/dist/demo/pb-facsimile-dedup-test.html +48 -0
  52. package/dist/demo/pb-facsimile.html +4 -4
  53. package/dist/demo/pb-formula.html +1 -1
  54. package/dist/demo/pb-grid.html +22 -8
  55. package/dist/demo/pb-highlight.html +2 -2
  56. package/dist/demo/pb-i18n-simple.html +1 -0
  57. package/dist/demo/pb-i18n.html +15 -5
  58. package/dist/demo/pb-image-strip-standalone.html +2 -2
  59. package/dist/demo/pb-image-strip-view.html +2 -2
  60. package/dist/demo/pb-leaflet-map.html +3 -3
  61. package/dist/demo/pb-leaflet-map2.html +2 -2
  62. package/dist/demo/pb-leaflet-map3.html +3 -3
  63. package/dist/demo/pb-link.html +1 -1
  64. package/dist/demo/pb-load.html +2 -6
  65. package/dist/demo/pb-login.html +1 -3
  66. package/dist/demo/pb-manage-odds.html +9 -4
  67. package/dist/demo/pb-markdown.html +1 -1
  68. package/dist/demo/pb-media-query.html +2 -2
  69. package/dist/demo/pb-mei.html +2 -2
  70. package/dist/demo/pb-mei2.html +2 -2
  71. package/dist/demo/pb-message.html +2 -3
  72. package/dist/demo/pb-odd-editor.html +54 -52
  73. package/dist/demo/pb-page-header.html +27 -0
  74. package/dist/demo/pb-popover.html +1 -1
  75. package/dist/demo/pb-print-preview.html +2 -2
  76. package/dist/demo/pb-progress.html +4 -4
  77. package/dist/demo/pb-repeat.html +32 -36
  78. package/dist/demo/pb-search.html +16 -5
  79. package/dist/demo/pb-search2.html +4 -4
  80. package/dist/demo/pb-search3.html +3 -3
  81. package/dist/demo/pb-search4.html +3 -3
  82. package/dist/demo/pb-select-feature.html +4 -4
  83. package/dist/demo/pb-select-feature2.html +4 -4
  84. package/dist/demo/pb-select-feature3.html +2 -2
  85. package/dist/demo/pb-select-i18n.html +58 -53
  86. package/dist/demo/pb-select-odd.html +1 -1
  87. package/dist/demo/pb-select.html +190 -75
  88. package/dist/demo/pb-select2.html +91 -37
  89. package/dist/demo/pb-select3.html +109 -41
  90. package/dist/demo/pb-svg.html +1 -1
  91. package/dist/demo/pb-table-grid.html +26 -15
  92. package/dist/demo/pb-tabs.html +15 -7
  93. package/dist/demo/pb-tify.html +7 -7
  94. package/dist/demo/pb-timeline.html +1 -1
  95. package/dist/demo/pb-timeline2.html +1 -1
  96. package/dist/demo/pb-toggle-feature.html +26 -23
  97. package/dist/demo/pb-toggle-feature2.html +4 -4
  98. package/dist/demo/pb-toggle-feature3.html +2 -2
  99. package/dist/demo/pb-toggle-feature4.html +56 -54
  100. package/dist/demo/pb-version.html +2 -2
  101. package/dist/demo/pb-view.html +78 -40
  102. package/dist/demo/pb-view2.html +69 -46
  103. package/dist/demo/pb-view3.html +53 -48
  104. package/dist/demo/pb-view4.html +70 -49
  105. package/dist/demo/pb-zoom.html +2 -2
  106. package/dist/{es-global-bridge-d8ce175d.js → es-global-bridge-D8ZcUcx_.js} +0 -4
  107. package/dist/focus-mixin-VCsFap6b.js +768 -0
  108. package/dist/images/icons.svg +217 -0
  109. package/dist/jinn-codemirror-DETLdm08.js +1 -0
  110. package/dist/lib/openseadragon.min.js +80 -0
  111. package/dist/lib/openseadragon.min.js.map +1 -0
  112. package/dist/pb-code-editor.js +25 -20
  113. package/dist/pb-component-docs.js +414 -3225
  114. package/dist/pb-components-bundle.js +3046 -4402
  115. package/dist/pb-dialog-tklYGWfc.js +121 -0
  116. package/dist/pb-edit-app.js +208 -107
  117. package/dist/pb-elements.json +716 -249
  118. package/dist/pb-facsimile.js +46 -0
  119. package/dist/pb-i18n-C0NDma4h.js +1 -0
  120. package/dist/pb-leaflet-map.js +23 -23
  121. package/dist/pb-mei.js +152 -134
  122. package/dist/pb-mixin-DHoWQheB.js +1 -0
  123. package/dist/pb-odd-editor.js +1671 -1231
  124. package/dist/pb-tify.js +1 -27
  125. package/dist/unsafe-html-D5VGo9Oq.js +1 -0
  126. package/dist/urls-BEONu_g4.js +1 -0
  127. package/eslint.config.mjs +92 -0
  128. package/gh-pages.js +5 -3
  129. package/i18n/common/en.json +6 -0
  130. package/i18n/common/pl.json +2 -2
  131. package/images/icons.svg +217 -0
  132. package/index.html +0 -5
  133. package/lib/leaflet-src.js.map +1 -0
  134. package/lib/leaflet.markercluster-src.js.map +1 -0
  135. package/lib/openseadragon.min.js +6 -6
  136. package/package.json +56 -81
  137. package/pb-elements.json +716 -249
  138. package/rollup.config.mjs +312 -0
  139. package/src/assets/components.css +5 -5
  140. package/src/assets/design-system.css +607 -0
  141. package/src/authority/airtable.js +20 -21
  142. package/src/authority/anton.js +129 -129
  143. package/src/authority/custom.js +70 -27
  144. package/src/authority/geonames.js +38 -32
  145. package/src/authority/gnd.js +50 -42
  146. package/src/authority/kbga.js +136 -134
  147. package/src/authority/metagrid.js +44 -46
  148. package/src/authority/reconciliation.js +66 -68
  149. package/src/authority/registry.js +4 -4
  150. package/src/docs/demo-utils.js +91 -0
  151. package/src/docs/pb-component-docs.js +287 -147
  152. package/src/docs/pb-component-view.js +380 -273
  153. package/src/docs/pb-components-list.js +115 -51
  154. package/src/docs/pb-demo-snippet.js +199 -174
  155. package/src/dts-client.js +306 -303
  156. package/src/dts-select-endpoint.js +125 -85
  157. package/src/parse-date-service.js +184 -135
  158. package/src/pb-ajax.js +175 -173
  159. package/src/pb-authority-lookup.js +198 -158
  160. package/src/pb-autocomplete.js +731 -313
  161. package/src/pb-blacklab-highlight.js +266 -260
  162. package/src/pb-blacklab-results.js +230 -225
  163. package/src/pb-browse-docs.js +601 -484
  164. package/src/pb-browse.js +68 -65
  165. package/src/pb-clipboard.js +97 -76
  166. package/src/pb-code-editor.js +111 -103
  167. package/src/pb-code-highlight.js +234 -204
  168. package/src/pb-codepen.js +81 -73
  169. package/src/pb-collapse.js +265 -152
  170. package/src/pb-combo-box.js +191 -191
  171. package/src/pb-components-bundle.js +1 -7
  172. package/src/pb-components.js +2 -6
  173. package/src/pb-custom-form.js +230 -141
  174. package/src/pb-dialog.js +99 -63
  175. package/src/pb-document.js +118 -91
  176. package/src/pb-download.js +214 -198
  177. package/src/pb-drawer.js +146 -149
  178. package/src/pb-edit-app.js +471 -240
  179. package/src/pb-edit-xml.js +101 -98
  180. package/src/pb-events.js +126 -107
  181. package/src/pb-facs-link.js +130 -101
  182. package/src/pb-facsimile.js +494 -410
  183. package/src/pb-fetch.js +389 -0
  184. package/src/pb-formula.js +152 -154
  185. package/src/pb-geolocation.js +130 -132
  186. package/src/pb-grid-action.js +59 -56
  187. package/src/pb-grid.js +388 -228
  188. package/src/pb-highlight.js +142 -142
  189. package/src/pb-hotkeys.js +40 -42
  190. package/src/pb-i18n.js +115 -127
  191. package/src/pb-icon-button.js +108 -0
  192. package/src/pb-icon.js +283 -0
  193. package/src/pb-image-strip.js +85 -79
  194. package/src/pb-lang.js +142 -57
  195. package/src/pb-leaflet-map.js +551 -483
  196. package/src/pb-link.js +132 -126
  197. package/src/pb-load.js +495 -428
  198. package/src/pb-login.js +303 -248
  199. package/src/pb-manage-odds.js +384 -338
  200. package/src/pb-map-icon.js +90 -90
  201. package/src/pb-map-layer.js +86 -86
  202. package/src/pb-markdown.js +107 -110
  203. package/src/pb-media-query.js +75 -73
  204. package/src/pb-mei.js +523 -303
  205. package/src/pb-message.js +144 -98
  206. package/src/pb-mixin.js +268 -265
  207. package/src/pb-navigation.js +83 -96
  208. package/src/pb-observable.js +39 -39
  209. package/src/pb-odd-editor.js +1209 -948
  210. package/src/pb-odd-elementspec-editor.js +375 -310
  211. package/src/pb-odd-model-editor.js +1189 -941
  212. package/src/pb-odd-parameter-editor.js +269 -170
  213. package/src/pb-odd-rendition-editor.js +184 -131
  214. package/src/pb-page.js +451 -422
  215. package/src/pb-paginate.js +260 -178
  216. package/src/pb-panel.js +217 -183
  217. package/src/pb-popover-themes.js +16 -9
  218. package/src/pb-popover.js +297 -288
  219. package/src/pb-print-preview.js +128 -128
  220. package/src/pb-progress.js +52 -52
  221. package/src/pb-repeat.js +141 -108
  222. package/src/pb-restricted.js +85 -78
  223. package/src/pb-search.js +258 -230
  224. package/src/pb-select-feature.js +210 -126
  225. package/src/pb-select-odd.js +184 -118
  226. package/src/pb-select-template.js +113 -78
  227. package/src/pb-select.js +330 -229
  228. package/src/pb-split-list.js +181 -176
  229. package/src/pb-svg.js +81 -80
  230. package/src/pb-table-column.js +55 -55
  231. package/src/pb-table-grid.js +334 -205
  232. package/src/pb-tabs.js +238 -61
  233. package/src/pb-tify.js +3331 -126
  234. package/src/pb-timeline.js +394 -255
  235. package/src/pb-toggle-feature.js +196 -188
  236. package/src/pb-upload.js +201 -176
  237. package/src/pb-version.js +22 -34
  238. package/src/pb-view-annotate.js +138 -102
  239. package/src/pb-view.js +1722 -1272
  240. package/src/pb-zoom.js +144 -46
  241. package/src/search-result-service.js +256 -223
  242. package/src/seed-element.js +14 -22
  243. package/src/settings.js +4 -4
  244. package/src/theming.js +98 -91
  245. package/src/urls.js +403 -289
  246. package/src/utils.js +53 -51
  247. package/vite.config.js +86 -0
  248. package/css/pb-styles.css +0 -51
  249. package/dist/iron-form-3b8dcaa7.js +0 -210
  250. package/dist/jinn-codemirror-da0e2d1f.js +0 -1
  251. package/dist/paper-checkbox-515a5284.js +0 -1597
  252. package/dist/paper-icon-button-b1d31571.js +0 -398
  253. package/dist/paper-listbox-a3b7175c.js +0 -1265
  254. package/dist/pb-i18n-0611135a.js +0 -1
  255. package/dist/pb-mixin-b1caa22e.js +0 -158
  256. package/dist/polymer-hack.js +0 -1
  257. package/dist/vaadin-element-mixin-fe4a4883.js +0 -527
  258. package/lib/Control.Geocoder.min.js +0 -2
  259. package/lib/Control.Geocoder.min.js.map +0 -1
  260. package/src/assets/pb-styles.css +0 -51
  261. package/src/pb-light-dom.js +0 -41
  262. package/src/polymer-hack.js +0 -6
@@ -1,14 +1,8 @@
1
- import { LitElement, html, css } from 'lit-element';
1
+ import { LitElement, html, css, nothing } from 'lit';
2
2
  import { pbMixin, waitOnce } from './pb-mixin.js';
3
3
  import { translate } from './pb-i18n.js';
4
- import '@polymer/paper-input/paper-input.js';
5
- import '@polymer/paper-button';
6
- import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
7
- import '@polymer/paper-listbox';
8
- import '@polymer/paper-checkbox';
9
- import '@polymer/paper-dialog';
10
- import '@polymer/paper-dialog-scrollable';
11
- import '@polymer/iron-form';
4
+ import './pb-icon.js';
5
+ import './pb-dialog.js';
12
6
 
13
7
  /**
14
8
  * Editor component for the App Generator. Allows to edit all settings for an application.
@@ -17,246 +11,483 @@ import '@polymer/iron-form';
17
11
  * @fires pb-end-update - Fired after the element has finished updating its content
18
12
  */
19
13
  export class PbEditApp extends pbMixin(LitElement) {
20
- static get properties() {
21
- return {
22
- ...super.properties,
23
- error: {
24
- type: String
25
- },
26
- url: {
27
- type: String
28
- },
29
- templates: {
30
- type: Array
31
- },
32
- odds: {
33
- type: Array
34
- }
35
- };
36
- }
14
+ static get properties() {
15
+ return {
16
+ ...super.properties,
17
+ error: {
18
+ type: String,
19
+ },
20
+ url: {
21
+ type: String,
22
+ },
23
+ templates: {
24
+ type: Array,
25
+ },
26
+ odds: {
27
+ type: Array,
28
+ },
29
+ _templateValue: {
30
+ type: String,
31
+ },
32
+ _defaultViewValue: {
33
+ type: String,
34
+ },
35
+ _indexValue: {
36
+ type: String,
37
+ },
38
+ };
39
+ }
37
40
 
38
- constructor() {
39
- super();
40
- this.templates = [];
41
- this.odds = [];
42
- }
41
+ constructor() {
42
+ super();
43
+ this.templates = [];
44
+ this.odds = [];
45
+ this._templateValue = 'view.html';
46
+ this._defaultViewValue = 'div';
47
+ this._indexValue = 'tei:div';
48
+ }
49
+
50
+ connectedCallback() {
51
+ super.connectedCallback();
52
+ }
53
+
54
+ firstUpdated() {
55
+ const form = this.shadowRoot.getElementById('form');
56
+ waitOnce('pb-page-ready', detail => {
57
+ const endpoint = detail.endpoint;
58
+ const templatesUrl = this.minApiVersion('1.0.0')
59
+ ? `${endpoint}/api/templates`
60
+ : `${endpoint}/modules/lib/components-list-templates.xql`;
61
+ const oddsUrl = this.minApiVersion('1.0.0')
62
+ ? `${endpoint}/api/odd`
63
+ : `${endpoint}/modules/lib/components-list-odds.xql`;
64
+ const action = this.minApiVersion('1.0.0')
65
+ ? `${endpoint}/api/apps/generate`
66
+ : `${endpoint}/modules/components-generate.xql`;
67
+
68
+ if (form) {
69
+ form.action = action;
70
+ }
43
71
 
44
- connectedCallback() {
45
- super.connectedCallback();
72
+ fetch(templatesUrl, {
73
+ method: 'GET',
74
+ mode: 'cors',
75
+ credentials: 'same-origin',
76
+ })
77
+ .then(response => response.json())
78
+ .then(json => {
79
+ const list = Array.isArray(json) ? json : [];
80
+ this.templates = list;
81
+ if (!list.find(item => item.name === this._templateValue)) {
82
+ this._templateValue = list.length ? list[0].name : '';
83
+ }
84
+ this.requestUpdate();
85
+ })
86
+ .catch(error => console.error('<pb-edit-app> Failed to load templates', error));
87
+
88
+ fetch(oddsUrl, {
89
+ method: 'GET',
90
+ mode: 'cors',
91
+ credentials: 'same-origin',
92
+ })
93
+ .then(response => response.json())
94
+ .then(json => {
95
+ this.odds = Array.isArray(json) ? json : [];
96
+ this.requestUpdate();
97
+ })
98
+ .catch(error => console.error('<pb-edit-app> Failed to load odds list', error));
99
+ });
100
+
101
+ if (form) {
102
+ form.addEventListener('submit', this._handleSubmit.bind(this));
46
103
  }
104
+ }
47
105
 
48
- firstUpdated() {
49
- const form = this.shadowRoot.getElementById('form');
50
- const defaultView = this.shadowRoot.getElementById('defaultView');
51
- const index = this.shadowRoot.getElementById('index');
52
- const template = this.shadowRoot.getElementById('template');
53
- this.subscribeTo('pb-i18n-update', (options) => {
54
- // clear paper-listbox selection after language updates
55
- const defaultViewListbox = this.shadowRoot.querySelector('#defaultView paper-listbox');
56
- let old = defaultViewListbox.selected;
57
- defaultViewListbox.selected = undefined;
58
- defaultViewListbox.selected = old;
59
-
60
- const indexListbox = this.shadowRoot.querySelector('#index paper-listbox');
61
- old = indexListbox.selected;
62
- indexListbox.selected = undefined;
63
- indexListbox.selected = old;
64
- }, []);
65
- waitOnce('pb-page-ready', (detail) => {
66
- let url;
67
- if (this.minApiVersion('1.0.0')) {
68
- url = `${detail.endpoint}/api/templates`;
69
- } else {
70
- url = `${detail.endpoint}/modules/lib/components-list-templates.xql`;
71
- }
72
- fetch(url, {
73
- method: 'GET',
74
- mode: 'cors',
75
- credentials: 'same-origin'
76
- })
77
- .then((response) => response.json())
78
- .then(json => { this.templates = json });
79
-
80
- if (this.minApiVersion('1.0.0')) {
81
- url = `${detail.endpoint}/api/odd`;
82
- } else {
83
- url = `${detail.endpoint}/modules/lib/components-list-odds.xql`;
84
- }
85
- fetch(url, {
86
- method: 'GET',
87
- mode: 'cors',
88
- credentials: 'same-origin'
89
- })
90
- .then((response) => response.json())
91
- .then(json => { this.odds = json });
92
-
93
- const htmlForm = this.shadowRoot.querySelector('form');
94
- if (this.minApiVersion('1.0.0')) {
95
- htmlForm.action = `${detail.endpoint}/api/apps/generate`;
96
- } else {
97
- htmlForm.action = `${detail.endpoint}/modules/components-generate.xql`;
98
- }
99
- });
100
- form.addEventListener('iron-form-presubmit', function () {
101
- const view = defaultView.selectedItem.getAttribute('value');
102
- this.request.body['default-view'] = view;
103
- this.request.body.index = index.selectedItem.getAttribute('value');
104
- this.request.body.template = template.selectedItem.getAttribute('value');
105
- });
106
- form.addEventListener('iron-form-response', (event) => {
107
- console.log(event);
108
- event.detail.completes.then((r) => {
109
- this.emitTo('pb-end-update');
110
- const result = r.parseResponse();
111
- console.log('<pb-edit-app> Received response: %o', result);
112
- if (result.target) {
113
- const baseURL = window.location.href.replace(/^(.*)\/tei-publisher\/.*/, "$1");
114
- this.url = baseURL + '/' + this.shadowRoot.querySelector('paper-input[name=abbrev]').value;
115
- this.error = null;
116
- } else {
117
- this.error = result.description;
118
- }
119
- this.shadowRoot.getElementById('dialog').open();
120
- });
121
- }
122
- );
123
- form.addEventListener('iron-form-error', (event) => {
124
- this.emitTo('pb-end-update');
125
-
126
- console.log('<pb-edit-app> Received response: %o', event.detail.request.response);
127
- this.error = event.detail.request.response.description;
128
- this.shadowRoot.getElementById('dialog').open();
129
- });
130
- form.addEventListener('iron-form-invalid', () =>
131
- this.emitTo('pb-end-update')
132
- );
106
+ _doSubmit() {
107
+ const form = this.shadowRoot.getElementById('form');
108
+ if (!form) {
109
+ return;
110
+ }
111
+ if (form.requestSubmit) {
112
+ form.requestSubmit();
113
+ } else {
114
+ form.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));
133
115
  }
116
+ }
134
117
 
135
- _doSubmit() {
136
- this.emitTo('pb-start-update');
137
- const form = this.shadowRoot.getElementById('form');
138
- form.submit();
118
+ _renderTextField({
119
+ id,
120
+ name,
121
+ type = 'text',
122
+ required = false,
123
+ pattern,
124
+ placeholder = '',
125
+ label,
126
+ }) {
127
+ return html`
128
+ <label class="pb-field" for="${id}">
129
+ <span class="pb-field__label">${label}</span>
130
+ <input
131
+ id="${id}"
132
+ class="pb-input"
133
+ type="${type}"
134
+ name="${name}"
135
+ ?required=${required}
136
+ pattern=${pattern ? pattern : nothing}
137
+ placeholder="${placeholder}"
138
+ />
139
+ </label>
140
+ `;
141
+ }
142
+
143
+ _onTemplateChange(event) {
144
+ this._templateValue = event.target.value;
145
+ }
146
+
147
+ _onDefaultViewChange(event) {
148
+ this._defaultViewValue = event.target.value;
149
+ }
150
+
151
+ _onIndexChange(event) {
152
+ this._indexValue = event.target.value;
153
+ }
154
+
155
+ async _handleSubmit(event) {
156
+ event.preventDefault();
157
+ const form = event.currentTarget;
158
+ if (form.reportValidity && !form.reportValidity()) {
159
+ return;
139
160
  }
140
161
 
141
- render() {
142
- return html`
143
- <iron-form id="form">
144
- <form method="POST" accept="application/json" enctype="application/json">
145
- <fieldset>
146
- <legend>${translate('document.selectODD')}</legend>
147
- ${ this.odds.map(odd => html`<paper-checkbox name="odd" value="${odd.name}">${odd.label}</paper-checkbox>`)}
148
- </fieldset>
149
- <paper-input name="uri" type="url" required placeholder="https://e-editiones.org/apps/my-simple-app"
150
- label="${translate('appgen.uri')}" auto-validate></paper-input>
151
- <paper-input id="abbrev" name="abbrev" pattern="[a-zA-Z0-9-_]+" required placeholder="${translate('appgen.abbrev.placeholder')}"
152
- label="${translate('appgen.abbrev.label')}" auto-validate></paper-input>
153
- <paper-input name="data-collection" pattern="[a-zA-Z0-9-_/]+" placeholder="data"
154
- label="${translate('appgen.collection')}" auto-validate></paper-input>
155
- <paper-input name="title" required placeholder="${translate('appgen.title.label')}"
156
- label="${translate('appgen.title.help')}"></paper-input>
157
- <fieldset>
158
- <legend>${translate('appgen.template.help')}</legend>
159
- <paper-dropdown-menu id="template" label="${translate('appgen.template.label')}" name="template">
160
- <paper-listbox slot="dropdown-content" class="dropdown-content" attr-for-selected="value" selected="view.html">
161
- ${this.templates.map(t => html`<paper-item value="${t.name}">${t.title}</paper-item>`)}
162
- </paper-listbox>
163
- </paper-dropdown-menu>
164
- </fieldset>
165
- <fieldset>
166
- <legend>${translate('appgen.view.help')}</legend>
167
- <paper-dropdown-menu id="defaultView" label="${translate('appgen.label')}" name="default-view">
168
- <paper-listbox slot="dropdown-content" class="dropdown-content" selected="div" attr-for-selected="value">
169
- <paper-item value="div">${translate('appgen.view.div')}</paper-item>
170
- <paper-item value="page">${translate('appgen.view.page')}</paper-item>
171
- </paper-listbox>
172
- </paper-dropdown-menu>
173
- </fieldset>
174
- <fieldset>
175
- <legend>${translate('appgen.index.help')}</legend>
176
- <paper-dropdown-menu id="index" label="${translate('appgen.index.label')}" name="index">
177
- <paper-listbox slot="dropdown-content" class="dropdown-content" selected="tei:div" attr-for-selected="value">
178
- <paper-item value="tei:div">${translate('appgen.index.index-div')}</paper-item>
179
- <paper-item value="tei:text">${translate('appgen.index.index-text')}</paper-item>
180
- </paper-listbox>
181
- </paper-dropdown-menu>
182
- </fieldset>
183
- <fieldset>
184
- <legend>${translate('appgen.account.user')}</legend>
185
- <paper-input name="owner" required placeholder="${translate('login.user')}"
186
- label="${translate('appgen.account.owner')}" auto-validate></paper-input>
187
- <paper-input name="password" type="password" required placeholder="${translate('login.password')}"
188
- label="${translate('appgen.account.password')}" auto-validate></paper-input>
189
- </fieldset>
190
- <paper-button id="submit" @click="${this._doSubmit}"><iron-icon icon="save"></iron-icon> ${translate('appgen.submit')}</paper-button>
191
- </form>
192
- </iron-form>
193
- <paper-dialog id="dialog">
194
- <h2>${translate('appgen.dialog.title')}</h2>
195
- <div id="dialogContent">
196
- ${
197
- this.error ?
198
- html`<div id="error">${this.error}</div>` :
199
- html`<a href="${this.url}" target="_blank">
200
- <paper-button><iron-icon icon="icons:open-in-new"></iron-icon> ${translate('appgen.open')}</paper-button>
201
- </a>
202
- <p>${translate('appgen.success')}</p>`
203
- }
204
- </div>
205
- <div class="buttons">
206
- <paper-button dialog-dismiss autofocus>${translate('dialogs.close')}</paper-button>
207
- </div>
208
- </paper-dialog>
209
- `;
162
+ this.emitTo('pb-start-update');
163
+
164
+ const payload = this._collectFormData(form);
165
+ const action = form.action || '';
166
+
167
+ try {
168
+ const response = await fetch(action, {
169
+ method: form.method || 'POST',
170
+ headers: {
171
+ 'content-type': 'application/json',
172
+ },
173
+ credentials: 'same-origin',
174
+ body: JSON.stringify(payload),
175
+ });
176
+
177
+ const contentType = response.headers.get('content-type') || '';
178
+ const isJson = contentType.includes('application/json');
179
+ const data = isJson ? await response.json() : await response.text();
180
+
181
+ if (!response.ok) {
182
+ const error = data && typeof data === 'object' ? data : { description: data };
183
+ throw Object.assign(new Error(error.description || response.statusText), { result: error });
184
+ }
185
+
186
+ this._handleSubmitSuccess(data, form);
187
+ } catch (error) {
188
+ this._handleSubmitError(error);
210
189
  }
190
+ }
211
191
 
212
- static get styles() {
213
- return css`
214
- :host {
215
- display: block;
216
- }
217
- paper-dropdown-menu {
218
- width: 100%;
219
- max-width: 864px;
220
- }
221
- fieldset {
222
- margin-top: 16px;
223
- margin-bottom: 16px;
224
- padding: 0;
225
- border: 0;
226
- }
227
- legend {
228
- color: #909090;
229
- }
230
- paper-checkbox {
231
- display: block;
232
- margin-left: 20px;
233
- margin-top: 10px;
234
- }
235
- paper-dialog {
236
- min-width: 420px;
237
- max-width: 640px;
238
- min-height: 128px;
239
- }
240
-
241
- paper-dialog h2 {
242
- background-color: #607D8B;
243
- padding: 16px 8px;
244
- margin-top: 0;
245
- color: #F0F0F0;
246
- }
247
-
248
- .content {
249
- display: flex;
250
- flex-direction: row;
251
- justify-content: space-between;
252
- align-items: center;
253
- }
254
-
255
- .content a {
256
- display: block;
257
- flex: 1 0;
258
- }
259
- `;
192
+ _collectFormData(form) {
193
+ const formData = new FormData(form);
194
+ const payload = {};
195
+ Array.from(form.elements || [])
196
+ .filter(el => el.name && !el.disabled && !el.closest('[disabled]'))
197
+ .forEach(element => {
198
+ if (!(element.name in payload)) {
199
+ payload[element.name] = null;
200
+ }
201
+ });
202
+ formData.forEach((value, key) => {
203
+ if (Object.prototype.hasOwnProperty.call(payload, key) && payload[key] != null) {
204
+ if (Array.isArray(payload[key])) {
205
+ payload[key].push(value);
206
+ } else {
207
+ payload[key] = [payload[key], value];
208
+ }
209
+ } else {
210
+ payload[key] = value;
211
+ }
212
+ });
213
+ return payload;
214
+ }
215
+
216
+ _handleSubmitSuccess(result, form) {
217
+ this.emitTo('pb-end-update');
218
+
219
+ if (result && result.target) {
220
+ const baseURL = window.location.href.replace(/^(.*)\/tei-publisher\/.*/, '$1');
221
+ const abbrev = form.querySelector('input[name=abbrev]');
222
+ this.url = `${baseURL}/${abbrev ? abbrev.value : ''}`;
223
+ this.error = null;
224
+ } else {
225
+ this.error = result && result.description ? result.description : 'Request failed';
226
+ this.url = null;
260
227
  }
228
+
229
+ this._openDialog();
230
+ }
231
+
232
+ _handleSubmitError(error) {
233
+ this.emitTo('pb-end-update');
234
+ const description = error?.result?.description || error?.message || 'Request failed';
235
+ this.error = description;
236
+ this.url = null;
237
+ this._openDialog();
238
+ }
239
+
240
+ _openDialog() {
241
+ const dialog = this.shadowRoot.getElementById('dialog');
242
+ dialog?.openDialog();
243
+ }
244
+
245
+ render() {
246
+ return html`
247
+ <form id="form" method="POST" accept="application/json" enctype="application/json">
248
+ <fieldset class="pb-fieldset">
249
+ <legend>${translate('document.selectODD')}</legend>
250
+ ${this.odds.map(
251
+ odd => html`
252
+ <label class="pb-checkbox">
253
+ <input
254
+ type="checkbox"
255
+ name="odd"
256
+ .value="${odd.name}"
257
+ ?checked=${Boolean(odd.checked)}
258
+ />
259
+ <span>${odd.label}</span>
260
+ </label>
261
+ `,
262
+ )}
263
+ </fieldset>
264
+
265
+ ${this._renderTextField({
266
+ id: 'uri',
267
+ name: 'uri',
268
+ type: 'url',
269
+ required: true,
270
+ placeholder: 'https://e-editiones.org/apps/my-simple-app',
271
+ label: translate('appgen.uri'),
272
+ })}
273
+ ${this._renderTextField({
274
+ id: 'abbrev',
275
+ name: 'abbrev',
276
+ pattern: '[a-zA-Z0-9-_]+',
277
+ required: true,
278
+ placeholder: translate('appgen.abbrev.placeholder'),
279
+ label: translate('appgen.abbrev.label'),
280
+ })}
281
+ ${this._renderTextField({
282
+ id: 'data-collection',
283
+ name: 'data-collection',
284
+ pattern: '[a-zA-Z0-9-_/]+',
285
+ placeholder: 'data',
286
+ label: translate('appgen.collection'),
287
+ })}
288
+ ${this._renderTextField({
289
+ id: 'title',
290
+ name: 'title',
291
+ required: true,
292
+ placeholder: translate('appgen.title.label'),
293
+ label: translate('appgen.title.help'),
294
+ })}
295
+
296
+ <fieldset class="pb-fieldset">
297
+ <legend>${translate('appgen.template.help')}</legend>
298
+ <label class="pb-field" for="template">
299
+ <span class="pb-field__label">${translate('appgen.template.label')}</span>
300
+ <select
301
+ id="template"
302
+ class="pb-select"
303
+ name="template"
304
+ .value=${this._templateValue || ''}
305
+ @change=${this._onTemplateChange}
306
+ >
307
+ ${this.templates.map(t => html`<option value="${t.name}">${t.title}</option>`)}
308
+ </select>
309
+ </label>
310
+ </fieldset>
311
+
312
+ <fieldset class="pb-fieldset">
313
+ <legend>${translate('appgen.view.help')}</legend>
314
+ <label class="pb-field" for="defaultView">
315
+ <span class="pb-field__label">${translate('appgen.label')}</span>
316
+ <select
317
+ id="defaultView"
318
+ class="pb-select"
319
+ name="default-view"
320
+ .value=${this._defaultViewValue || ''}
321
+ @change=${this._onDefaultViewChange}
322
+ >
323
+ <option value="div">${translate('appgen.view.div')}</option>
324
+ <option value="page">${translate('appgen.view.page')}</option>
325
+ </select>
326
+ </label>
327
+ </fieldset>
328
+
329
+ <fieldset class="pb-fieldset">
330
+ <legend>${translate('appgen.index.help')}</legend>
331
+ <label class="pb-field" for="index">
332
+ <span class="pb-field__label">${translate('appgen.index.label')}</span>
333
+ <select
334
+ id="index"
335
+ class="pb-select"
336
+ name="index"
337
+ .value=${this._indexValue || ''}
338
+ @change=${this._onIndexChange}
339
+ >
340
+ <option value="tei:div">${translate('appgen.index.index-div')}</option>
341
+ <option value="tei:text">${translate('appgen.index.index-text')}</option>
342
+ </select>
343
+ </label>
344
+ </fieldset>
345
+
346
+ <fieldset class="pb-fieldset">
347
+ <legend>${translate('appgen.account.user')}</legend>
348
+ ${this._renderTextField({
349
+ id: 'owner',
350
+ name: 'owner',
351
+ required: true,
352
+ placeholder: translate('login.user'),
353
+ label: translate('appgen.account.owner'),
354
+ })}
355
+ ${this._renderTextField({
356
+ id: 'password',
357
+ name: 'password',
358
+ type: 'password',
359
+ required: true,
360
+ placeholder: translate('login.password'),
361
+ label: translate('appgen.account.password'),
362
+ })}
363
+ </fieldset>
364
+ <button
365
+ id="submit"
366
+ class="pb-button pb-button--contained"
367
+ type="button"
368
+ @click="${this._doSubmit}"
369
+ >
370
+ <pb-icon icon="save"></pb-icon>
371
+ ${translate('appgen.submit')}
372
+ </button>
373
+ </form>
374
+ <pb-dialog id="dialog" title="${translate('appgen.dialog.title')}">
375
+ <div id="dialogContent">
376
+ ${this.error
377
+ ? html`<div id="error">${this.error}</div>`
378
+ : html`<a href="${this.url}" target="_blank" class="pb-button pb-button--text">
379
+ <pb-icon icon="icons:open-in-new"></pb-icon>
380
+ ${translate('appgen.open')}
381
+ </a>
382
+ <p>${translate('appgen.success')}</p>`}
383
+ </div>
384
+ <div slot="footer" class="buttons">
385
+ <button class="pb-button pb-button--text" type="button" rel="prev" autofocus>
386
+ ${translate('dialogs.close')}
387
+ </button>
388
+ </div>
389
+ </pb-dialog>
390
+ `;
391
+ }
392
+
393
+ static get styles() {
394
+ return css`
395
+ :host {
396
+ display: block;
397
+ }
398
+ .pb-fieldset {
399
+ margin: 16px 0;
400
+ padding: 0;
401
+ border: 0;
402
+ }
403
+ .pb-fieldset legend {
404
+ color: #909090;
405
+ font-size: 0.85rem;
406
+ text-transform: uppercase;
407
+ letter-spacing: 0.04em;
408
+ margin-bottom: 8px;
409
+ }
410
+ .pb-checkbox {
411
+ display: block;
412
+ margin-left: 20px;
413
+ margin-top: 10px;
414
+ font-size: 0.95rem;
415
+ color: rgba(0, 0, 0, 0.87);
416
+ cursor: pointer;
417
+ }
418
+ .pb-checkbox input {
419
+ margin-right: 8px;
420
+ }
421
+ .pb-field {
422
+ display: flex;
423
+ flex-direction: column;
424
+ gap: 0.45rem;
425
+ margin-bottom: 1rem;
426
+ max-width: 864px;
427
+ }
428
+ .pb-field__label {
429
+ font-size: 0.85rem;
430
+ font-weight: 600;
431
+ letter-spacing: 0.04em;
432
+ text-transform: uppercase;
433
+ color: rgba(0, 0, 0, 0.6);
434
+ }
435
+ .pb-input,
436
+ .pb-select {
437
+ height: var(--pb-input-height, 48px);
438
+ padding: 0.5rem 0.75rem;
439
+ border: 1px solid rgba(0, 0, 0, 0.16);
440
+ border-radius: 8px;
441
+ font: inherit;
442
+ color: inherit;
443
+ background: #fff;
444
+ transition: border-color 120ms ease, box-shadow 120ms ease;
445
+ line-height: 1.4;
446
+ }
447
+ .pb-input::placeholder {
448
+ color: rgba(0, 0, 0, 0.4);
449
+ }
450
+ .pb-input:focus,
451
+ .pb-select:focus {
452
+ outline: none;
453
+ border-color: #1976d2;
454
+ box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.16);
455
+ }
456
+ .pb-select {
457
+ appearance: none;
458
+ background-image: linear-gradient(45deg, transparent 50%, rgba(0, 0, 0, 0.4) 50%),
459
+ linear-gradient(135deg, rgba(0, 0, 0, 0.4) 50%, transparent 50%),
460
+ linear-gradient(to right, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
461
+ background-position: calc(100% - 18px) calc(0.6em + 2px),
462
+ calc(100% - 13px) calc(0.6em + 2px), calc(100% - 2.5rem) 0.5em;
463
+ background-size: 5px 5px, 5px 5px, 1px 2.25em;
464
+ background-repeat: no-repeat;
465
+ }
466
+ paper-dialog {
467
+ min-width: 420px;
468
+ max-width: 640px;
469
+ min-height: 128px;
470
+ }
471
+
472
+ paper-dialog h2 {
473
+ background-color: #607d8b;
474
+ padding: 16px 8px;
475
+ margin-top: 0;
476
+ color: #f0f0f0;
477
+ }
478
+
479
+ .content {
480
+ display: flex;
481
+ flex-direction: row;
482
+ justify-content: space-between;
483
+ align-items: center;
484
+ }
485
+
486
+ .content a {
487
+ display: block;
488
+ flex: 1 0;
489
+ }
490
+ `;
491
+ }
261
492
  }
262
- customElements.define('pb-edit-app', PbEditApp);
493
+ customElements.define('pb-edit-app', PbEditApp);