@json-editor/json-editor 2.9.0-beta.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -1
- package/README.md +16 -7
- package/dist/jsoneditor.js +2 -2
- package/dist/jsoneditor.js.LICENSE.txt +15 -0
- package/dist/jsoneditor.js.map +1 -0
- package/dist/nonmin/jsoneditor.js +989 -127
- package/dist/nonmin/jsoneditor.js.map +1 -1
- package/docs/index.html +22 -10
- package/docs/meta_schema.json +3 -2
- package/docs/starrating.html +2 -6
- package/package.json +4 -2
- package/src/defaults.js +9 -1
- package/src/editor.js +17 -3
- package/src/editors/array.js +7 -4
- package/src/editors/multiselect.js +1 -0
- package/src/editors/object.css +3 -3
- package/src/editors/object.css.js +1 -1
- package/src/editors/object.js +5 -2
- package/src/editors/table.js +11 -4
- package/src/editors/upload.js +3 -2
- package/src/themes/barebones.js +3 -1
- package/src/themes/bootstrap5.css +97 -0
- package/src/themes/bootstrap5.css.js +3 -0
- package/src/themes/bootstrap5.js +623 -0
- package/src/themes/index.js +2 -0
- package/src/themes/tailwind.js +2 -2
- package/tests/codeceptjs/core_test.js +107 -17
- package/tests/codeceptjs/editors/array_test.js +6 -5
- package/tests/codeceptjs/editors/button_test.js +7 -6
- package/tests/codeceptjs/editors/checkbox_test.js +3 -2
- package/tests/codeceptjs/editors/integer_test.js +3 -2
- package/tests/codeceptjs/editors/issues/issue-gh-1158_test.js +10 -0
- package/tests/codeceptjs/editors/issues/issue-gh-1257_test.js +13 -0
- package/tests/codeceptjs/editors/number_test.js +2 -1
- package/tests/codeceptjs/editors/object_test.js +39 -38
- package/tests/codeceptjs/editors/option-no_default_values_test.js +1 -1
- package/tests/codeceptjs/editors/programmatic-changes_test.js +3 -2
- package/tests/codeceptjs/editors/tabs_test.js +5 -3
- package/tests/codeceptjs/editors/validation_test.js +3 -1
- package/tests/codeceptjs/meta-schema_test.js +72 -4
- package/tests/codeceptjs/schemaloader_test.js +2 -1
- package/tests/codeceptjs/test-config.js +3 -0
- package/tests/codeceptjs/themes_test.js +14 -0
- package/tests/pages/anyof-2.html +90 -0
- package/tests/pages/anyof.html +1 -1
- package/tests/pages/container-attributes.html +50 -0
- package/tests/pages/issues/issue-gh-1158.html +50 -0
- package/tests/pages/issues/issue-gh-1233-failing.html +46 -0
- package/tests/pages/issues/issue-gh-1233-passing.html +49 -0
- package/tests/pages/issues/issue-gh-1257.html +77 -0
- package/tests/pages/meta-schema.html +747 -0
- package/tests/pages/meta_schema.json +3 -16
- package/tests/pages/oneof-2.html +90 -0
- package/tests/pages/per-editor-options.html +44 -0
- package/tests/pages/stepper.html +2 -2
- package/tests/pages/themes.html +2 -0
- /package/tests/pages/{table-move-events.html → array-events-table.html} +0 -0
- /package/tests/pages/{array-move-events.html → array-events.html} +0 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
import { AbstractTheme } from '../theme.js'
|
|
2
|
+
import rules from './bootstrap5.css.js'
|
|
3
|
+
import { trigger } from '../utilities'
|
|
4
|
+
|
|
5
|
+
/* Theme config options that allows changing various aspects of the output */
|
|
6
|
+
const options = {
|
|
7
|
+
disable_theme_rules: false,
|
|
8
|
+
input_size: 'normal', /* Size of input and select elements. "small", "normal", "large" */
|
|
9
|
+
object_indent: true, /* Indent nested object elements (use nested .card layout) */
|
|
10
|
+
object_background: 'bg-light', /* Bootstrap 4 card background modifier class */
|
|
11
|
+
object_text: '', /* Bootstrap 5 card text color modifier class */
|
|
12
|
+
table_border: false, /* Add border to array "table" row and cells */
|
|
13
|
+
table_zebrastyle: false, /* Add "zebra style" to array "table" rows */
|
|
14
|
+
tooltip: 'bootstrap' /* how to display tooltips (infoText). Can be `browser` for native `title`, `css` for simple CSS Styling, or `bootstrap` for TWBS/Popper.js handling */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class bootstrap5Theme extends AbstractTheme {
|
|
18
|
+
constructor (jsoneditor) {
|
|
19
|
+
super(jsoneditor, options)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getSelectInput (options, multiple) {
|
|
23
|
+
const el = super.getSelectInput(options)
|
|
24
|
+
el.classList.add('form-control')
|
|
25
|
+
el.classList.add('form-select')
|
|
26
|
+
if (this.options.input_size === 'small') el.classList.add('form-control-sm')
|
|
27
|
+
if (this.options.input_size === 'large') el.classList.add('form-control-lg')
|
|
28
|
+
|
|
29
|
+
return el
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getContainer () {
|
|
33
|
+
const el = document.createElement('div')
|
|
34
|
+
if (!this.options.object_indent) el.classList.add('je-noindent')
|
|
35
|
+
return el
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setGridColumnSize (el, size, offset) {
|
|
39
|
+
el.classList.add(`col-md-${size}`)
|
|
40
|
+
|
|
41
|
+
if (offset) {
|
|
42
|
+
el.classList.add(`offset-md-${offset}`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
afterInputReady (input) {
|
|
47
|
+
if (input.controlgroup) return
|
|
48
|
+
|
|
49
|
+
/* set id/for */
|
|
50
|
+
/* is not working for: [type=file], [type=checkbox] */
|
|
51
|
+
const id = input.name
|
|
52
|
+
input.id = id
|
|
53
|
+
/* 2x parentNode, b/c range input has an <div> wrapper */
|
|
54
|
+
const label = input.parentNode.parentNode.getElementsByTagName('label')[0]
|
|
55
|
+
if (label) {
|
|
56
|
+
label.classList.add('form-label')
|
|
57
|
+
label.htmlFor = id
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
input.controlgroup = this.closest(input, '.form-group')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getTextareaInput () {
|
|
64
|
+
const el = document.createElement('textarea')
|
|
65
|
+
el.classList.add('form-control')
|
|
66
|
+
if (this.options.input_size === 'small') el.classList.add('form-control-sm')
|
|
67
|
+
if (this.options.input_size === 'large') el.classList.add('form-control-lg')
|
|
68
|
+
return el
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getRangeInput (min, max, step) {
|
|
72
|
+
const el = super.getRangeInput(min, max, step)
|
|
73
|
+
el.classList.remove('form-control')
|
|
74
|
+
el.classList.add('form-range')
|
|
75
|
+
return el
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getStepperButtons (input) {
|
|
79
|
+
const inputGroup = document.createElement('div')
|
|
80
|
+
|
|
81
|
+
const minusBtn = document.createElement('button')
|
|
82
|
+
minusBtn.setAttribute('type', 'button')
|
|
83
|
+
|
|
84
|
+
const plusBtn = document.createElement('button')
|
|
85
|
+
plusBtn.setAttribute('type', 'button')
|
|
86
|
+
|
|
87
|
+
inputGroup.appendChild(minusBtn)
|
|
88
|
+
inputGroup.appendChild(input)
|
|
89
|
+
inputGroup.appendChild(plusBtn)
|
|
90
|
+
|
|
91
|
+
inputGroup.classList.add('input-group')
|
|
92
|
+
minusBtn.classList.add('btn')
|
|
93
|
+
minusBtn.classList.add('btn-secondary')
|
|
94
|
+
minusBtn.classList.add('stepper-down')
|
|
95
|
+
plusBtn.classList.add('btn')
|
|
96
|
+
plusBtn.classList.add('btn-secondary')
|
|
97
|
+
plusBtn.classList.add('stepper-up')
|
|
98
|
+
|
|
99
|
+
const readonly = input.getAttribute('readonly')
|
|
100
|
+
|
|
101
|
+
if (readonly) {
|
|
102
|
+
minusBtn.setAttribute('disabled', true)
|
|
103
|
+
plusBtn.setAttribute('disabled', true)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
minusBtn.textContent = '-'
|
|
107
|
+
plusBtn.textContent = '+'
|
|
108
|
+
|
|
109
|
+
const initialize = (input, min) => {
|
|
110
|
+
if (min) {
|
|
111
|
+
input.value = Number(min)
|
|
112
|
+
} else {
|
|
113
|
+
input.value = Number(input.value)
|
|
114
|
+
}
|
|
115
|
+
input.setAttribute('initialized', '1')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const min = input.getAttribute('min')
|
|
119
|
+
const max = input.getAttribute('max')
|
|
120
|
+
|
|
121
|
+
input.addEventListener('change', () => {
|
|
122
|
+
if (!input.getAttribute('initialized')) {
|
|
123
|
+
input.setAttribute('initialized', '1')
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
minusBtn.addEventListener('click', () => {
|
|
128
|
+
if (!input.getAttribute('initialized')) {
|
|
129
|
+
initialize(input, min)
|
|
130
|
+
} else if (min) {
|
|
131
|
+
if (Number(input.value) > Number(min)) {
|
|
132
|
+
input.stepDown()
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
input.stepDown()
|
|
136
|
+
}
|
|
137
|
+
trigger(input, 'change')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
plusBtn.addEventListener('click', () => {
|
|
141
|
+
if (!input.getAttribute('initialized')) {
|
|
142
|
+
initialize(input, min)
|
|
143
|
+
} else if (max) {
|
|
144
|
+
if (Number(input.value) < Number(max)) {
|
|
145
|
+
input.stepUp()
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
input.stepUp()
|
|
149
|
+
}
|
|
150
|
+
trigger(input, 'change')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
return inputGroup
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
getFormInputField (type) {
|
|
157
|
+
const el = super.getFormInputField(type)
|
|
158
|
+
if (type !== 'checkbox' && type !== 'radio') {
|
|
159
|
+
el.classList.add('form-control')
|
|
160
|
+
if (this.options.input_size === 'small') el.classList.add('form-control-sm')
|
|
161
|
+
if (this.options.input_size === 'large') el.classList.add('form-control-lg')
|
|
162
|
+
}
|
|
163
|
+
return el
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getFormControl (label, input, description, infoText) {
|
|
167
|
+
const group = document.createElement('div')
|
|
168
|
+
group.classList.add('form-group')
|
|
169
|
+
|
|
170
|
+
if (label && (input.type === 'checkbox' || input.type === 'radio')) {
|
|
171
|
+
const check = document.createElement('div')
|
|
172
|
+
|
|
173
|
+
check.classList.add('form-check')
|
|
174
|
+
input.classList.add('form-check-input')
|
|
175
|
+
label.classList.add('form-check-label')
|
|
176
|
+
|
|
177
|
+
const unique = (Date.now() * Math.random()).toFixed(0)
|
|
178
|
+
input.setAttribute('id', unique)
|
|
179
|
+
label.setAttribute('for', unique)
|
|
180
|
+
|
|
181
|
+
check.appendChild(input)
|
|
182
|
+
check.appendChild(label)
|
|
183
|
+
if (infoText) check.appendChild(infoText)
|
|
184
|
+
|
|
185
|
+
group.appendChild(check)
|
|
186
|
+
} else {
|
|
187
|
+
if (label) {
|
|
188
|
+
label.classList.add('form-label')
|
|
189
|
+
group.appendChild(label)
|
|
190
|
+
|
|
191
|
+
if (infoText) group.appendChild(infoText)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
group.appendChild(input)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (description) {
|
|
198
|
+
group.appendChild(description)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return group
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
getInfoButton (text) {
|
|
205
|
+
const button = document.createElement('button') /* shoud be a <button> but no fitting tbws style... */
|
|
206
|
+
button.type = 'button'
|
|
207
|
+
button.classList.add('ms-3', 'jsoneditor-twbs5-text-button')
|
|
208
|
+
button.setAttribute('data-toggle', 'tooltip')
|
|
209
|
+
button.setAttribute('data-placement', 'auto')
|
|
210
|
+
button.title = text
|
|
211
|
+
|
|
212
|
+
const icon = document.createTextNode('ⓘ')
|
|
213
|
+
button.appendChild(icon)
|
|
214
|
+
|
|
215
|
+
if (this.options.tooltip === 'bootstrap') {
|
|
216
|
+
if (window.jQuery && window.jQuery().tooltip) {
|
|
217
|
+
window.jQuery(button).tooltip()
|
|
218
|
+
} else {
|
|
219
|
+
// eslint-disable-next-line no-console
|
|
220
|
+
console.warn('Could not find popper jQuery plugin of Bootstrap.')
|
|
221
|
+
}
|
|
222
|
+
} else if (this.options.tooltip === 'css') {
|
|
223
|
+
button.classList.add('je-tooltip')
|
|
224
|
+
} /* else -> nothing todo for native [title] handling */
|
|
225
|
+
|
|
226
|
+
return button
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Generates a checkbox...
|
|
231
|
+
*
|
|
232
|
+
* Overwriten from master theme to get rid of inline styles.
|
|
233
|
+
*/
|
|
234
|
+
getCheckbox () {
|
|
235
|
+
const el = this.getFormInputField('checkbox')
|
|
236
|
+
return el
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Multiple checkboxes in a row.
|
|
241
|
+
*
|
|
242
|
+
*/
|
|
243
|
+
getMultiCheckboxHolder (controls, label, description, infoText) {
|
|
244
|
+
const el = document.createElement('div')
|
|
245
|
+
el.classList.add('form-group')
|
|
246
|
+
|
|
247
|
+
if (label) {
|
|
248
|
+
el.appendChild(label)
|
|
249
|
+
|
|
250
|
+
if (infoText) {
|
|
251
|
+
label.appendChild(infoText)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* for inline view we need an container so it doesnt wrap in the "row" of the <label> */
|
|
256
|
+
const container = document.createElement('div')
|
|
257
|
+
|
|
258
|
+
Object.values(controls).forEach(c => {
|
|
259
|
+
/* controls are already parsed by getFormControl() so they have an .form-group */
|
|
260
|
+
/* wrapper we need to get rid of... */
|
|
261
|
+
const ctrl = c.firstChild
|
|
262
|
+
|
|
263
|
+
container.appendChild(ctrl)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
el.appendChild(container)
|
|
267
|
+
|
|
268
|
+
if (description) el.appendChild(description)
|
|
269
|
+
|
|
270
|
+
return el
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Single radio element
|
|
275
|
+
*/
|
|
276
|
+
getFormRadio (attributes) {
|
|
277
|
+
const el = this.getFormInputField('radio')
|
|
278
|
+
|
|
279
|
+
for (const key in attributes) {
|
|
280
|
+
el.setAttribute(key, attributes[key])
|
|
281
|
+
}
|
|
282
|
+
el.classList.add('form-check-input')
|
|
283
|
+
|
|
284
|
+
return el
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Add the <label> for the single radio from getFormRadio()
|
|
289
|
+
*
|
|
290
|
+
*/
|
|
291
|
+
getFormRadioLabel (text, req) {
|
|
292
|
+
const el = document.createElement('label')
|
|
293
|
+
|
|
294
|
+
el.classList.add('form-check-label')
|
|
295
|
+
el.appendChild(document.createTextNode(text))
|
|
296
|
+
return el
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Stack the radios from getFormRadio()/getFormRadioLabel()
|
|
301
|
+
*
|
|
302
|
+
*/
|
|
303
|
+
getFormRadioControl (label, input, compact) {
|
|
304
|
+
const el = document.createElement('div')
|
|
305
|
+
|
|
306
|
+
el.classList.add('form-check')
|
|
307
|
+
|
|
308
|
+
el.appendChild(input)
|
|
309
|
+
el.appendChild(label)
|
|
310
|
+
|
|
311
|
+
if (compact) {
|
|
312
|
+
el.classList.add('form-check-inline')
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return el
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
getIndentedPanel () {
|
|
319
|
+
const el = document.createElement('div')
|
|
320
|
+
el.classList.add('card', 'card-body', 'my-3')
|
|
321
|
+
|
|
322
|
+
if (this.options.object_background) {
|
|
323
|
+
el.classList.add(this.options.object_background)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (this.options.object_text) {
|
|
327
|
+
el.classList.add(this.options.object_text)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* for better twbs card styling we should be able to return a nested div */
|
|
331
|
+
|
|
332
|
+
return el
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
getFormInputDescription (text) {
|
|
336
|
+
const el = document.createElement('small')
|
|
337
|
+
el.classList.add('form-text')
|
|
338
|
+
el.classList.add('d-block')
|
|
339
|
+
|
|
340
|
+
if (window.DOMPurify) {
|
|
341
|
+
el.innerHTML = window.DOMPurify.sanitize(text)
|
|
342
|
+
} else {
|
|
343
|
+
el.textContent = this.cleanText(text)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return el
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
getHeader (text, pathDepth) {
|
|
350
|
+
const el = document.createElement('h3')
|
|
351
|
+
el.classList.add('card-title')
|
|
352
|
+
el.classList.add('level-' + pathDepth)
|
|
353
|
+
|
|
354
|
+
if (typeof text === 'string') {
|
|
355
|
+
el.textContent = text
|
|
356
|
+
} else {
|
|
357
|
+
el.appendChild(text)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
el.style.display = 'inline-block'
|
|
361
|
+
|
|
362
|
+
return el
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
getHeaderButtonHolder () {
|
|
366
|
+
const el = this.getButtonHolder()
|
|
367
|
+
|
|
368
|
+
return el
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
getButtonHolder () {
|
|
372
|
+
const el = document.createElement('span')
|
|
373
|
+
el.classList.add('btn-group')
|
|
374
|
+
return el
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
getFormButtonHolder (buttonAlign) {
|
|
378
|
+
const el = this.getButtonHolder()
|
|
379
|
+
el.classList.add('d-block')
|
|
380
|
+
|
|
381
|
+
if (buttonAlign === 'center') el.classList.add('text-center')
|
|
382
|
+
else if (buttonAlign === 'right') el.classList.add('text-end')
|
|
383
|
+
|
|
384
|
+
return el
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
getButton (text, icon, title) {
|
|
388
|
+
const el = super.getButton(text, icon, title)
|
|
389
|
+
el.classList.add('btn', 'btn-secondary', 'btn-sm')
|
|
390
|
+
return el
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
getTable () {
|
|
394
|
+
const el = document.createElement('table')
|
|
395
|
+
el.classList.add('table', 'table-sm')
|
|
396
|
+
|
|
397
|
+
if (this.options.table_border) {
|
|
398
|
+
el.classList.add('table-bordered')
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (this.options.table_zebrastyle) {
|
|
402
|
+
el.classList.add('table-striped')
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return el
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
getErrorMessage (text) {
|
|
409
|
+
const el = document.createElement('div')
|
|
410
|
+
el.classList.add('alert', 'alert-danger')
|
|
411
|
+
el.setAttribute('role', 'alert')
|
|
412
|
+
el.appendChild(document.createTextNode(text))
|
|
413
|
+
return el
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* input validation on <input>
|
|
418
|
+
*/
|
|
419
|
+
addInputError (input, text) {
|
|
420
|
+
if (!input.controlgroup) return
|
|
421
|
+
|
|
422
|
+
input.controlgroup.classList.add('is-invalid')
|
|
423
|
+
|
|
424
|
+
if (!input.errmsg) {
|
|
425
|
+
input.errmsg = document.createElement('p')
|
|
426
|
+
input.errmsg.classList.add('invalid-feedback')
|
|
427
|
+
input.controlgroup.appendChild(input.errmsg)
|
|
428
|
+
input.errmsg.style.display = 'block'
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
input.errmsg.style.display = 'block'
|
|
432
|
+
input.errmsg.textContent = text
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
removeInputError (input) {
|
|
436
|
+
if (!input.errmsg) return
|
|
437
|
+
input.errmsg.style.display = 'none'
|
|
438
|
+
input.controlgroup.classList.remove('is-invalid')
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
getTabHolder (propertyName) {
|
|
442
|
+
const el = document.createElement('div')
|
|
443
|
+
const pName = (typeof propertyName === 'undefined') ? '' : propertyName
|
|
444
|
+
el.innerHTML = `<div class='col-md-2' id='${pName}'><ul class='nav flex-column nav-pills'></ul></div><div class='col-md-10'><div class='tab-content' id='${pName}'></div></div>`
|
|
445
|
+
el.classList.add('row')
|
|
446
|
+
return el
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
addTab (holder, tab) {
|
|
450
|
+
holder.children[0].children[0].appendChild(tab)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
getTabContentHolder (tabHolder) {
|
|
454
|
+
return tabHolder.children[1].children[0]
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
getTopTabHolder (propertyName) {
|
|
458
|
+
const pName = (typeof propertyName === 'undefined') ? '' : propertyName
|
|
459
|
+
|
|
460
|
+
const el = document.createElement('div')
|
|
461
|
+
el.classList.add('card')
|
|
462
|
+
|
|
463
|
+
el.innerHTML = `<div class='card-header'><ul class='nav nav-tabs card-header-tabs' id='${pName}'></ul></div><div class='card-body'><div class='tab-content' id='${pName}'></div></div>`
|
|
464
|
+
|
|
465
|
+
return el
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
getTab (text, tabId) {
|
|
469
|
+
const liel = document.createElement('li')
|
|
470
|
+
liel.classList.add('nav-item')
|
|
471
|
+
|
|
472
|
+
const ael = document.createElement('a')
|
|
473
|
+
ael.classList.add('nav-link')
|
|
474
|
+
ael.setAttribute('href', `#${tabId}`)
|
|
475
|
+
ael.setAttribute('data-toggle', 'tab')
|
|
476
|
+
ael.appendChild(text)
|
|
477
|
+
|
|
478
|
+
liel.appendChild(ael)
|
|
479
|
+
|
|
480
|
+
return liel
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
getTopTab (text, tabId) {
|
|
484
|
+
const el = document.createElement('li')
|
|
485
|
+
el.classList.add('nav-item')
|
|
486
|
+
|
|
487
|
+
const a = document.createElement('a')
|
|
488
|
+
a.classList.add('nav-link')
|
|
489
|
+
a.setAttribute('href', `#${tabId}`)
|
|
490
|
+
a.setAttribute('data-toggle', 'tab')
|
|
491
|
+
a.appendChild(text)
|
|
492
|
+
|
|
493
|
+
el.appendChild(a)
|
|
494
|
+
|
|
495
|
+
return el
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
getTabContent () {
|
|
499
|
+
const el = document.createElement('div')
|
|
500
|
+
el.classList.add('tab-pane')
|
|
501
|
+
el.setAttribute('role', 'tabpanel')
|
|
502
|
+
return el
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
getTopTabContent () {
|
|
506
|
+
const el = document.createElement('div')
|
|
507
|
+
el.classList.add('tab-pane')
|
|
508
|
+
el.setAttribute('role', 'tabpanel')
|
|
509
|
+
return el
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
markTabActive (row) {
|
|
513
|
+
row.tab.firstChild.classList.add('active')
|
|
514
|
+
|
|
515
|
+
if (typeof row.rowPane !== 'undefined') {
|
|
516
|
+
row.rowPane.classList.add('active')
|
|
517
|
+
} else {
|
|
518
|
+
row.container.classList.add('active')
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
markTabInactive (row) {
|
|
523
|
+
row.tab.firstChild.classList.remove('active')
|
|
524
|
+
|
|
525
|
+
if (typeof row.rowPane !== 'undefined') {
|
|
526
|
+
row.rowPane.classList.remove('active')
|
|
527
|
+
} else {
|
|
528
|
+
row.container.classList.remove('active')
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
insertBasicTopTab (tab, newTabsHolder) {
|
|
533
|
+
newTabsHolder.children[0].children[0].insertBefore(tab, newTabsHolder.children[0].children[0].firstChild)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
addTopTab (holder, tab) {
|
|
537
|
+
holder.children[0].children[0].appendChild(tab)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
getTopTabContentHolder (tabHolder) {
|
|
541
|
+
return tabHolder.children[1].children[0]
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
getFirstTab (holder) {
|
|
545
|
+
return holder.firstChild.firstChild.firstChild
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
getProgressBar () {
|
|
549
|
+
const min = 0
|
|
550
|
+
const max = 100
|
|
551
|
+
const start = 0
|
|
552
|
+
|
|
553
|
+
const container = document.createElement('div')
|
|
554
|
+
container.classList.add('progress')
|
|
555
|
+
|
|
556
|
+
const bar = document.createElement('div')
|
|
557
|
+
bar.classList.add('progress-bar')
|
|
558
|
+
bar.setAttribute('role', 'progressbar')
|
|
559
|
+
bar.setAttribute('aria-valuenow', start)
|
|
560
|
+
bar.setAttribute('aria-valuemin', min)
|
|
561
|
+
bar.setAttribute('aria-valuenax', max)
|
|
562
|
+
bar.innerHTML = `${start}%`
|
|
563
|
+
container.appendChild(bar)
|
|
564
|
+
|
|
565
|
+
return container
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
updateProgressBar (progressBar, progress) {
|
|
569
|
+
if (!progressBar) return
|
|
570
|
+
|
|
571
|
+
const bar = progressBar.firstChild
|
|
572
|
+
const percentage = `${progress}%`
|
|
573
|
+
bar.setAttribute('aria-valuenow', progress)
|
|
574
|
+
bar.style.width = percentage
|
|
575
|
+
bar.innerHTML = percentage
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
updateProgressBarUnknown (progressBar) {
|
|
579
|
+
if (!progressBar) return
|
|
580
|
+
|
|
581
|
+
const bar = progressBar.firstChild
|
|
582
|
+
progressBar.classList.add('progress', 'progress-striped', 'active')
|
|
583
|
+
bar.removeAttribute('aria-valuenow')
|
|
584
|
+
bar.style.width = '100%'
|
|
585
|
+
bar.innerHTML = ''
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
getBlockLink () {
|
|
589
|
+
const link = document.createElement('a')
|
|
590
|
+
link.classList.add('mb-3', 'd-inline-block')
|
|
591
|
+
return link
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Link after successfull upload
|
|
596
|
+
*/
|
|
597
|
+
getLinksHolder () {
|
|
598
|
+
const el = document.createElement('div')
|
|
599
|
+
return el
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
getInputGroup (input, buttons) {
|
|
603
|
+
if (!input) return
|
|
604
|
+
|
|
605
|
+
const inputGroupContainer = document.createElement('div')
|
|
606
|
+
inputGroupContainer.classList.add('input-group')
|
|
607
|
+
|
|
608
|
+
inputGroupContainer.appendChild(input)
|
|
609
|
+
|
|
610
|
+
for (let i = 0; i < buttons.length; i++) {
|
|
611
|
+
/* this uses the getButton() wrapper, so we have to remove the panel/ctrl spacing for this case */
|
|
612
|
+
buttons[i].classList.remove('me-2', 'btn-secondary')
|
|
613
|
+
buttons[i].classList.add('btn-outline-secondary')
|
|
614
|
+
|
|
615
|
+
inputGroupContainer.appendChild(buttons[i])
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return inputGroupContainer
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/* Custom stylesheet rules. format: "selector" : "CSS rules" */
|
|
623
|
+
bootstrap5Theme.rules = rules
|
package/src/themes/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { htmlTheme } from './html.js'
|
|
|
3
3
|
// import { bootstrap2Theme } from './bootstrap2'
|
|
4
4
|
import { bootstrap3Theme } from './bootstrap3.js'
|
|
5
5
|
import { bootstrap4Theme } from './bootstrap4.js'
|
|
6
|
+
import { bootstrap5Theme } from './bootstrap5.js'
|
|
6
7
|
// import { foundationTheme, foundation3Theme, foundation4Theme, foundation5Theme, foundation6Theme } from './foundation.js'
|
|
7
8
|
import { jqueryuiTheme } from './jqueryui.js'
|
|
8
9
|
import { barebonesTheme } from './barebones.js'
|
|
@@ -15,6 +16,7 @@ export const themes = {
|
|
|
15
16
|
// bootstrap2: bootstrap2Theme,
|
|
16
17
|
bootstrap3: bootstrap3Theme,
|
|
17
18
|
bootstrap4: bootstrap4Theme,
|
|
19
|
+
bootstrap5: bootstrap5Theme,
|
|
18
20
|
// foundation: foundationTheme,
|
|
19
21
|
// foundation3: foundation3Theme,
|
|
20
22
|
// foundation4: foundation4Theme,
|
package/src/themes/tailwind.js
CHANGED
|
@@ -277,7 +277,7 @@ export class tailwindTheme extends AbstractTheme {
|
|
|
277
277
|
addInputError (input, text) {
|
|
278
278
|
if (!input.controlgroup) return
|
|
279
279
|
input.controlgroup.classList.add('has-error')
|
|
280
|
-
input.classList.add('
|
|
280
|
+
input.controlgroup.classList.add('text-red-600')
|
|
281
281
|
if (!input.errmsg) {
|
|
282
282
|
input.errmsg = document.createElement('p')
|
|
283
283
|
input.errmsg.classList.add('block', 'mt-1', 'text-xs', 'text-red')
|
|
@@ -291,7 +291,7 @@ export class tailwindTheme extends AbstractTheme {
|
|
|
291
291
|
removeInputError (input) {
|
|
292
292
|
if (!input.errmsg) return
|
|
293
293
|
input.errmsg.style.display = 'none'
|
|
294
|
-
input.classList.remove('
|
|
294
|
+
input.controlgroup.classList.remove('text-red-600')
|
|
295
295
|
input.controlgroup.classList.remove('has-error')
|
|
296
296
|
}
|
|
297
297
|
|