@teipublisher/pb-components 2.25.5 → 2.25.6

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 (128) 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 +8 -0
  5. package/Dockerfile +78 -70
  6. package/css/components.css +5 -5
  7. package/dist/demo/pb-drawer2.html +1 -1
  8. package/dist/demo/pb-leaflet-map.html +1 -1
  9. package/dist/demo/pb-repeat.html +1 -3
  10. package/dist/demo/pb-view3.html +1 -1
  11. package/dist/{paper-icon-button-0fb125c4.js → paper-icon-button-72125e67.js} +1 -1
  12. package/dist/pb-code-editor.js +25 -20
  13. package/dist/pb-component-docs.js +58 -54
  14. package/dist/pb-components-bundle.js +1827 -1520
  15. package/dist/pb-edit-app.js +167 -107
  16. package/dist/pb-elements.json +54 -54
  17. package/dist/{pb-i18n-0611135a.js → pb-i18n-4cc00bfe.js} +1 -1
  18. package/dist/pb-leaflet-map.js +23 -23
  19. package/dist/pb-mei.js +56 -41
  20. package/dist/{pb-mixin-b1caa22e.js → pb-mixin-886ece32.js} +1 -1
  21. package/dist/pb-odd-editor.js +925 -758
  22. package/dist/pb-tify.js +2 -2
  23. package/dist/{vaadin-element-mixin-859a0132.js → vaadin-element-mixin-ad07ba25.js} +88 -61
  24. package/gh-pages.js +5 -3
  25. package/package.json +2 -2
  26. package/pb-elements.json +54 -54
  27. package/src/assets/components.css +5 -5
  28. package/src/authority/airtable.js +20 -21
  29. package/src/authority/anton.js +129 -129
  30. package/src/authority/custom.js +23 -21
  31. package/src/authority/geonames.js +38 -32
  32. package/src/authority/gnd.js +47 -42
  33. package/src/authority/kbga.js +137 -134
  34. package/src/authority/metagrid.js +44 -46
  35. package/src/authority/reconciliation.js +66 -67
  36. package/src/authority/registry.js +4 -4
  37. package/src/docs/pb-component-docs.js +2 -2
  38. package/src/docs/pb-component-view.js +5 -5
  39. package/src/docs/pb-components-list.js +2 -2
  40. package/src/docs/pb-demo-snippet.js +2 -2
  41. package/src/dts-client.js +299 -297
  42. package/src/dts-select-endpoint.js +90 -82
  43. package/src/parse-date-service.js +184 -135
  44. package/src/pb-ajax.js +171 -167
  45. package/src/pb-authority-lookup.js +96 -81
  46. package/src/pb-autocomplete.js +292 -280
  47. package/src/pb-blacklab-highlight.js +264 -259
  48. package/src/pb-blacklab-results.js +236 -221
  49. package/src/pb-browse-docs.js +540 -475
  50. package/src/pb-browse.js +68 -65
  51. package/src/pb-clipboard.js +79 -76
  52. package/src/pb-code-editor.js +110 -102
  53. package/src/pb-code-highlight.js +209 -204
  54. package/src/pb-codepen.js +79 -72
  55. package/src/pb-collapse.js +149 -146
  56. package/src/pb-combo-box.js +190 -190
  57. package/src/pb-components-bundle.js +1 -1
  58. package/src/pb-custom-form.js +150 -149
  59. package/src/pb-document.js +89 -90
  60. package/src/pb-download.js +208 -195
  61. package/src/pb-drawer.js +145 -148
  62. package/src/pb-edit-app.js +301 -229
  63. package/src/pb-edit-xml.js +99 -96
  64. package/src/pb-events.js +114 -107
  65. package/src/pb-facs-link.js +104 -102
  66. package/src/pb-facsimile.js +411 -413
  67. package/src/pb-formula.js +151 -153
  68. package/src/pb-geolocation.js +129 -131
  69. package/src/pb-grid-action.js +53 -56
  70. package/src/pb-grid.js +231 -228
  71. package/src/pb-highlight.js +140 -140
  72. package/src/pb-hotkeys.js +40 -42
  73. package/src/pb-i18n.js +101 -104
  74. package/src/pb-image-strip.js +84 -78
  75. package/src/pb-lang.js +83 -70
  76. package/src/pb-leaflet-map.js +488 -485
  77. package/src/pb-link.js +126 -124
  78. package/src/pb-load.js +431 -426
  79. package/src/pb-login.js +275 -254
  80. package/src/pb-manage-odds.js +364 -318
  81. package/src/pb-map-icon.js +89 -89
  82. package/src/pb-map-layer.js +85 -85
  83. package/src/pb-markdown.js +90 -99
  84. package/src/pb-media-query.js +74 -72
  85. package/src/pb-mei.js +306 -295
  86. package/src/pb-message.js +143 -130
  87. package/src/pb-mixin.js +269 -264
  88. package/src/pb-navigation.js +80 -82
  89. package/src/pb-observable.js +38 -38
  90. package/src/pb-odd-editor.js +1056 -958
  91. package/src/pb-odd-elementspec-editor.js +348 -297
  92. package/src/pb-odd-model-editor.js +1058 -898
  93. package/src/pb-odd-parameter-editor.js +200 -178
  94. package/src/pb-odd-rendition-editor.js +136 -124
  95. package/src/pb-page.js +432 -422
  96. package/src/pb-paginate.js +202 -190
  97. package/src/pb-panel.js +191 -179
  98. package/src/pb-popover-themes.js +7 -5
  99. package/src/pb-popover.js +296 -287
  100. package/src/pb-print-preview.js +127 -127
  101. package/src/pb-progress.js +49 -49
  102. package/src/pb-repeat.js +105 -104
  103. package/src/pb-restricted.js +84 -77
  104. package/src/pb-search.js +238 -221
  105. package/src/pb-select-feature.js +127 -120
  106. package/src/pb-select-odd.js +132 -124
  107. package/src/pb-select-template.js +89 -78
  108. package/src/pb-select.js +251 -227
  109. package/src/pb-split-list.js +179 -174
  110. package/src/pb-svg.js +80 -79
  111. package/src/pb-table-column.js +54 -54
  112. package/src/pb-table-grid.js +221 -203
  113. package/src/pb-tabs.js +61 -63
  114. package/src/pb-tify.js +154 -154
  115. package/src/pb-timeline.js +271 -229
  116. package/src/pb-toggle-feature.js +198 -185
  117. package/src/pb-upload.js +184 -174
  118. package/src/pb-version.js +30 -30
  119. package/src/pb-view-annotate.js +132 -98
  120. package/src/pb-view.js +1282 -1263
  121. package/src/pb-zoom.js +40 -40
  122. package/src/polymer-hack.js +1 -1
  123. package/src/search-result-service.js +256 -223
  124. package/src/seed-element.js +13 -20
  125. package/src/settings.js +4 -4
  126. package/src/theming.js +91 -91
  127. package/src/urls.js +289 -289
  128. package/src/utils.js +53 -51
@@ -1,10 +1,10 @@
1
1
  // @ts-nocheck
2
2
  import { LitElement, html, css } from 'lit-element';
3
- import { supported as fsSupported, fileSave } from "browser-fs-access";
4
- import { pbMixin, waitOnce } from './pb-mixin.js';
5
- import { pbHotkeys } from './pb-hotkeys.js';
3
+ import { supported as fsSupported, fileSave } from 'browser-fs-access';
6
4
  import { repeat } from 'lit-html/directives/repeat';
7
5
  import { ifDefined } from 'lit-html/directives/if-defined';
6
+ import { pbMixin, waitOnce } from './pb-mixin.js';
7
+ import { pbHotkeys } from './pb-hotkeys.js';
8
8
 
9
9
  import '@vaadin/vaadin-tabs/vaadin-tabs';
10
10
  import '@vaadin/vaadin-tabs/vaadin-tab';
@@ -19,11 +19,10 @@ import '@polymer/paper-item/paper-item';
19
19
  import '@cwmr/paper-autocomplete/paper-autocomplete';
20
20
  import './pb-collapse';
21
21
  import '@polymer/paper-checkbox/paper-checkbox';
22
- import './pb-odd-elementspec-editor.js';
22
+ import { PbOddElementspecEditor } from './pb-odd-elementspec-editor.js';
23
23
  import './pb-message.js';
24
24
 
25
- import { get as i18n, translate } from "./pb-i18n.js";
26
- import { PbOddElementspecEditor } from "./pb-odd-elementspec-editor";
25
+ import { get as i18n, translate } from './pb-i18n.js';
27
26
 
28
27
  /**
29
28
  * ODD editor component
@@ -35,905 +34,1002 @@ import { PbOddElementspecEditor } from "./pb-odd-elementspec-editor";
35
34
  * @cssprop --pb-heading-line-height
36
35
  */
37
36
  export class PbOddEditor extends pbHotkeys(pbMixin(LitElement)) {
38
-
39
- static get styles() {
40
- return css`
41
- :host {
42
- display: flex;
43
- /*margin: 30px 20px;*/
44
- margin:0;
45
- padding:0;
46
- height:auto;
47
- }
48
-
49
- #layout {
50
- width: 100%;
51
- display: grid;
52
- grid-template-columns: auto 1fr;
53
- grid-template-rows: auto 1fr;
54
- }
55
-
56
- #drawer {
57
- grid-column: 1 / 1;
58
- min-width: 320px;
59
- }
60
-
61
- #navlist {
62
- grid-column: 1 / 1;
63
- grid-row: 2 / 2;
64
- overflow: auto;
65
- height: 100%;
66
- }
67
-
68
- .specs {
69
- grid-column: 2 / 2;
70
- grid-row: 1 / span 2;
71
- overflow: auto;
72
- }
73
-
74
- section{
75
- padding:20px;
76
- }
77
-
78
- h3, h4 {
79
- font-family: var(--pb-heading-font-family);
80
- font-weight: var(--pb-heading-font-weight);
81
- line-height: var(--pb-heading-line-height);
82
- }
83
-
84
- /* ported over but not checked yet */
85
-
86
- .specs {
87
- padding:6px;
88
- }
89
-
90
- .metadata {
91
- display: block;
92
- }
93
-
94
- .metadata div {
95
- padding: 0 16px 16px;
96
- }
97
-
98
- .metadata paper-input {
99
- margin-bottom: 10px;
100
- }
101
-
102
- .metadata .extCssEdit {
103
- display: flex;
104
- align-items: center;
105
- padding: 0;
106
- }
107
- .metadata .extCssEdit paper-input {
108
- flex: 2;
109
- }
110
- .metadata .extCssEdit pb-edit-xml {
111
- width: 40px;
112
- }
113
-
114
- #jump-to {
115
- margin-top: 1em;
116
- }
117
-
118
- odd-model {
119
- border-bottom: 1px solid #E0E0E0;
120
- }
121
- odd-model h4 {
122
- margin-top: 15px;
123
- padding-top: 5px;
124
- border-top: 1px solid #E0E0E0;
125
- }
126
- .renditions {
127
- margin-top: 10px;
128
- }
129
- .icons{
130
- display:inline-block;
131
- white-space: nowrap;
132
- }
133
-
134
- /* todo: this doesn't work - should refactor to have the complete trigger exposed here (move out of pb-collapse) */
135
- pb-collapse#meta ::slotted(.collapse-trigger){
136
- /*height:56px;*/
137
- }
138
-
139
- iron-collapse {
140
- --iron-collapse-transition-duration:0.8s;
141
- }
142
-
143
- pb-message#errorMsg{
144
- background: var(--paper-red-500);
145
- color:white;
146
- }
147
- .card-content{
148
- height:100%;
149
- overflow:auto;
150
- }
151
-
152
- paper-tab{
153
- width:100px;
154
- }
155
-
156
- .editingView {
157
- width:100%;
158
- }
159
-
160
- vaadin-tabs{
161
- margin-top:10px;
162
- }
163
-
164
- vaadin-tab{
165
- background:var(--paper-grey-200);
166
- padding:0 6px;
167
- border:thin solid var(--paper-grey-300);
168
- border-bottom:none;
169
- }
170
- vaadin-tab[selected]{
171
- background:white;
172
- border-top-right-radius:20px;
173
- box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
174
- 0 1px 5px 0 rgba(0, 0, 0, 0.12),
175
- 0 3px 1px -2px rgba(0, 0, 0, 0.2);
176
-
177
- }
178
-
179
- `;
180
- }
181
-
182
- static get properties() {
183
- return {
184
- ...super.properties,
185
- ident: {
186
- type: String
187
- },
188
- /**
189
- * ElementSpec mode. Can be ´add´, ´change´ or undefined.
190
- */
191
- mode: {
192
- type: String
193
- },
194
- /**
195
- * Array of ´odd-model´ Elements
196
- */
197
- models: {
198
- type: Array
199
- },
200
- /**
201
- * the odd file being edited
202
- */
203
- odd: {
204
- type: String,
205
- reflect: true
206
- },
207
- /**
208
- * array of ´element-spec´ Elements of given odd file
209
- */
210
- elementSpecs: {
211
- type: Array
212
- },
213
- source: {
214
- type: String
215
- },
216
- title: {
217
- type: String
218
- },
219
- titleShort: {
220
- type: String,
221
- reflect: true,
222
- attribute: 'title-short'
223
- },
224
- description: {
225
- type: String
226
- },
227
- namespace: {
228
- type: String
229
- },
230
- rootPath: {
231
- type: String,
232
- attribute: 'root-path'
233
- },
234
- loading: {
235
- type: Boolean
236
- },
237
- indentString: {
238
- type: String
239
- },
240
- outputPrefix: {
241
- type: String,
242
- attribute: 'output-prefix'
243
- },
244
- outputRoot: {
245
- type: String,
246
- attribute: 'output-root'
247
- },
248
- currentSelection: {
249
- type: Object
250
- },
251
- useNamespace: {
252
- type: Boolean
253
- },
254
- loggedIn: {
255
- type: Boolean
256
- },
257
- tabs: {
258
- type: Array
259
- },
260
- tabIndex: {
261
- type: Number,
262
- reflect: true
263
- }
264
- };
265
- }
266
-
267
- constructor() {
268
- super();
269
- this.ident = '';
270
- this.mode = '';
271
- this.models = () => [];
272
- this.odd = '';
273
- this.elementSpecs = [];
274
- this.source = '';
275
- this.title = '';
276
- this.titleShort = '';
277
- this.description = '';
278
- this.namespace = '';
279
- this.rootPath = '';
280
- this.loading = false;
281
- this.indentString = ' ';
282
- this.outputPrefix = '';
283
- this.outputRoot = '';
284
- this.currentSelection = {};
285
- this.useNamespace = false;
286
- this.loggedIn = true;
287
- this.tabs = [];
288
- this.tabIndex = undefined;
289
- this.selectedNavIndex = 0;
290
- this.cssFile = '';
291
- this.hotkeys = {
292
- save: 'ctrl+shift+s,command+shift+s'
293
- }
294
- this._hasChanges = false;
295
- }
296
-
297
- render() {
298
- return html`
299
- <iron-ajax id="loadContent"
300
- handle-as="json" content-type="application/x-www-form-urlencoded"
301
- with-credentials
302
- method="GET"></iron-ajax>
303
-
304
- <iron-ajax id="saveOdd"
305
- handle-as="json"
306
- with-credentials></iron-ajax>
307
-
308
- <div id="layout">
309
- <div id="drawer">
310
- <slot id="slot"></slot>
311
- <h3>
312
- <span>${this.odd}</span>
313
-
314
- <span class="icons">
315
- <pb-edit-xml id="editSource"><paper-icon-button icon="code" title="${translate('odd.editor.odd-source')}"></paper-icon-button></pb-edit-xml>
316
- <paper-icon-button @click="${() => this.save(true)}" icon="icons:cloud-download" title="${fsSupported ? translate('odd.editor.save-as'): translate('odd.editor.download')}"></paper-icon-button>
317
- <paper-icon-button @click="${this._reload}" icon="refresh" title="${translate('odd.editor.reload')}"></paper-icon-button>
318
- <paper-icon-button @click="${() => this.save(false)}" icon="save" title="${translate('odd.editor.save')} ${this.display('save')}"
319
- ?disabled="${!this.loggedIn}"></paper-icon-button>
320
- </span>
321
- </h3>
322
- <div id="new-element" class="input-group">
323
- <paper-input id="identNew" label="${translate('odd.editor.add-element')}" always-float-label="always-float-label">
324
- <paper-icon-button slot="suffix" @click="${this.addElementSpec}" icon="add" tabindex="-1"></paper-icon-button>
325
- </paper-input>
326
- </div>
327
-
328
- <div id="jump-to">
329
- <paper-autocomplete id="jumpTo" label="${translate('odd.editor.jump-to')}" always-float-label="always-float-label"></paper-autocomplete>
330
- </div>
331
-
332
- <h3>${translate('odd.editor.specs')}</h3>
333
- </div>
334
- <div id="navlist">
335
- ${repeat(this.elementSpecs, (i) => i.ident, (i, index) =>
336
- html`
337
- <paper-item id="es_${i.ident}"
338
- index="${index}"
339
- @click="${(ev) => this._openElementSpec(ev, index)}">${i.ident}</paper-item>
340
- `)}
341
- </div>
342
- <section class="specs" id="specs">
343
-
344
- <paper-card class="metadata">
345
- <pb-collapse id="meta">
346
- <h4 slot="collapse-trigger" class="panel-title">
347
- ${this._computedTitle()}
348
- </h4>
349
- <div slot="collapse-content">
350
- <paper-input id="title" name="title" value="${this.title}" label="${translate('odd.editor.title')}"
351
- placeholder="[${translate('odd.editor.title-placeholder')}]"
352
- @change="${this._inputTitle}"></paper-input>
353
- <paper-input id="titleShort" name="short-title" .value="${this.titleShort}" label="${translate('odd.editor.title-short')}"
354
- placeholder="[${translate('odd.editor.title-short-placeholder')}]"
355
- @change="${(e) => this.titleShort = e.composedPath()[0].value}"></paper-input>
356
- <paper-input id="description" name="description" .value="${ifDefined(this.description)}" label="${translate('odd.editor.description-label')}"
357
- placeholder="[${translate('odd.editor.description-placeholder')}]"
358
- @change="${(e) => this.description = e.composedPath()[0].value}"></paper-input>
359
- <paper-input id="source" name="source" ?value="${this.source}" label="${translate('odd.editor.source-label')}"
360
- placeholder="[${translate('odd.editor.source-placeholder')}]"
361
- @change="${(e) => this.source = e.composedPath()[0].value}"></paper-input>
362
- <paper-checkbox id="useNamespace" @change="${this.setUseNamespace}">${translate('odd.editor.use-namespace')}</paper-checkbox>
363
- <paper-input id="namespace" name="namespace" value="${this.namespace}" label="Namespace" ?disabled="${!this.useNamespace}"
364
- placeholder="[${translate('odd.editor.namespace-placeholder')}]"
365
- @change="${(e) => this.namespace = e.composedPath()[0].value}"></paper-input>
366
- <div class="extCssEdit">
367
- <paper-input name="cssFile" value="${this.cssFile}" label="External CSS File"
368
- placeholder="[External CSS file with additional class definitions]"
369
- @change="${this._cssFileChanged}"></paper-input>
370
- <pb-edit-xml id="editCSS"><paper-icon-button icon="create" title="${translate('odd.editor.css-source')}"></paper-icon-button></pb-edit-xml>
371
- </div>
372
- </div>
373
- </pb-collapse>
374
- </paper-card>
375
-
376
- <!-- todo: import elementspec to make it function -->
377
-
378
- <div class="editingView">
379
- <vaadin-tabs id="tabs" selected="${this.tabIndex}">
380
- ${repeat(this.tabs, (i) => i.id, (i, index) =>
381
- html`
382
- <vaadin-tab name="${i}" @click="${(e) => this._selectTab(e, i)}"><span style="padding-right:20px;">${i}</span><paper-icon-button icon="close" @click="${(ev) => this._closeTabHandler(ev, index)}"></paper-icon-button></vaadin-tab>
383
- `)}
384
- </vaadin-tabs>
385
-
386
- <div id="currentElement"></div>
387
- </div>
388
- </section>
389
-
37
+ static get styles() {
38
+ return css`
39
+ :host {
40
+ display: flex;
41
+ /*margin: 30px 20px;*/
42
+ margin: 0;
43
+ padding: 0;
44
+ height: auto;
45
+ }
46
+
47
+ #layout {
48
+ width: 100%;
49
+ display: grid;
50
+ grid-template-columns: auto 1fr;
51
+ grid-template-rows: auto 1fr;
52
+ }
53
+
54
+ #drawer {
55
+ grid-column: 1 / 1;
56
+ min-width: 320px;
57
+ }
58
+
59
+ #navlist {
60
+ grid-column: 1 / 1;
61
+ grid-row: 2 / 2;
62
+ overflow: auto;
63
+ height: 100%;
64
+ }
65
+
66
+ .specs {
67
+ grid-column: 2 / 2;
68
+ grid-row: 1 / span 2;
69
+ overflow: auto;
70
+ }
71
+
72
+ section {
73
+ padding: 20px;
74
+ }
75
+
76
+ h3,
77
+ h4 {
78
+ font-family: var(--pb-heading-font-family);
79
+ font-weight: var(--pb-heading-font-weight);
80
+ line-height: var(--pb-heading-line-height);
81
+ }
82
+
83
+ /* ported over but not checked yet */
84
+
85
+ .specs {
86
+ padding: 6px;
87
+ }
88
+
89
+ .metadata {
90
+ display: block;
91
+ }
92
+
93
+ .metadata div {
94
+ padding: 0 16px 16px;
95
+ }
96
+
97
+ .metadata paper-input {
98
+ margin-bottom: 10px;
99
+ }
100
+
101
+ .metadata .extCssEdit {
102
+ display: flex;
103
+ align-items: center;
104
+ padding: 0;
105
+ }
106
+ .metadata .extCssEdit paper-input {
107
+ flex: 2;
108
+ }
109
+ .metadata .extCssEdit pb-edit-xml {
110
+ width: 40px;
111
+ }
112
+
113
+ #jump-to {
114
+ margin-top: 1em;
115
+ }
116
+
117
+ odd-model {
118
+ border-bottom: 1px solid #e0e0e0;
119
+ }
120
+ odd-model h4 {
121
+ margin-top: 15px;
122
+ padding-top: 5px;
123
+ border-top: 1px solid #e0e0e0;
124
+ }
125
+ .renditions {
126
+ margin-top: 10px;
127
+ }
128
+ .icons {
129
+ display: inline-block;
130
+ white-space: nowrap;
131
+ }
132
+
133
+ /* todo: this doesn't work - should refactor to have the complete trigger exposed here (move out of pb-collapse) */
134
+ pb-collapse#meta ::slotted(.collapse-trigger) {
135
+ /*height:56px;*/
136
+ }
137
+
138
+ iron-collapse {
139
+ --iron-collapse-transition-duration: 0.8s;
140
+ }
141
+
142
+ pb-message#errorMsg {
143
+ background: var(--paper-red-500);
144
+ color: white;
145
+ }
146
+ .card-content {
147
+ height: 100%;
148
+ overflow: auto;
149
+ }
150
+
151
+ paper-tab {
152
+ width: 100px;
153
+ }
154
+
155
+ .editingView {
156
+ width: 100%;
157
+ }
158
+
159
+ vaadin-tabs {
160
+ margin-top: 10px;
161
+ }
162
+
163
+ vaadin-tab {
164
+ background: var(--paper-grey-200);
165
+ padding: 0 6px;
166
+ border: thin solid var(--paper-grey-300);
167
+ border-bottom: none;
168
+ }
169
+ vaadin-tab[selected] {
170
+ background: white;
171
+ border-top-right-radius: 20px;
172
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12),
173
+ 0 3px 1px -2px rgba(0, 0, 0, 0.2);
174
+ }
175
+ `;
176
+ }
177
+
178
+ static get properties() {
179
+ return {
180
+ ...super.properties,
181
+ ident: {
182
+ type: String,
183
+ },
184
+ /**
185
+ * ElementSpec mode. Can be ´add´, ´change´ or undefined.
186
+ */
187
+ mode: {
188
+ type: String,
189
+ },
190
+ /**
191
+ * Array of ´odd-model´ Elements
192
+ */
193
+ models: {
194
+ type: Array,
195
+ },
196
+ /**
197
+ * the odd file being edited
198
+ */
199
+ odd: {
200
+ type: String,
201
+ reflect: true,
202
+ },
203
+ /**
204
+ * array of ´element-spec´ Elements of given odd file
205
+ */
206
+ elementSpecs: {
207
+ type: Array,
208
+ },
209
+ source: {
210
+ type: String,
211
+ },
212
+ title: {
213
+ type: String,
214
+ },
215
+ titleShort: {
216
+ type: String,
217
+ reflect: true,
218
+ attribute: 'title-short',
219
+ },
220
+ description: {
221
+ type: String,
222
+ },
223
+ namespace: {
224
+ type: String,
225
+ },
226
+ rootPath: {
227
+ type: String,
228
+ attribute: 'root-path',
229
+ },
230
+ loading: {
231
+ type: Boolean,
232
+ },
233
+ indentString: {
234
+ type: String,
235
+ },
236
+ outputPrefix: {
237
+ type: String,
238
+ attribute: 'output-prefix',
239
+ },
240
+ outputRoot: {
241
+ type: String,
242
+ attribute: 'output-root',
243
+ },
244
+ currentSelection: {
245
+ type: Object,
246
+ },
247
+ useNamespace: {
248
+ type: Boolean,
249
+ },
250
+ loggedIn: {
251
+ type: Boolean,
252
+ },
253
+ tabs: {
254
+ type: Array,
255
+ },
256
+ tabIndex: {
257
+ type: Number,
258
+ reflect: true,
259
+ },
260
+ };
261
+ }
262
+
263
+ constructor() {
264
+ super();
265
+ this.ident = '';
266
+ this.mode = '';
267
+ this.models = () => [];
268
+ this.odd = '';
269
+ this.elementSpecs = [];
270
+ this.source = '';
271
+ this.title = '';
272
+ this.titleShort = '';
273
+ this.description = '';
274
+ this.namespace = '';
275
+ this.rootPath = '';
276
+ this.loading = false;
277
+ this.indentString = ' ';
278
+ this.outputPrefix = '';
279
+ this.outputRoot = '';
280
+ this.currentSelection = {};
281
+ this.useNamespace = false;
282
+ this.loggedIn = true;
283
+ this.tabs = [];
284
+ this.tabIndex = undefined;
285
+ this.selectedNavIndex = 0;
286
+ this.cssFile = '';
287
+ this.hotkeys = {
288
+ save: 'ctrl+shift+s,command+shift+s',
289
+ };
290
+ this._hasChanges = false;
291
+ }
292
+
293
+ render() {
294
+ return html`
295
+ <iron-ajax
296
+ id="loadContent"
297
+ handle-as="json"
298
+ content-type="application/x-www-form-urlencoded"
299
+ with-credentials
300
+ method="GET"
301
+ ></iron-ajax>
302
+
303
+ <iron-ajax id="saveOdd" handle-as="json" with-credentials></iron-ajax>
304
+
305
+ <div id="layout">
306
+ <div id="drawer">
307
+ <slot id="slot"></slot>
308
+ <h3>
309
+ <span>${this.odd}</span>
310
+
311
+ <span class="icons">
312
+ <pb-edit-xml id="editSource"
313
+ ><paper-icon-button
314
+ icon="code"
315
+ title="${translate('odd.editor.odd-source')}"
316
+ ></paper-icon-button
317
+ ></pb-edit-xml>
318
+ <paper-icon-button
319
+ @click="${() => this.save(true)}"
320
+ icon="icons:cloud-download"
321
+ title="${fsSupported
322
+ ? translate('odd.editor.save-as')
323
+ : translate('odd.editor.download')}"
324
+ ></paper-icon-button>
325
+ <paper-icon-button
326
+ @click="${this._reload}"
327
+ icon="refresh"
328
+ title="${translate('odd.editor.reload')}"
329
+ ></paper-icon-button>
330
+ <paper-icon-button
331
+ @click="${() => this.save(false)}"
332
+ icon="save"
333
+ title="${translate('odd.editor.save')} ${this.display('save')}"
334
+ ?disabled="${!this.loggedIn}"
335
+ ></paper-icon-button>
336
+ </span>
337
+ </h3>
338
+ <div id="new-element" class="input-group">
339
+ <paper-input
340
+ id="identNew"
341
+ label="${translate('odd.editor.add-element')}"
342
+ always-float-label="always-float-label"
343
+ >
344
+ <paper-icon-button
345
+ slot="suffix"
346
+ @click="${this.addElementSpec}"
347
+ icon="add"
348
+ tabindex="-1"
349
+ ></paper-icon-button>
350
+ </paper-input>
351
+ </div>
352
+
353
+ <div id="jump-to">
354
+ <paper-autocomplete
355
+ id="jumpTo"
356
+ label="${translate('odd.editor.jump-to')}"
357
+ always-float-label="always-float-label"
358
+ ></paper-autocomplete>
359
+ </div>
360
+
361
+ <h3>${translate('odd.editor.specs')}</h3>
390
362
  </div>
391
-
392
-
393
- <pb-message id="dialog" hidden></pb-message>
394
- <pb-message id="errorMsg"></pb-message>
395
- `;
396
- }
397
-
398
- firstUpdated(changedProperties) {
399
- this.shadowRoot.getElementById('useNamespace').checked = this.useNamespace;
400
-
401
- // console.log('firstUpdated ', changedProperties);
402
- // console.log('firstUpdated endpoint', this.getEndpoint());
403
- // console.log('firstUpdated rootpath', this.rootPath);
404
- this.jumpCtrl = this.shadowRoot.getElementById('jumpTo');
405
- this.jumpCtrl.addEventListener('autocomplete-selected', this.jumpTo.bind(this));
406
-
407
- const oddSelector = this.querySelector('odd-selector');
408
-
409
- if (this.odd && oddSelector) {
410
- oddSelector.selected = this.odd;
411
-
412
- oddSelector.addEventListener('odd-selected', e => {
413
- if (confirm('Any unsaved changes will be lost. Continue?')) {
414
- this.odd = e.detail.odd;
415
- window.history.pushState({}, "", '?odd=' + this.odd)
416
- }
417
- oddSelector.selected = this.odd;
418
- })
363
+ <div id="navlist">
364
+ ${repeat(
365
+ this.elementSpecs,
366
+ i => i.ident,
367
+ (i, index) =>
368
+ html`
369
+ <paper-item
370
+ id="es_${i.ident}"
371
+ index="${index}"
372
+ @click="${ev => this._openElementSpec(ev, index)}"
373
+ >${i.ident}</paper-item
374
+ >
375
+ `,
376
+ )}
377
+ </div>
378
+ <section class="specs" id="specs">
379
+ <paper-card class="metadata">
380
+ <pb-collapse id="meta">
381
+ <h4 slot="collapse-trigger" class="panel-title">${this._computedTitle()}</h4>
382
+ <div slot="collapse-content">
383
+ <paper-input
384
+ id="title"
385
+ name="title"
386
+ value="${this.title}"
387
+ label="${translate('odd.editor.title')}"
388
+ placeholder="[${translate('odd.editor.title-placeholder')}]"
389
+ @change="${this._inputTitle}"
390
+ ></paper-input>
391
+ <paper-input
392
+ id="titleShort"
393
+ name="short-title"
394
+ .value="${this.titleShort}"
395
+ label="${translate('odd.editor.title-short')}"
396
+ placeholder="[${translate('odd.editor.title-short-placeholder')}]"
397
+ @change="${e => (this.titleShort = e.composedPath()[0].value)}"
398
+ ></paper-input>
399
+ <paper-input
400
+ id="description"
401
+ name="description"
402
+ .value="${ifDefined(this.description)}"
403
+ label="${translate('odd.editor.description-label')}"
404
+ placeholder="[${translate('odd.editor.description-placeholder')}]"
405
+ @change="${e => (this.description = e.composedPath()[0].value)}"
406
+ ></paper-input>
407
+ <paper-input
408
+ id="source"
409
+ name="source"
410
+ ?value="${this.source}"
411
+ label="${translate('odd.editor.source-label')}"
412
+ placeholder="[${translate('odd.editor.source-placeholder')}]"
413
+ @change="${e => (this.source = e.composedPath()[0].value)}"
414
+ ></paper-input>
415
+ <paper-checkbox id="useNamespace" @change="${this.setUseNamespace}"
416
+ >${translate('odd.editor.use-namespace')}</paper-checkbox
417
+ >
418
+ <paper-input
419
+ id="namespace"
420
+ name="namespace"
421
+ value="${this.namespace}"
422
+ label="Namespace"
423
+ ?disabled="${!this.useNamespace}"
424
+ placeholder="[${translate('odd.editor.namespace-placeholder')}]"
425
+ @change="${e => (this.namespace = e.composedPath()[0].value)}"
426
+ ></paper-input>
427
+ <div class="extCssEdit">
428
+ <paper-input
429
+ name="cssFile"
430
+ value="${this.cssFile}"
431
+ label="External CSS File"
432
+ placeholder="[External CSS file with additional class definitions]"
433
+ @change="${this._cssFileChanged}"
434
+ ></paper-input>
435
+ <pb-edit-xml id="editCSS"
436
+ ><paper-icon-button
437
+ icon="create"
438
+ title="${translate('odd.editor.css-source')}"
439
+ ></paper-icon-button
440
+ ></pb-edit-xml>
441
+ </div>
442
+ </div>
443
+ </pb-collapse>
444
+ </paper-card>
445
+
446
+ <!-- todo: import elementspec to make it function -->
447
+
448
+ <div class="editingView">
449
+ <vaadin-tabs id="tabs" selected="${this.tabIndex}">
450
+ ${repeat(
451
+ this.tabs,
452
+ i => i.id,
453
+ (i, index) =>
454
+ html`
455
+ <vaadin-tab name="${i}" @click="${e => this._selectTab(e, i)}"
456
+ ><span style="padding-right:20px;">${i}</span
457
+ ><paper-icon-button
458
+ icon="close"
459
+ @click="${ev => this._closeTabHandler(ev, index)}"
460
+ ></paper-icon-button
461
+ ></vaadin-tab>
462
+ `,
463
+ )}
464
+ </vaadin-tabs>
465
+
466
+ <div id="currentElement"></div>
467
+ </div>
468
+ </section>
469
+ </div>
470
+
471
+ <pb-message id="dialog" hidden></pb-message>
472
+ <pb-message id="errorMsg"></pb-message>
473
+ `;
474
+ }
475
+
476
+ firstUpdated(changedProperties) {
477
+ this.shadowRoot.getElementById('useNamespace').checked = this.useNamespace;
478
+
479
+ // console.log('firstUpdated ', changedProperties);
480
+ // console.log('firstUpdated endpoint', this.getEndpoint());
481
+ // console.log('firstUpdated rootpath', this.rootPath);
482
+ this.jumpCtrl = this.shadowRoot.getElementById('jumpTo');
483
+ this.jumpCtrl.addEventListener('autocomplete-selected', this.jumpTo.bind(this));
484
+
485
+ const oddSelector = this.querySelector('odd-selector');
486
+
487
+ if (this.odd && oddSelector) {
488
+ oddSelector.selected = this.odd;
489
+
490
+ oddSelector.addEventListener('odd-selected', e => {
491
+ if (confirm('Any unsaved changes will be lost. Continue?')) {
492
+ this.odd = e.detail.odd;
493
+ window.history.pushState({}, '', `?odd=${this.odd}`);
419
494
  }
420
-
421
- this.addEventListener('current-changed', this._changeSelection);
422
- this.addEventListener('odd-copy', e => this._copy(e));
423
- this.addEventListener('odd-paste', e => this._paste(e));
424
- this.addEventListener('element-spec-removed', this.removeElementSpec.bind(this));
425
-
426
- window.addEventListener('beforeunload', () => 'Any unsaved changes will be lost. Continue?');
427
-
428
- this.subscribeTo('pb-login', (ev) => {
429
- this.loggedIn = ev.detail.user != null;
430
- });
431
-
432
- this.focus();
433
-
434
- this.loadContent = this.shadowRoot.getElementById('loadContent');
435
-
436
- // it is unclear to me why root-path is not read from attribute without this explicit call
437
- this.rootPath = this.getAttribute('root-path');
438
-
439
- waitOnce('pb-page-ready', () => {
440
- this.load();
441
- this.inited = true;
442
- });
443
-
444
- this.registerHotkey('save', () => this.save(false));
445
- }
446
-
447
- setUseNamespace() {
448
- this.useNamespace = this.shadowRoot.getElementById('useNamespace').checked;
495
+ oddSelector.selected = this.odd;
496
+ });
449
497
  }
450
498
 
451
- async load() {
452
- if (this.loading) {
453
- return;
454
- }
455
- this.loading = true;
456
-
457
- if (this.rootPath === '' || this.odd === '') {
458
- return;
459
- }
460
-
461
- // reset
462
- this.elementSpecs = [];
463
-
464
- document.dispatchEvent(new CustomEvent('pb-start-update'));
465
-
499
+ this.addEventListener('current-changed', this._changeSelection);
500
+ this.addEventListener('odd-copy', e => this._copy(e));
501
+ this.addEventListener('odd-paste', e => this._paste(e));
502
+ this.addEventListener('element-spec-removed', this.removeElementSpec.bind(this));
466
503
 
467
- // this.$.editSource.setPath(this.rootPath + '/' + this.odd);
468
- const editSrc = this.shadowRoot.getElementById('editSource');
469
- editSrc.setPath(this.rootPath + '/' + this.odd);
470
- // this.shadowRoot.getElementById('editSource').setPath(this.rootPath + '/' + this.odd)
504
+ window.addEventListener('beforeunload', () => 'Any unsaved changes will be lost. Continue?');
471
505
 
472
- const params = { odd: this.odd, root: this.rootPath };
506
+ this.subscribeTo('pb-login', ev => {
507
+ this.loggedIn = ev.detail.user != null;
508
+ });
473
509
 
474
- // this.$.loadContent.params = params;
475
- this.loadContent.params = params;
476
- this.loadContent.url = `${this.getEndpoint()}/${this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : 'api/odd/' + this.odd}`;
477
- const request = this.loadContent.generateRequest();
510
+ this.focus();
478
511
 
479
- this._hasChanges = false;
480
- request.completes.then(r => this.handleOdd(r));
481
- }
482
-
483
- handleOdd(req) {
484
- const data = req.response;
485
- this.loggedIn = data.canWrite;
486
- this.source = data.source;
487
- this.title = data.title;
488
- this.titleShort = data.titleShort;
489
- this.description = data.description;
490
- this.cssFile = data.cssFile == null ? '' : data.cssFile;
491
- this.namespace = data.namespace != null ? data.namespace : '';
492
- this.useNamespace = data.namespace != null;
493
-
494
- if (this.cssFile) {
495
- const editCss = this.shadowRoot.getElementById('editCSS');
496
- editCss.setPath(this.rootPath + '/' + this.cssFile);
497
- }
512
+ this.loadContent = this.shadowRoot.getElementById('loadContent');
498
513
 
499
- // update elementSpecs
500
- this.elementSpecs = data.elementSpecs.map(es => this.mapElementSpec(es));
514
+ // it is unclear to me why root-path is not read from attribute without this explicit call
515
+ this.rootPath = this.getAttribute('root-path');
501
516
 
502
- // init auto-complete list
503
- // const jumpTo = this.shadowRoot.getElementById('jumpTo');
504
- // jumpTo.source = this.elementSpecs.map(this._specMapper);
505
- this._updateAutoComplete();
517
+ waitOnce('pb-page-ready', () => {
518
+ this.load();
519
+ this.inited = true;
520
+ });
506
521
 
507
- this.requestUpdate();
522
+ this.registerHotkey('save', () => this.save(false));
523
+ }
508
524
 
509
- this.loading = false;
510
- document.dispatchEvent(new CustomEvent('pb-end-update'));
525
+ setUseNamespace() {
526
+ this.useNamespace = this.shadowRoot.getElementById('useNamespace').checked;
527
+ }
511
528
 
512
- document.title = this.titleShort || this.title;
529
+ async load() {
530
+ if (this.loading) {
531
+ return;
513
532
  }
533
+ this.loading = true;
514
534
 
515
- _updateAutoComplete() {
516
- const jumpTo = this.shadowRoot.getElementById('jumpTo');
517
- jumpTo.source = this.elementSpecs.map(this._specMapper);
535
+ if (this.rootPath === '' || this.odd === '') {
536
+ return;
518
537
  }
519
538
 
520
- _cssFileChanged(e) {
521
- this.cssFile = e.composedPath()[0].value;
522
- if (this.cssFile) {
523
- const editCss = this.shadowRoot.getElementById('editCSS');
524
- editCss.setPath(this.rootPath + '/' + this.cssFile);
525
- }
539
+ // reset
540
+ this.elementSpecs = [];
541
+
542
+ document.dispatchEvent(new CustomEvent('pb-start-update'));
543
+
544
+ // this.$.editSource.setPath(this.rootPath + '/' + this.odd);
545
+ const editSrc = this.shadowRoot.getElementById('editSource');
546
+ editSrc.setPath(`${this.rootPath}/${this.odd}`);
547
+ // this.shadowRoot.getElementById('editSource').setPath(this.rootPath + '/' + this.odd)
548
+
549
+ const params = { odd: this.odd, root: this.rootPath };
550
+
551
+ // this.$.loadContent.params = params;
552
+ this.loadContent.params = params;
553
+ this.loadContent.url = `${this.getEndpoint()}/${
554
+ this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : `api/odd/${this.odd}`
555
+ }`;
556
+ const request = this.loadContent.generateRequest();
557
+
558
+ this._hasChanges = false;
559
+ request.completes.then(r => this.handleOdd(r));
560
+ }
561
+
562
+ handleOdd(req) {
563
+ const data = req.response;
564
+ this.loggedIn = data.canWrite;
565
+ this.source = data.source;
566
+ this.title = data.title;
567
+ this.titleShort = data.titleShort;
568
+ this.description = data.description;
569
+ this.cssFile = data.cssFile == null ? '' : data.cssFile;
570
+ this.namespace = data.namespace != null ? data.namespace : '';
571
+ this.useNamespace = data.namespace != null;
572
+
573
+ if (this.cssFile) {
574
+ const editCss = this.shadowRoot.getElementById('editCSS');
575
+ editCss.setPath(`${this.rootPath}/${this.cssFile}`);
526
576
  }
527
577
 
528
- /**
529
- * handler for paper-item in navigation list in the drawer
530
- *
531
- * @param e
532
- * @param index
533
- * @private
534
- */
535
- _navlistActiveChanged(e, index) {
536
- // set the paper-item active that got the click
537
- this.selectedNavIndex = index;
538
- this.requestUpdate();
539
- }
578
+ // update elementSpecs
579
+ this.elementSpecs = data.elementSpecs.map(es => this.mapElementSpec(es));
540
580
 
541
- _returnTabs() {
542
- return this.tabs;
543
- }
544
-
545
- _selectTab(e, item) {
546
- const spec = this.elementSpecs.find(theSpec => theSpec.ident === item);
547
- this._updateElementspec(spec);
548
- }
581
+ // init auto-complete list
582
+ // const jumpTo = this.shadowRoot.getElementById('jumpTo');
583
+ // jumpTo.source = this.elementSpecs.map(this._specMapper);
584
+ this._updateAutoComplete();
549
585
 
550
- _openElementSpec(ev, index) {
551
- console.log('_openElementSpec ', ev, index);
586
+ this.requestUpdate();
552
587
 
553
- const spec = this.elementSpecs[index]; //get target elementspec
554
- this._updateElementspec(spec);
588
+ this.loading = false;
589
+ document.dispatchEvent(new CustomEvent('pb-end-update'));
555
590
 
556
- const ident = spec.ident;
591
+ document.title = this.titleShort || this.title;
592
+ }
557
593
 
558
- // do not re-open existing tab, but select it
559
- if (this.tabs.indexOf(ident) >= 0) {
560
- this.tabIndex = this.tabs.indexOf(ident);
561
- this.requestUpdate();
562
- return;
563
- }
594
+ _updateAutoComplete() {
595
+ const jumpTo = this.shadowRoot.getElementById('jumpTo');
596
+ jumpTo.source = this.elementSpecs.map(this._specMapper);
597
+ }
564
598
 
565
- this.tabs.push(ident);
566
- this.tabIndex = this.tabs.length - 1;
567
- this.requestUpdate();
599
+ _cssFileChanged(e) {
600
+ this.cssFile = e.composedPath()[0].value;
601
+ if (this.cssFile) {
602
+ const editCss = this.shadowRoot.getElementById('editCSS');
603
+ editCss.setPath(`${this.rootPath}/${this.cssFile}`);
568
604
  }
569
-
570
- _updateElementspec(elementSpec) {
571
- // const spec = this.elementSpecs.find(theSpec => theSpec.ident === specIdent);
572
-
573
- // reset - delete current element if there's one
574
- const currentElement = this.shadowRoot.getElementById('currentElement');
575
- currentElement.innerHTML = "";
576
-
577
- // create new elementspec
578
- const newElementSpec = new PbOddElementspecEditor();
579
- newElementSpec.addEventListener('element-spec-changed', this.handleElementSpecChanged.bind(this));
580
- newElementSpec.ident = elementSpec.ident;
581
- newElementSpec.models = elementSpec.models;
582
- newElementSpec.mode = elementSpec.mode;
583
- newElementSpec.endpoint = this._endpoint;
584
- newElementSpec.apiVersion = this._apiVersion;
585
-
586
- newElementSpec.hotkeys = this.hotkeys;
587
- currentElement.appendChild(newElementSpec);
605
+ }
606
+
607
+ /**
608
+ * handler for paper-item in navigation list in the drawer
609
+ *
610
+ * @param e
611
+ * @param index
612
+ * @private
613
+ */
614
+ _navlistActiveChanged(e, index) {
615
+ // set the paper-item active that got the click
616
+ this.selectedNavIndex = index;
617
+ this.requestUpdate();
618
+ }
619
+
620
+ _returnTabs() {
621
+ return this.tabs;
622
+ }
623
+
624
+ _selectTab(e, item) {
625
+ const spec = this.elementSpecs.find(theSpec => theSpec.ident === item);
626
+ this._updateElementspec(spec);
627
+ }
628
+
629
+ _openElementSpec(ev, index) {
630
+ console.log('_openElementSpec ', ev, index);
631
+
632
+ const spec = this.elementSpecs[index]; // get target elementspec
633
+ this._updateElementspec(spec);
634
+
635
+ const { ident } = spec;
636
+
637
+ // do not re-open existing tab, but select it
638
+ if (this.tabs.indexOf(ident) >= 0) {
639
+ this.tabIndex = this.tabs.indexOf(ident);
640
+ this.requestUpdate();
641
+ return;
588
642
  }
589
643
 
590
- _closeTabHandler(ev, index) {
591
- console.log('_closeTabHandler ', index);
592
- ev.preventDefault();
593
- ev.stopPropagation();
594
-
595
- this._closeTab(index);
596
- return false;
644
+ this.tabs.push(ident);
645
+ this.tabIndex = this.tabs.length - 1;
646
+ this.requestUpdate();
647
+ }
648
+
649
+ _updateElementspec(elementSpec) {
650
+ // const spec = this.elementSpecs.find(theSpec => theSpec.ident === specIdent);
651
+
652
+ // reset - delete current element if there's one
653
+ const currentElement = this.shadowRoot.getElementById('currentElement');
654
+ currentElement.innerHTML = '';
655
+
656
+ // create new elementspec
657
+ const newElementSpec = new PbOddElementspecEditor();
658
+ newElementSpec.addEventListener(
659
+ 'element-spec-changed',
660
+ this.handleElementSpecChanged.bind(this),
661
+ );
662
+ newElementSpec.ident = elementSpec.ident;
663
+ newElementSpec.models = elementSpec.models;
664
+ newElementSpec.mode = elementSpec.mode;
665
+ newElementSpec.endpoint = this._endpoint;
666
+ newElementSpec.apiVersion = this._apiVersion;
667
+
668
+ newElementSpec.hotkeys = this.hotkeys;
669
+ currentElement.appendChild(newElementSpec);
670
+ }
671
+
672
+ _closeTabHandler(ev, index) {
673
+ console.log('_closeTabHandler ', index);
674
+ ev.preventDefault();
675
+ ev.stopPropagation();
676
+
677
+ this._closeTab(index);
678
+ return false;
679
+ }
680
+
681
+ _closeTab(index) {
682
+ this.tabs.splice(index, 1);
683
+ // last tab closed
684
+ if (this.tabs.length === 0) {
685
+ this.shadowRoot.getElementById('currentElement').innerHTML = '';
686
+ this.tabIndex = 0;
687
+ this.tabs = [];
597
688
  }
689
+ // a tab left of selected tab or current tab closed
690
+ else if (this.tabIndex > 0 && this.tabIndex >= index) {
691
+ // decrease tabIndex by one
692
+ this.tabIndex -= 1;
598
693
 
599
- _closeTab(index) {
600
- this.tabs.splice(index, 1);
601
- // last tab closed
602
- if (this.tabs.length === 0) {
603
- this.shadowRoot.getElementById('currentElement').innerHTML = '';
604
- this.tabIndex = 0;
605
- this.tabs = [];
606
- }
607
- // a tab left of selected tab or current tab closed
608
- else if (this.tabIndex > 0 && this.tabIndex >= index) {
609
- // decrease tabIndex by one
610
- this.tabIndex -= 1;
611
-
612
- const currentTab = this.tabs[this.tabIndex];
613
- this._selectTab(null, currentTab);
614
- }
694
+ const currentTab = this.tabs[this.tabIndex];
695
+ this._selectTab(null, currentTab);
615
696
  }
616
-
617
- attributeChangedCallback(name, oldVal, newVal) {
618
- // console.log('attributeChangedCallback', name, oldVal, newVal);
619
-
620
- super.attributeChangedCallback(name, oldVal, newVal);
621
- if (name == 'odd' && oldVal !== newVal) {
622
- // console.log('<pb-document> Emit update event');
623
- // this.emitTo('pb-odd-editor', this);
624
- if (this.inited) {
625
- this.load();
626
- }
627
- }
697
+ }
698
+
699
+ attributeChangedCallback(name, oldVal, newVal) {
700
+ // console.log('attributeChangedCallback', name, oldVal, newVal);
701
+
702
+ super.attributeChangedCallback(name, oldVal, newVal);
703
+ if (name == 'odd' && oldVal !== newVal) {
704
+ // console.log('<pb-document> Emit update event');
705
+ // this.emitTo('pb-odd-editor', this);
706
+ if (this.inited) {
707
+ this.load();
708
+ }
628
709
  }
629
-
630
- static get replaceCharMap() {
631
- return {
632
- '"': '&quot;',
633
- '&': '&amp;',
634
- '<': '&lt;',
635
- '>': '&gt;'
636
- }
710
+ }
711
+
712
+ static get replaceCharMap() {
713
+ return {
714
+ '"': '&quot;',
715
+ '&': '&amp;',
716
+ '<': '&lt;',
717
+ '>': '&gt;',
637
718
  };
638
-
639
- static get replaceCharRegexp() {
640
- return /"|&|<|>/g
641
- }
642
-
643
- static replaceChars(match) {
644
- return PbOddEditor.replaceCharMap[match];
645
- }
646
-
647
- jumpTo(e) {
648
- const jumpCtrl = this.shadowRoot.getElementById('jumpTo');
649
- const id = '#es_' + jumpCtrl.text;
650
- const target = this.shadowRoot.querySelector(id);
651
- if (!target) {
652
- return
653
- }
654
-
655
- this.jumpCtrl.clear();
656
- target.click();
657
- }
658
-
659
- _computedTitle() {
660
- if (!this.odd) {
661
- return ''
662
- }
663
- return this.title || this.titleShort || this.odd || 'Loading ...'
664
- }
665
-
666
- _copy(e) {
667
- // console.log('odd-editor._copy ', e);
668
- this.clipboard = e.detail.model;
669
- const clone = JSON.parse(JSON.stringify(e.detail.model));
670
- this.clipboard = clone;
671
- }
672
-
673
- _paste(e) {
674
- console.log('_paste ', e);
675
- console.log('_paste clipboard', this.clipboard);
676
-
677
- if (this.clipboard == {} || this.clipboard == undefined) {
678
- return;
679
- }
680
- const targetElement = e.detail.target;
681
- targetElement.addModel(this.clipboard);
682
- targetElement.render();
719
+ }
720
+
721
+ static get replaceCharRegexp() {
722
+ return /"|&|<|>/g;
723
+ }
724
+
725
+ static replaceChars(match) {
726
+ return PbOddEditor.replaceCharMap[match];
727
+ }
728
+
729
+ jumpTo(e) {
730
+ const jumpCtrl = this.shadowRoot.getElementById('jumpTo');
731
+ const id = `#es_${jumpCtrl.text}`;
732
+ const target = this.shadowRoot.querySelector(id);
733
+ if (!target) {
734
+ return;
683
735
  }
684
736
 
685
- _specMapper(spec) {
686
- return {
687
- text: spec.ident,
688
- value: spec.ident
689
- };
690
- }
737
+ this.jumpCtrl.clear();
738
+ target.click();
739
+ }
691
740
 
692
- _specObserver(changeRecord) {
693
- const source = this.elementSpecs.map(this._specMapper);
694
- this.jumpCtrl.source = source;
741
+ _computedTitle() {
742
+ if (!this.odd) {
743
+ return '';
695
744
  }
696
-
697
- mapElementSpec(elementSpec) {
698
- return Object.assign(
699
- {},
700
- elementSpec,
701
- { models: elementSpec.models.map(m => this.addShowToModel(m)) }
702
- );
703
- }
704
-
705
- addShowToModel(model) {
706
- if (model.models) {
707
- const extendedModels = model.models.map(m => this.addShowToModel(m));
708
- return Object.assign({}, model, { models: extendedModels, show: false });
709
- }
710
- return Object.assign({}, model, { show: false });
745
+ return this.title || this.titleShort || this.odd || 'Loading ...';
746
+ }
747
+
748
+ _copy(e) {
749
+ // console.log('odd-editor._copy ', e);
750
+ this.clipboard = e.detail.model;
751
+ const clone = JSON.parse(JSON.stringify(e.detail.model));
752
+ this.clipboard = clone;
753
+ }
754
+
755
+ _paste(e) {
756
+ console.log('_paste ', e);
757
+ console.log('_paste clipboard', this.clipboard);
758
+
759
+ if (this.clipboard == {} || this.clipboard == undefined) {
760
+ return;
711
761
  }
762
+ const targetElement = e.detail.target;
763
+ targetElement.addModel(this.clipboard);
764
+ targetElement.render();
765
+ }
766
+
767
+ _specMapper(spec) {
768
+ return {
769
+ text: spec.ident,
770
+ value: spec.ident,
771
+ };
772
+ }
712
773
 
713
- addElementSpec(ev) {
714
- // const ident = this.$.identNew.value;
715
- const identNew = this.shadowRoot.getElementById('identNew');
774
+ _specObserver(changeRecord) {
775
+ const source = this.elementSpecs.map(this._specMapper);
776
+ this.jumpCtrl.source = source;
777
+ }
716
778
 
717
- const ident = identNew.value;
718
- if (!ident || ident.length === 0) {
719
- return;
720
- }
721
- const existingSpec = this.elementSpecs.find((spec) => spec.ident === ident);
722
- if (existingSpec) {
723
- console.log('<pb-odd-editor> element spec to be added already exists: %s', ident);
724
- const id = `#es_${ident}`;
725
- const target = this.shadowRoot.querySelector(id);
726
- if (!target) {
727
- return
728
- }
729
- target.click();
730
- return;
731
- }
779
+ mapElementSpec(elementSpec) {
780
+ return {
781
+ ...elementSpec,
782
+ models: elementSpec.models.map(m => this.addShowToModel(m)),
783
+ };
784
+ }
732
785
 
733
- const oldApiParams = {
734
- action: "find",
735
- odd: this.odd,
736
- root: this.rootPath,
737
- ident
738
- };
739
- const newApiParams = {
740
- root: this.rootPath,
741
- ident
742
- };
743
-
744
- const params = this.lessThanApiVersion('1.0.0') ? oldApiParams : newApiParams;
745
-
746
- this.loadContent.params = params;
747
- this.loadContent.url = `${this.getEndpoint()}/${this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : 'api/odd/' + this.odd}`;
748
- let request = this.loadContent.generateRequest();
749
- request.completes.then(this._handleElementSpecResponse.bind(this));
786
+ addShowToModel(model) {
787
+ if (model.models) {
788
+ const extendedModels = model.models.map(m => this.addShowToModel(m));
789
+ return { ...model, models: extendedModels, show: false };
750
790
  }
791
+ return { ...model, show: false };
792
+ }
751
793
 
794
+ addElementSpec(ev) {
795
+ // const ident = this.$.identNew.value;
796
+ const identNew = this.shadowRoot.getElementById('identNew');
752
797
 
753
- _handleElementSpecResponse(req) {
754
- const identNew = this.shadowRoot.getElementById('identNew');
755
-
756
- const data = req.response;
757
- const ident = identNew.value
758
- const mode = (data.status === 'not-found' ? 'add' : 'change');
759
- const models = data.models || [];
760
- const newSpec = {
761
- ident,
762
- mode,
763
- models
764
- };
765
-
766
- this.elementSpecs.unshift(newSpec);
767
- // trigger update of autocomplete list in jumpTo
768
- identNew.value = '';
769
-
770
- //open new tab with newly created element
771
- this.tabs.push(ident);
772
- this.tabIndex = this.tabs.length - 1;
773
-
774
- this.elementSpecs.sort((a, b) => a.ident.localeCompare(b.ident));
775
-
776
- this.requestUpdate().then(() => {
777
- const elem = this.shadowRoot.querySelectorAll('paper-item');
778
- const idx = this.elementSpecs.indexOf(newSpec);
779
-
780
- this._updateAutoComplete();
781
-
782
- elem[idx].click();
783
- elem[idx].focus();
784
- });
798
+ const ident = identNew.value;
799
+ if (!ident || ident.length === 0) {
800
+ return;
785
801
  }
786
-
787
- removeElementSpec(ev) {
788
- const ident = ev.detail.target.ident;
789
- this.shadowRoot.getElementById('dialog')
790
- .confirm(i18n('browse.delete'), i18n('odd.editor.delete-spec', { ident }))
791
- .then(() => {
792
- const targetIndex = this.elementSpecs.findIndex(theSpec => theSpec.ident === ident);
793
- this.elementSpecs.splice(targetIndex, 1);
794
- this.requestUpdate();
795
-
796
-
797
- const selectedTab = this.shadowRoot.querySelector('vaadin-tab[selected]');
798
- const tabName = selectedTab.getAttribute('name');
799
- const idx = this.tabs.indexOf(tabName);
800
- this._closeTab(idx);
801
- }, () => null);
802
+ const existingSpec = this.elementSpecs.find(spec => spec.ident === ident);
803
+ if (existingSpec) {
804
+ console.log('<pb-odd-editor> element spec to be added already exists: %s', ident);
805
+ const id = `#es_${ident}`;
806
+ const target = this.shadowRoot.querySelector(id);
807
+ if (!target) {
808
+ return;
809
+ }
810
+ target.click();
811
+ return;
802
812
  }
803
813
 
804
- serializeOdd() {
805
- const ns = this.useNamespace ? ` ns="${this.namespace}"` : '';
806
- const source = this.source ? ` source="${this.source}"` : '';
807
- const description = this.description ? ` <desc>${this.description}</desc>` : '';
808
- const title = `${this.indentString}<title>${this.title}${description}</title>\n`;
809
- const titleShort = this.titleShort ? `${this.indentString}<title type="short">${this.titleShort}</title>\n` : '';
810
- const cssFile = this.cssFile ? `${this.indentString}<rendition source="${this.cssFile}"/>\n` : '';
811
- const elementSpecs = this.elementSpecs
812
- .map(e => this.serializeElementSpec(this.indentString, e)).join('');
813
-
814
- return `<schemaSpec xmlns="http://www.tei-c.org/ns/1.0" xmlns:pb="http://teipublisher.com/1.0"${ns}${source}>\n${title}${titleShort}${cssFile}\n${elementSpecs}</schemaSpec>\n`
815
- }
814
+ const oldApiParams = {
815
+ action: 'find',
816
+ odd: this.odd,
817
+ root: this.rootPath,
818
+ ident,
819
+ };
820
+ const newApiParams = {
821
+ root: this.rootPath,
822
+ ident,
823
+ };
816
824
 
817
- serializeElementSpec(indent, elementSpec) {
818
- const mode = elementSpec.mode ? ` mode="${elementSpec.mode}"` : '';
819
- const indent2 = indent + this.indentString
820
- const models = elementSpec.models
821
- .map(m => this.serializeModel(indent2, m))
822
- .join('')
825
+ const params = this.lessThanApiVersion('1.0.0') ? oldApiParams : newApiParams;
826
+
827
+ this.loadContent.params = params;
828
+ this.loadContent.url = `${this.getEndpoint()}/${
829
+ this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : `api/odd/${this.odd}`
830
+ }`;
831
+ const request = this.loadContent.generateRequest();
832
+ request.completes.then(this._handleElementSpecResponse.bind(this));
833
+ }
834
+
835
+ _handleElementSpecResponse(req) {
836
+ const identNew = this.shadowRoot.getElementById('identNew');
837
+
838
+ const data = req.response;
839
+ const ident = identNew.value;
840
+ const mode = data.status === 'not-found' ? 'add' : 'change';
841
+ const models = data.models || [];
842
+ const newSpec = {
843
+ ident,
844
+ mode,
845
+ models,
846
+ };
823
847
 
824
- return `${indent}<elementSpec ident="${elementSpec.ident}"${mode}>\n${models}${indent}</elementSpec>\n`;
848
+ this.elementSpecs.unshift(newSpec);
849
+ // trigger update of autocomplete list in jumpTo
850
+ identNew.value = '';
851
+
852
+ // open new tab with newly created element
853
+ this.tabs.push(ident);
854
+ this.tabIndex = this.tabs.length - 1;
855
+
856
+ this.elementSpecs.sort((a, b) => a.ident.localeCompare(b.ident));
857
+
858
+ this.requestUpdate().then(() => {
859
+ const elem = this.shadowRoot.querySelectorAll('paper-item');
860
+ const idx = this.elementSpecs.indexOf(newSpec);
861
+
862
+ this._updateAutoComplete();
863
+
864
+ elem[idx].click();
865
+ elem[idx].focus();
866
+ });
867
+ }
868
+
869
+ removeElementSpec(ev) {
870
+ const { ident } = ev.detail.target;
871
+ this.shadowRoot
872
+ .getElementById('dialog')
873
+ .confirm(i18n('browse.delete'), i18n('odd.editor.delete-spec', { ident }))
874
+ .then(
875
+ () => {
876
+ const targetIndex = this.elementSpecs.findIndex(theSpec => theSpec.ident === ident);
877
+ this.elementSpecs.splice(targetIndex, 1);
878
+ this.requestUpdate();
879
+
880
+ const selectedTab = this.shadowRoot.querySelector('vaadin-tab[selected]');
881
+ const tabName = selectedTab.getAttribute('name');
882
+ const idx = this.tabs.indexOf(tabName);
883
+ this._closeTab(idx);
884
+ },
885
+ () => null,
886
+ );
887
+ }
888
+
889
+ serializeOdd() {
890
+ const ns = this.useNamespace ? ` ns="${this.namespace}"` : '';
891
+ const source = this.source ? ` source="${this.source}"` : '';
892
+ const description = this.description ? ` <desc>${this.description}</desc>` : '';
893
+ const title = `${this.indentString}<title>${this.title}${description}</title>\n`;
894
+ const titleShort = this.titleShort
895
+ ? `${this.indentString}<title type="short">${this.titleShort}</title>\n`
896
+ : '';
897
+ const cssFile = this.cssFile
898
+ ? `${this.indentString}<rendition source="${this.cssFile}"/>\n`
899
+ : '';
900
+ const elementSpecs = this.elementSpecs
901
+ .map(e => this.serializeElementSpec(this.indentString, e))
902
+ .join('');
903
+
904
+ return `<schemaSpec xmlns="http://www.tei-c.org/ns/1.0" xmlns:pb="http://teipublisher.com/1.0"${ns}${source}>\n${title}${titleShort}${cssFile}\n${elementSpecs}</schemaSpec>\n`;
905
+ }
906
+
907
+ serializeElementSpec(indent, elementSpec) {
908
+ const mode = elementSpec.mode ? ` mode="${elementSpec.mode}"` : '';
909
+ const indent2 = indent + this.indentString;
910
+ const models = elementSpec.models.map(m => this.serializeModel(indent2, m)).join('');
911
+
912
+ return `${indent}<elementSpec ident="${elementSpec.ident}"${mode}>\n${models}${indent}</elementSpec>\n`;
913
+ }
914
+
915
+ serializeModel(indent, model) {
916
+ if (model.type === 'model' && !model.behaviour) {
917
+ return '';
825
918
  }
826
919
 
827
- serializeModel(indent, model) {
828
- if (model.type === 'model' && !model.behaviour) {
829
- return '';
830
- }
831
-
832
- const nestedIndent = indent + this.indentString;
833
-
834
- const attributes = [
835
- this.serializeAttribute('output', model.output),
836
- this.serializeAttribute('predicate', model.predicate),
837
- model.type === 'model' ? this.serializeAttribute('behaviour', model.behaviour) : '',
838
- this.serializeAttribute('cssClass', model.css),
839
- this.serializeAttribute('useSourceRendition', model.sourcerend),
840
- this.serializeAttribute('pb:mode', model.mode)
841
- ].join('');
842
-
843
- const desc = model.desc ? nestedIndent + '<desc>' + model.desc + '</desc>\n' : '';
844
-
845
- // innerXML += this.serializeTag('model', nestedIndent);
846
- const models = model.models.map(m => this.serializeModel(nestedIndent, m)).join('');
847
- const parameters = model.parameters.map(p => this.serializeParameter(nestedIndent, p)).join('');
848
- const renditions = model.renditions.map(r => this.serializeRendition(nestedIndent, r)).join('');
849
- const template = PbOddEditor.serializeTemplate(nestedIndent, model.template);
850
- const innerXML = `${desc}${models}${parameters}${template}${renditions}`;
851
- const end = (innerXML.length > 0) ? `>\n${innerXML}${indent}</${model.type}` : '/';
852
-
853
- return `${indent}<${model.type}${attributes}${end}>\n`
920
+ const nestedIndent = indent + this.indentString;
921
+
922
+ const attributes = [
923
+ this.serializeAttribute('output', model.output),
924
+ this.serializeAttribute('predicate', model.predicate),
925
+ model.type === 'model' ? this.serializeAttribute('behaviour', model.behaviour) : '',
926
+ this.serializeAttribute('cssClass', model.css),
927
+ this.serializeAttribute('useSourceRendition', model.sourcerend),
928
+ this.serializeAttribute('pb:mode', model.mode),
929
+ ].join('');
930
+
931
+ const desc = model.desc ? `${nestedIndent}<desc>${model.desc}</desc>\n` : '';
932
+
933
+ // innerXML += this.serializeTag('model', nestedIndent);
934
+ const models = model.models.map(m => this.serializeModel(nestedIndent, m)).join('');
935
+ const parameters = model.parameters.map(p => this.serializeParameter(nestedIndent, p)).join('');
936
+ const renditions = model.renditions.map(r => this.serializeRendition(nestedIndent, r)).join('');
937
+ const template = PbOddEditor.serializeTemplate(nestedIndent, model.template);
938
+ const innerXML = `${desc}${models}${parameters}${template}${renditions}`;
939
+ const end = innerXML.length > 0 ? `>\n${innerXML}${indent}</${model.type}` : '/';
940
+
941
+ return `${indent}<${model.type}${attributes}${end}>\n`;
942
+ }
943
+
944
+ serializeParameter(indent, parameter) {
945
+ if (!parameter.name) {
946
+ return '';
854
947
  }
855
-
856
- serializeParameter(indent, parameter) {
857
- if (!parameter.name) {
858
- return '';
859
- }
860
- const name = this.serializeAttribute('name', parameter.name);
861
- const value = this.serializeAttribute('value', parameter.value);
862
- if (parameter.set) {
863
- return `${indent}<pb:set-param xmlns=""${name}${value}/>\n`
864
- }
865
- return `${indent}<param${name}${value}/>\n`
948
+ const name = this.serializeAttribute('name', parameter.name);
949
+ const value = this.serializeAttribute('value', parameter.value);
950
+ if (parameter.set) {
951
+ return `${indent}<pb:set-param xmlns=""${name}${value}/>\n`;
866
952
  }
867
-
868
- serializeRendition(indent, rendition) {
869
- const scope = rendition.scope && rendition.scope !== 'null' ? this.serializeAttribute('scope', rendition.scope) : '';
870
- const css = PbOddEditor.escape(rendition.css);
871
- return `${indent}<outputRendition xml:space="preserve" ${scope}>\n${indent}${css}\n${indent}</outputRendition>\n`;
953
+ return `${indent}<param${name}${value}/>\n`;
954
+ }
955
+
956
+ serializeRendition(indent, rendition) {
957
+ const scope =
958
+ rendition.scope && rendition.scope !== 'null'
959
+ ? this.serializeAttribute('scope', rendition.scope)
960
+ : '';
961
+ const css = PbOddEditor.escape(rendition.css);
962
+ return `${indent}<outputRendition xml:space="preserve" ${scope}>\n${indent}${css}\n${indent}</outputRendition>\n`;
963
+ }
964
+
965
+ static serializeTemplate(indent, template) {
966
+ if (!template) {
967
+ return '';
872
968
  }
969
+ return `${indent}<pb:template xml:space="preserve" xmlns="">${template}</pb:template>\n`;
970
+ }
873
971
 
874
- static serializeTemplate(indent, template) {
875
- if (!template) {
876
- return '';
877
- }
878
- return `${indent}<pb:template xml:space="preserve" xmlns="">${template}</pb:template>\n`;
879
- }
972
+ serializeAttribute(name, value) {
973
+ return value ? ` ${name}="${PbOddEditor.escape(value)}"` : '';
974
+ }
880
975
 
881
- serializeAttribute(name, value) {
882
- return value ? ` ${name}="${PbOddEditor.escape(value)}"` : ''
976
+ static escape(code) {
977
+ if (!code) {
978
+ return '';
883
979
  }
884
-
885
- static escape(code) {
886
- if (!code) {
887
- return '';
888
- }
889
- if (typeof code === 'string') {
890
- return code.replace(PbOddEditor.replaceCharRegexp, PbOddEditor.replaceChars);
891
- }
892
- return code;
980
+ if (typeof code === 'string') {
981
+ return code.replace(PbOddEditor.replaceCharRegexp, PbOddEditor.replaceChars);
893
982
  }
894
-
895
- save(download=false) {
896
- document.dispatchEvent(new CustomEvent('pb-start-update'));
897
- const data = this.serializeOdd();
898
-
899
- this.shadowRoot.getElementById('dialog').show(i18n("odd.editor.save"), i18n('odd.editor.saving'));
900
-
901
- const saveOdd = this.shadowRoot.getElementById('saveOdd');
902
- saveOdd.url = `${this.getEndpoint()}/${this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : 'api/odd/' + this.odd}`;
903
- if (this.lessThanApiVersion('1.0.0')) {
904
- saveOdd.contentType = 'application/x-www-form-urlencoded';
905
- saveOdd.method = "POST";
906
- saveOdd.params = null;
907
- saveOdd.body = {
908
- action: "save",
909
- root: this.rootPath,
910
- "output-prefix": this.outputPrefix,
911
- "output-root": this.outputRoot,
912
- odd: this.odd,
913
- data
914
- };
915
- } else {
916
- saveOdd.contentType = 'application/xml';
917
- saveOdd.method = "PUT";
918
- saveOdd.params = {
919
- root: this.rootPath,
920
- "output-prefix": this.outputPrefix,
921
- "output-root": this.outputRoot,};
922
- saveOdd.body = data;
923
- }
924
-
925
- const request = saveOdd.generateRequest();
926
- request.completes
927
- .then((req) => {
928
- this.handleSaveComplete(req, download);
929
- })
930
- .catch(this.handleSaveError.bind(this));
983
+ return code;
984
+ }
985
+
986
+ save(download = false) {
987
+ document.dispatchEvent(new CustomEvent('pb-start-update'));
988
+ const data = this.serializeOdd();
989
+
990
+ this.shadowRoot
991
+ .getElementById('dialog')
992
+ .show(i18n('odd.editor.save'), i18n('odd.editor.saving'));
993
+
994
+ const saveOdd = this.shadowRoot.getElementById('saveOdd');
995
+ saveOdd.url = `${this.getEndpoint()}/${
996
+ this.lessThanApiVersion('1.0.0') ? 'modules/editor.xql' : `api/odd/${this.odd}`
997
+ }`;
998
+ if (this.lessThanApiVersion('1.0.0')) {
999
+ saveOdd.contentType = 'application/x-www-form-urlencoded';
1000
+ saveOdd.method = 'POST';
1001
+ saveOdd.params = null;
1002
+ saveOdd.body = {
1003
+ action: 'save',
1004
+ root: this.rootPath,
1005
+ 'output-prefix': this.outputPrefix,
1006
+ 'output-root': this.outputRoot,
1007
+ odd: this.odd,
1008
+ data,
1009
+ };
1010
+ } else {
1011
+ saveOdd.contentType = 'application/xml';
1012
+ saveOdd.method = 'PUT';
1013
+ saveOdd.params = {
1014
+ root: this.rootPath,
1015
+ 'output-prefix': this.outputPrefix,
1016
+ 'output-root': this.outputRoot,
1017
+ };
1018
+ saveOdd.body = data;
931
1019
  }
932
1020
 
933
- //to be deprecated: only used for old api
934
- static _renderReport(report) {
935
- if (report.error) {
936
- return `
1021
+ const request = saveOdd.generateRequest();
1022
+ request.completes
1023
+ .then(req => {
1024
+ this.handleSaveComplete(req, download);
1025
+ })
1026
+ .catch(this.handleSaveError.bind(this));
1027
+ }
1028
+
1029
+ // to be deprecated: only used for old api
1030
+ static _renderReport(report) {
1031
+ if (report.error) {
1032
+ return `
937
1033
  <div class="list-group-item-danger">
938
1034
  <h4 class="list-group-item-heading">${report.file}</h4>
939
1035
  <h5 class="list-group-item-heading">Compilation error on line ${report.line}:</h5>
@@ -941,138 +1037,140 @@ export class PbOddEditor extends pbHotkeys(pbMixin(LitElement)) {
941
1037
  <pre class="list-group-item-text">${report.message}</pre>
942
1038
  </div>
943
1039
  `;
944
- }
945
- return `
1040
+ }
1041
+ return `
946
1042
  <div class="list-group-item-success">
947
1043
  <p class="list-group-item-text">Generated ${report.file}</p>
948
1044
  </div>
949
1045
  `;
1046
+ }
1047
+
1048
+ handleSaveComplete(req, download = false) {
1049
+ const data = req.response;
1050
+ if (data.status === 'denied') {
1051
+ this.shadowRoot
1052
+ .getElementById('dialog')
1053
+ .set(i18n('odd.editor.denied'), i18n('odd.editor.denied-message', { odd: this.odd }));
1054
+ document.dispatchEvent(new CustomEvent('pb-end-update'));
1055
+ return;
950
1056
  }
951
1057
 
952
- handleSaveComplete(req, download=false) {
953
- const data = req.response;
954
- if (data.status === 'denied') {
955
- this.shadowRoot.getElementById('dialog').set(i18n("odd.editor.denied"), i18n("odd.editor.denied-message", { odd: this.odd }));
956
- document.dispatchEvent(new CustomEvent('pb-end-update'));
957
- return;
958
- }
959
-
960
- let msg;
961
-
962
- if (this.lessThanApiVersion('1.0.0')) {
963
- const report = data.report.map(PbOddEditor._renderReport);
964
- msg = `<div class="list-group">${report.join('')}</div>`;
965
- } else {
966
- const report = data.report;
967
- msg = `<div class="list-group">${report}</div>`;
968
- }
969
-
970
- this.shadowRoot.getElementById('dialog').set(i18n("odd.editor.saved"), msg);
971
-
972
- this._hasChanges = false;
973
- document.dispatchEvent(new CustomEvent('pb-end-update'));
974
-
975
- if (download) {
976
- const blob = new Blob([data.source], { type: 'application/xml'});
977
- fileSave(blob, {
978
- fileName: this.odd,
979
- extensions: ['.odd'],
980
- })
981
- .then(
982
- () => console.log(`<pb-odd-editor> ${this.odd} exported`),
983
- () => console.log('<pb-odd-editor> export aborted')
984
- );
985
- }
986
- }
987
-
988
- handleSaveError(rejected) {
989
- this.shadowRoot.getElementById('dialog').set("Error", rejected.error);
990
- // this.$.dialog.set("Error", rejected.error);
991
- document.dispatchEvent(new CustomEvent('pb-end-update'));
992
- }
1058
+ let msg;
993
1059
 
994
- _reload() {
995
- this.shadowRoot.getElementById('dialog')
996
- .confirm(i18n('odd.editor.reload'), i18n('odd.editor.reload-confirm'))
997
- .then(() => {
998
- this.load();
999
- this.tabs = [];
1000
- this.tabIndex = 0;
1001
- this.shadowRoot.getElementById('currentElement').innerHTML = '';
1002
- }, () => null);
1060
+ if (this.lessThanApiVersion('1.0.0')) {
1061
+ const report = data.report.map(PbOddEditor._renderReport);
1062
+ msg = `<div class="list-group">${report.join('')}</div>`;
1063
+ } else {
1064
+ const { report } = data;
1065
+ msg = `<div class="list-group">${report}</div>`;
1003
1066
  }
1004
1067
 
1005
- _setCurrentSelection(e) {
1006
- if (this.currentSelection != undefined) {
1007
- this.currentSelection.removeAttribute('currentselection');
1008
- }
1009
- this.currentSelection = e.target;
1010
- this.currentSelection.setAttribute('currentselection', 'true');
1011
- }
1012
-
1013
-
1014
- _changeSelection(ev) {
1015
- ev.preventDefault();
1016
- ev.stopPropagation();
1017
-
1018
- if (ev.detail.target === this) return;
1019
-
1020
- if (this.currentSelection &&
1021
- this.currentSelection.tagName !== undefined) {
1022
- this.currentSelection.removeAttribute('currentselection');
1023
- }
1068
+ this.shadowRoot.getElementById('dialog').set(i18n('odd.editor.saved'), msg);
1024
1069
 
1025
- let newSelection;
1026
- if (ev.detail.target) {
1027
- newSelection = ev.detail.target;
1028
- } else {
1029
- newSelection = ev.target;
1030
- }
1031
- newSelection.setAttribute('currentselection', 'true');
1032
- this.currentSelection = newSelection;
1033
- }
1070
+ this._hasChanges = false;
1071
+ document.dispatchEvent(new CustomEvent('pb-end-update'));
1034
1072
 
1035
- _selectElementspec(e) {
1036
- if (this.currentElementSpec &&
1037
- this.currentElementSpec.tagName === 'PB-ODD-ELEMENTSPEC-EDITOR') {
1038
- this.currentElementSpec.removeAttribute('currentselection');
1039
- }
1040
- const newSelection = e.target;
1041
- newSelection.setAttribute('currentselection', 'true');
1042
- this.currentElementSpec = newSelection;
1073
+ if (download) {
1074
+ const blob = new Blob([data.source], { type: 'application/xml' });
1075
+ fileSave(blob, {
1076
+ fileName: this.odd,
1077
+ extensions: ['.odd'],
1078
+ }).then(
1079
+ () => console.log(`<pb-odd-editor> ${this.odd} exported`),
1080
+ () => console.log('<pb-odd-editor> export aborted'),
1081
+ );
1043
1082
  }
1044
-
1045
- nsDisabled() {
1046
- return !this.useNamespace;
1047
- }
1048
-
1049
- _handleLoadError(e) {
1050
- console.log('loading error occurred: ', e);
1051
- const msg = this.shadowRoot.getElementById('errorMsg');
1052
- msg.style.background = 'red';
1053
- const url = this.shadowRoot.getElementById('loadContent').url;
1054
- console.log('url ', url);
1055
- msg.show('Error: ', 'ODD file could not be loaded from ' + url);
1083
+ }
1084
+
1085
+ handleSaveError(rejected) {
1086
+ this.shadowRoot.getElementById('dialog').set('Error', rejected.error);
1087
+ // this.$.dialog.set("Error", rejected.error);
1088
+ document.dispatchEvent(new CustomEvent('pb-end-update'));
1089
+ }
1090
+
1091
+ _reload() {
1092
+ this.shadowRoot
1093
+ .getElementById('dialog')
1094
+ .confirm(i18n('odd.editor.reload'), i18n('odd.editor.reload-confirm'))
1095
+ .then(
1096
+ () => {
1097
+ this.load();
1098
+ this.tabs = [];
1099
+ this.tabIndex = 0;
1100
+ this.shadowRoot.getElementById('currentElement').innerHTML = '';
1101
+ },
1102
+ () => null,
1103
+ );
1104
+ }
1105
+
1106
+ _setCurrentSelection(e) {
1107
+ if (this.currentSelection != undefined) {
1108
+ this.currentSelection.removeAttribute('currentselection');
1056
1109
  }
1110
+ this.currentSelection = e.target;
1111
+ this.currentSelection.setAttribute('currentselection', 'true');
1112
+ }
1057
1113
 
1114
+ _changeSelection(ev) {
1115
+ ev.preventDefault();
1116
+ ev.stopPropagation();
1058
1117
 
1059
- handleElementSpecChanged(e) {
1060
- // console.log('handleElementSpecChanged ',e);
1061
- this._hasChanges = true;
1062
- const elementSpec = this.elementSpecs.find(es => es.ident === e.detail.ident);
1063
- const index = this.elementSpecs.indexOf(elementSpec);
1064
- const newSpec = Object.assign({}, elementSpec, { models: e.detail.models });
1065
- const allSpecs = Array.from(this.elementSpecs);
1066
- allSpecs.splice(index, 1, newSpec)
1067
- this.elementSpecs = allSpecs;
1068
- // console.log('updated elementspecs ', this.elementSpecs);
1118
+ if (ev.detail.target === this) return;
1069
1119
 
1120
+ if (this.currentSelection && this.currentSelection.tagName !== undefined) {
1121
+ this.currentSelection.removeAttribute('currentselection');
1070
1122
  }
1071
1123
 
1072
- _inputTitle(ev) {
1073
- this.title = ev.composedPath()[0].value;
1124
+ let newSelection;
1125
+ if (ev.detail.target) {
1126
+ newSelection = ev.detail.target;
1127
+ } else {
1128
+ newSelection = ev.target;
1074
1129
  }
1075
-
1130
+ newSelection.setAttribute('currentselection', 'true');
1131
+ this.currentSelection = newSelection;
1132
+ }
1133
+
1134
+ _selectElementspec(e) {
1135
+ if (
1136
+ this.currentElementSpec &&
1137
+ this.currentElementSpec.tagName === 'PB-ODD-ELEMENTSPEC-EDITOR'
1138
+ ) {
1139
+ this.currentElementSpec.removeAttribute('currentselection');
1140
+ }
1141
+ const newSelection = e.target;
1142
+ newSelection.setAttribute('currentselection', 'true');
1143
+ this.currentElementSpec = newSelection;
1144
+ }
1145
+
1146
+ nsDisabled() {
1147
+ return !this.useNamespace;
1148
+ }
1149
+
1150
+ _handleLoadError(e) {
1151
+ console.log('loading error occurred: ', e);
1152
+ const msg = this.shadowRoot.getElementById('errorMsg');
1153
+ msg.style.background = 'red';
1154
+ const { url } = this.shadowRoot.getElementById('loadContent');
1155
+ console.log('url ', url);
1156
+ msg.show('Error: ', `ODD file could not be loaded from ${url}`);
1157
+ }
1158
+
1159
+ handleElementSpecChanged(e) {
1160
+ // console.log('handleElementSpecChanged ',e);
1161
+ this._hasChanges = true;
1162
+ const elementSpec = this.elementSpecs.find(es => es.ident === e.detail.ident);
1163
+ const index = this.elementSpecs.indexOf(elementSpec);
1164
+ const newSpec = { ...elementSpec, models: e.detail.models };
1165
+ const allSpecs = Array.from(this.elementSpecs);
1166
+ allSpecs.splice(index, 1, newSpec);
1167
+ this.elementSpecs = allSpecs;
1168
+ // console.log('updated elementspecs ', this.elementSpecs);
1169
+ }
1170
+
1171
+ _inputTitle(ev) {
1172
+ this.title = ev.composedPath()[0].value;
1173
+ }
1076
1174
  }
1077
1175
 
1078
1176
  customElements.define('pb-odd-editor', PbOddEditor);