@teipublisher/pb-components 2.26.1-next.3 → 3.0.0

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