djangocms-render-context 1.1.0__py3-none-any.whl → 1.2.1__py3-none-any.whl

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 (27) hide show
  1. djangocms_render_context/__init__.py +1 -1
  2. djangocms_render_context/cms_plugins.py +8 -0
  3. djangocms_render_context/encoders.py +8 -0
  4. djangocms_render_context/forms.py +46 -0
  5. djangocms_render_context/locale/cs/LC_MESSAGES/django.mo +0 -0
  6. djangocms_render_context/locale/cs/LC_MESSAGES/django.po +30 -2
  7. djangocms_render_context/locale/cs/LC_MESSAGES/djangojs.mo +0 -0
  8. djangocms_render_context/locale/cs/LC_MESSAGES/djangojs.po +130 -0
  9. djangocms_render_context/migrations/0003_rendercontext_config_and_path.py +46 -0
  10. djangocms_render_context/models.py +42 -5
  11. djangocms_render_context/static/djangocms_render_context/css/spreadsheet.css +15 -0
  12. djangocms_render_context/static/djangocms_render_context/css-dist/icon-family-Material-Icons.css +20 -0
  13. djangocms_render_context/static/djangocms_render_context/css-dist/jspreadsheet.min.css +8 -0
  14. djangocms_render_context/static/djangocms_render_context/css-dist/jsuites.min.css +8 -0
  15. djangocms_render_context/static/djangocms_render_context/js/spreadsheet.js +711 -0
  16. djangocms_render_context/static/djangocms_render_context/js-dist/csv.min.js +1 -0
  17. djangocms_render_context/static/djangocms_render_context/js-dist/index.min.js +8 -0
  18. djangocms_render_context/static/djangocms_render_context/js-dist/index.min.js.map +1 -0
  19. djangocms_render_context/static/djangocms_render_context/js-dist/js-yaml.min.js +2 -0
  20. djangocms_render_context/static/djangocms_render_context/js-dist/jsuites.min.js +8 -0
  21. djangocms_render_context/static/djangocms_render_context/js-dist/jsuites.min.js.map +1 -0
  22. djangocms_render_context/utils.py +16 -0
  23. {djangocms_render_context-1.1.0.dist-info → djangocms_render_context-1.2.1.dist-info}/METADATA +16 -1
  24. djangocms_render_context-1.2.1.dist-info/RECORD +32 -0
  25. {djangocms_render_context-1.1.0.dist-info → djangocms_render_context-1.2.1.dist-info}/WHEEL +1 -1
  26. djangocms_render_context-1.1.0.dist-info/RECORD +0 -17
  27. {djangocms_render_context-1.1.0.dist-info → djangocms_render_context-1.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,711 @@
1
+ // https://bossanova.uk/jspreadsheet/docs/getting-started
2
+ // https://github.com/jspreadsheet/editors
3
+ // https://jsuites.net/docs/javascript-html-editor
4
+ // https://jsuites.net/docs/v4/javascript-html-editor
5
+ /*
6
+ Available Editors:
7
+ text
8
+ numeric
9
+ hidden
10
+ dropdown
11
+ checkbox
12
+ radio
13
+ calendar
14
+ image
15
+ color
16
+ html
17
+ */
18
+
19
+ (function() {
20
+
21
+ const spreadsheetId = "id-spreadsheet"
22
+
23
+ function parseData(src, mimetype) {
24
+ let data = null
25
+ if (src.value) {
26
+ if (mimetype === "application/json") {
27
+ data = JSON.parse(src.value)
28
+ } else if (mimetype === "text/csv") {
29
+ data = CSV.parse(src.value)
30
+ } else if (mimetype === "application/yaml") {
31
+ data = jsyaml.load(src.value)
32
+ } else if (mimetype === "application/xml") {
33
+ data = parseXml(src.value)
34
+ }
35
+ }
36
+ return data
37
+ }
38
+
39
+ function parseXml(src) {
40
+ const data = {}
41
+ const parser = new DOMParser()
42
+ const doc = parser.parseFromString(src, "text/xml")
43
+ const root = doc.querySelector("*")
44
+ data[root.tagName] = {}
45
+ if (!root.children.length) {
46
+ return data
47
+ }
48
+ const table = []
49
+ for(const row of root.children) {
50
+ const line = {}
51
+ for(const column of row.children) {
52
+ line[column.tagName] = column.innerHTML
53
+ }
54
+ table.push(line)
55
+ }
56
+ data[root.tagName][root.children[0].tagName] = table
57
+ return data
58
+ }
59
+
60
+ function objectToXml(obj, params, level, name) {
61
+ let xml = ""
62
+ if (obj instanceof Object) {
63
+ const rootMissing = name === undefined && level === 0 && params.options.tableNameMissing
64
+ if (rootMissing) {
65
+ xml += `<${params.options.table}>`
66
+ }
67
+ if (Array.isArray(obj)) {
68
+ const subname = name === undefined ? (level ? params.options.table : params.options.row) : name
69
+ const columnMissing = level > 0 && params.options.columnName
70
+ if (columnMissing) {
71
+ xml += `<${params.options.columnName}>`
72
+ }
73
+ for(let key=0; key < obj.length; key++) {
74
+ xml += objectToXml(obj[key], params, level+1, subname)
75
+ }
76
+ if (columnMissing) {
77
+ xml += `</${params.options.columnName}>`
78
+ }
79
+ } else {
80
+ if (name !== undefined) {
81
+ xml += `<${name}>`
82
+ }
83
+ for (const key in obj) {
84
+ xml += objectToXml(obj[key], params, level+1, key)
85
+ }
86
+ if (name !== undefined) {
87
+ xml += `</${name}>`
88
+ }
89
+ }
90
+ if (rootMissing) {
91
+ xml += `</${params.options.table}>`
92
+ }
93
+ } else {
94
+ xml += name !== undefined ? `<${name}>${obj}</${name}>` : obj
95
+ }
96
+ return xml
97
+ }
98
+
99
+ function formatXml(xml) {
100
+ const PADDING = " "
101
+ const reg = /(>)(<)(\/*)/g
102
+ let pad = 0
103
+ xml = xml.replace(reg, '$1\r\n$2$3')
104
+ return xml.split('\r\n').map((node) => {
105
+ let indent = 0
106
+ if (node.match(/.+<\/\w[^>]*>$/)) {
107
+ indent = 0
108
+ } else if (node.match(/^<\/\w/)) {
109
+ if (pad !== 0) pad -= 1
110
+ } else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
111
+ indent = 1
112
+ }
113
+ const padding = PADDING.repeat(pad)
114
+ pad += indent
115
+ return padding + node
116
+ }).join('\r\n')
117
+ }
118
+
119
+ function dumpXml(data, params) {
120
+ if (Array.isArray(data)) {
121
+ params.options.tableNameMissing = true
122
+ if (data.length && Array.isArray(data[0])) {
123
+ params.options.columnName = "item"
124
+ }
125
+ }
126
+ if (isObj(data)) {
127
+ for (const key in data) {
128
+ if (Array.isArray(data[key])) {
129
+ params.options.tableNameMissing = true
130
+ break
131
+ }
132
+ }
133
+ }
134
+ return formatXml(objectToXml(data, params, 0))
135
+ }
136
+
137
+
138
+ function setDataIntoContext(data, params) {
139
+ const mimetype = document.querySelector("select[name=mimetype]").value
140
+ if (mimetype === "text/csv" && isObj(data)) {
141
+ throw new Error(gettext("This data cannot be serialized in the selected format. Please select a different format."))
142
+ }
143
+ let value
144
+ if (mimetype === "application/json") {
145
+ value = JSON.stringify(data, null, 2)
146
+ } else if (mimetype === "text/csv") {
147
+ value = CSV.serialize(data)
148
+ } else if (mimetype === "application/yaml") {
149
+ value = jsyaml.dump(data)
150
+ } else if (mimetype === "application/xml") {
151
+ value = dumpXml(data, params)
152
+ }
153
+ document.querySelector("textarea[name=context]").value = value
154
+ }
155
+
156
+ function stripCells(row) {
157
+ const cells = []
158
+ let isContent = false
159
+ for (let i = row.length - 1; i >= 0; i--) {
160
+ if (isContent || row[i]) {
161
+ isContent = true
162
+ cells.push(row[i])
163
+ }
164
+ }
165
+ return cells.reverse()
166
+ }
167
+
168
+ function removeEmptyRows(data) {
169
+ const table = []
170
+ let isContent = false
171
+ for (let i = data.length - 1; i >= 0; i--) {
172
+ const cells = stripCells(data[i])
173
+ if (isContent || cells.length) {
174
+ isContent = true
175
+ table.push(cells.length ? cells : data[i])
176
+ }
177
+ }
178
+ return table.reverse()
179
+ }
180
+
181
+ function createSpreadsheetNode() {
182
+ const context = document.querySelector("textarea[name=context]")
183
+ const node = document.createElement("div")
184
+ node.id = spreadsheetId
185
+ context.after(node)
186
+ }
187
+
188
+ function setSpreadsheetTranslations() {
189
+ window.jspreadsheet.setDictionary({
190
+ 'Are you sure?': gettext('Are you sure?'),
191
+ 'Rename this cell': gettext('Rename this cell'),
192
+ 'Cut': gettext('Cut'),
193
+ 'Copy': gettext('Copy'),
194
+ 'Paste': gettext('Paste'),
195
+ 'Insert a new column before': gettext('Insert a new column before'),
196
+ 'Insert a new column after': gettext('Insert a new column after'),
197
+ 'Insert a new row before': gettext('Insert a new row before'),
198
+ 'Insert a new row after': gettext('Insert a new row after'),
199
+ 'Delete selected columns': gettext('Delete selected columns'),
200
+ 'Delete selected rows': gettext('Delete selected rows'),
201
+ 'Rename this column': gettext('Rename this column'),
202
+ 'Add comments': gettext('Add comments'),
203
+ 'Edit comments': gettext('Edit comments'),
204
+ 'Clear comments': gettext('Clear comments'),
205
+ 'Order ascending': gettext('Order ascending'),
206
+ 'Order descending': gettext('Order descending'),
207
+ 'Save as': gettext('Save as'),
208
+ 'About': gettext('About'),
209
+ })
210
+ }
211
+
212
+ function displayError(message, title) {
213
+ if (!title) {
214
+ title = gettext("Error message")
215
+ }
216
+ jSuites.notification({
217
+ error: 1,
218
+ timeout: 60000,
219
+ // autoHide: false,
220
+ name: title,
221
+ message: message
222
+ })
223
+ }
224
+
225
+ function isObj(value) {
226
+ // Check if value is object.
227
+ return value instanceof Object && !Array.isArray(value)
228
+ }
229
+
230
+ function getPathsToArrays(obj, parent = "") {
231
+ let result = []
232
+ if (isObj(obj)) {
233
+ for (let key in obj) {
234
+ const path = parent ? `${parent}.${key}` : key
235
+ if (Array.isArray(obj[key])) {
236
+ result.push(path)
237
+ } else if (isObj(obj[key])) {
238
+ result = result.concat(getPathsToArrays(obj[key], path))
239
+ }
240
+ }
241
+ }
242
+ return result
243
+ }
244
+
245
+ function getPayload(obj, path) {
246
+ // Get objects data for the path.
247
+ path.split(".").forEach((key) => {
248
+ obj = obj[key]
249
+ })
250
+ return obj
251
+ }
252
+
253
+ function setPayload(obj, path, payload) {
254
+ // Set data into the object path.
255
+ const names = path.split(".")
256
+ const key = names.pop()
257
+ for(let i=0; i < names.length; i++) {
258
+ obj = obj[names[i]]
259
+ }
260
+ obj[key] = payload
261
+ }
262
+
263
+ function resolveColumnType(value) {
264
+ let type = "text"
265
+ if (Number.isInteger(value)) {
266
+ type = "numeric"
267
+ } else if (typeof value == "boolean") {
268
+ type = "checkbox"
269
+ } else if (typeof value === 'string') {
270
+ if (value.match(/#[A-Fa-f0-9]{6}/)) {
271
+ type = "color"
272
+ } else if (value.match(/\d{4}-\d{2}-\d{2}/)) {
273
+ type = "calendar"
274
+ } else if (value.match(/<.+>/)) {
275
+ type = "html"
276
+ }
277
+ }
278
+ return type
279
+ }
280
+
281
+ function getContextData(mimetype) {
282
+ return parseData(document.querySelector("textarea[name=context]"), mimetype)
283
+ }
284
+
285
+ function getTableName(path) {
286
+ const names = path.split(".").reverse()
287
+ return names.length > 1 ? names[1] : "table"
288
+ }
289
+
290
+ function getTableRowName(path) {
291
+ const names = path.split(".").reverse()
292
+ return names.length > 0 ? names[0] : "row"
293
+ }
294
+
295
+
296
+ function numberToColumn(num) {
297
+ let result = ""
298
+ while (num > 0) {
299
+ const remainder = (num - 1) % 26
300
+ result = String.fromCharCode(65 + remainder) + result
301
+ num = Math.floor((num - remainder) / 26)
302
+ }
303
+ return result
304
+ }
305
+
306
+ function convertDataToTableAndOptions(data) {
307
+ const tableData = [], tableOptions = {}
308
+ if (Array.isArray(data)) {
309
+ for(let r = 0; r < data.length; r++) {
310
+ const row = data[r]
311
+ if (Array.isArray(row)) {
312
+ tableData.push(row)
313
+ if (tableOptions.types === undefined) {
314
+ tableOptions.types = []
315
+ for(let c = 0; c < row.length; c++) {
316
+ tableOptions.types.push(resolveColumnType(row[c]))
317
+ }
318
+ }
319
+ } else if (isObj(row)) {
320
+ if (tableOptions.types === undefined) {
321
+ tableOptions.titles = []
322
+ tableOptions.types = []
323
+ for (const [key, value] of Object.entries(row)) {
324
+ tableOptions.titles.push(key)
325
+ tableOptions.types.push(resolveColumnType(value))
326
+ }
327
+ }
328
+ const columns = []
329
+ for (let c=0; c < tableOptions.titles.length; c++) {
330
+ columns.push(row[tableOptions.titles[c]])
331
+ }
332
+ tableData.push(columns)
333
+ } else {
334
+ tableOptions.types = [resolveColumnType(row)]
335
+ tableData.push([row])
336
+ }
337
+ }
338
+ if (!tableData.length) {
339
+ tableOptions.types = ["text"]
340
+ tableData.push([""])
341
+ }
342
+ } else {
343
+ tableData.push([data])
344
+ tableOptions.types = [resolveColumnType(data)]
345
+ }
346
+ return [tableData, tableOptions]
347
+ }
348
+
349
+
350
+ function addLink() {
351
+ const href = prompt(gettext("Enter a URL:"), "https://")
352
+ if (href) {
353
+ const sel = getSelection()
354
+ const label = sel.toString()
355
+ const link = document.createElement("a")
356
+ link.href = href
357
+ link.appendChild(document.createTextNode(label ? label : href))
358
+ const range = sel.getRangeAt(0)
359
+ range.deleteContents()
360
+ range.insertNode(link)
361
+ }
362
+ }
363
+
364
+ function onCreateEditor(sheet, td, x, y, empty, options) {
365
+ if (options.type === "html") {
366
+ setTimeout(() => {
367
+ const richtext = document.querySelector(".jss_richtext")
368
+ if (richtext) {
369
+ const item = richtext.querySelector(".jeditor-toolbar > div > div:nth-child(6)")
370
+ const button = item.cloneNode(true)
371
+ button.children[0].textContent = "link"
372
+ item.replaceWith(button)
373
+ button.onclick = addLink
374
+ const close = document.createElement("div")
375
+ close.style.cursor = "pointer"
376
+ close.style.textAlign = "center"
377
+ close.appendChild(document.createTextNode(gettext("(Press Alt+Enter to keep changes. / Alt+Q to cancel.)")))
378
+ close.title = gettext("Close this window.")
379
+ richtext.appendChild(close)
380
+ close.addEventListener("click", () => {
381
+ window.pluginSpreadsheet.closeEditor.call(richtext, td, true);
382
+ })
383
+ richtext.addEventListener("keydown", (event) => {
384
+ if(event.altKey && event.key == "Enter") {
385
+ window.pluginSpreadsheet.closeEditor.call(richtext, td, true)
386
+ } else if (event.altKey && event.key == "q") {
387
+ window.pluginSpreadsheet.closeEditor.call(richtext, td, false)
388
+ }
389
+ })
390
+ }
391
+ }, 100)
392
+ }
393
+ }
394
+
395
+ function getSpreadsheetConfig() {
396
+ const config = structuredClone(window.pluginSpreadsheet.getConfig())
397
+ delete config.data
398
+ // Remove default values.
399
+ const style = {}
400
+ for (const [key, value] of Object.entries(config.style)) {
401
+ if (value !== "text-align: center;") {
402
+ style[key] = value
403
+ }
404
+ }
405
+ config.style = style
406
+ return config
407
+ }
408
+
409
+ function setSpreadsheetConfig(sheetConfig, path, sheetIsOpen) {
410
+ const configNode = document.querySelector("textarea[name=config]")
411
+ let config = {}
412
+ if (configNode.value) {
413
+ config = JSON.parse(configNode.value)
414
+ if (config === null) {
415
+ config = {}
416
+ }
417
+ }
418
+ config[path] = sheetConfig
419
+ config.openedPath = sheetIsOpen ? path : null
420
+ configNode.value = JSON.stringify(config, null, 2)
421
+ }
422
+
423
+ function submitForm() {
424
+ const src = document.querySelector("textarea[name=context]")
425
+ const form = src.closest("form")
426
+ form.addEventListener('submit', (event) => {
427
+ if (window.pluginSpreadsheet) {
428
+ if (!saveSpreadsheetIntoFrom(true)) {
429
+ event.preventDefault()
430
+ return false
431
+ }
432
+ }
433
+ })
434
+ }
435
+
436
+ function createLinkButton(label, title, path, data) {
437
+ const link = document.createElement("a")
438
+ link.classList.add("btn")
439
+ link.disabled = true
440
+ link.style.cursor = "pointer"
441
+ if (title) {
442
+ link.title = title
443
+ }
444
+ if (path) {
445
+ link.dataset.path = path
446
+ }
447
+ if (data) {
448
+ link.dataset.options = JSON.stringify(data)
449
+ }
450
+ link.appendChild(document.createTextNode(label))
451
+ return link
452
+ }
453
+
454
+ function populateColumnsOptions(sheetConfig, tableOptions) {
455
+ for(let i = 0; i < tableOptions.types.length; i++) {
456
+ if (sheetConfig.columns[i] === undefined) {
457
+ sheetConfig.columns[i] = {type: tableOptions.types[i]}
458
+ }
459
+ if (sheetConfig.columns[i].title === undefined && tableOptions.titles && tableOptions.titles[i]) {
460
+ sheetConfig.columns[i].title = tableOptions.titles[i]
461
+ }
462
+ }
463
+ }
464
+
465
+ function toggleSelected(element) {
466
+ const parent = element.closest("div")
467
+ for(const link of parent.querySelectorAll("a.selected")) {
468
+ link.classList.remove("selected")
469
+ }
470
+ element.classList.add("selected")
471
+ }
472
+
473
+
474
+ function openJsSheet(button) {
475
+ if (button.classList.contains("selected")) {
476
+ return
477
+ }
478
+ if (window.pluginSpreadsheet) {
479
+ if (!saveSpreadsheetIntoFrom(true)) {
480
+ return
481
+ }
482
+ }
483
+ const mimetypeNone = document.querySelector("select[name=mimetype]")
484
+ button.dataset.mimetype = mimetypeNone.value
485
+ // Load table data and spreadsheet options.
486
+ let contextData, configOptions = {}
487
+ try {
488
+ contextData = getContextData(mimetypeNone.value)
489
+ } catch (error) {
490
+ displayError(error, gettext("Parse Data Error"))
491
+ return
492
+ }
493
+ const configValue = document.querySelector("textarea[name=config]").value
494
+ if (configValue) {
495
+ try {
496
+ configOptions = JSON.parse(configValue)
497
+ } catch (error) {
498
+ displayError(error, gettext("Error in Source settings"))
499
+ return
500
+ }
501
+ }
502
+
503
+ let payload
504
+ if (button.dataset.path !== ".") {
505
+ payload = getPayload(contextData, button.dataset.path)
506
+ } else {
507
+ payload = contextData
508
+ }
509
+ const [tableData, tableOptions] = convertDataToTableAndOptions(payload)
510
+ const path = button.dataset.path ? button.dataset.path : "."
511
+ let sheetConfig = (configOptions === null) ? null : configOptions[path]
512
+ if (sheetConfig) {
513
+ sheetConfig.data = tableData
514
+ } else {
515
+ sheetConfig = {minDimensions: [7, 10], data: tableData, columns: []}
516
+ }
517
+ populateColumnsOptions(sheetConfig, tableOptions)
518
+ createSpreadsheet(sheetConfig)
519
+ toggleSelected(button)
520
+ }
521
+
522
+ function createSpreadsheet(config) {
523
+ window.pluginSpreadsheet = window.jspreadsheet(document.getElementById(spreadsheetId), {
524
+ worksheets: [config],
525
+ oncreateeditor: onCreateEditor,
526
+ })[0]
527
+ document.querySelector("textarea[name=context]").style.display = "none"
528
+ document.querySelector("select[name=mimetype] option[value='application/vnd.oasis.opendocument.spreadsheet']").disabled = "disabled"
529
+ }
530
+
531
+ function destroySpreadsheet() {
532
+ jspreadsheet.destroy(document.getElementById(spreadsheetId))
533
+ window.pluginSpreadsheet = null
534
+ document.querySelector("textarea[name=context]").style.display = ""
535
+ document.querySelector("select[name=mimetype] option[value='application/vnd.oasis.opendocument.spreadsheet']").disabled = ""
536
+ }
537
+
538
+ function saveSpreadsheetIntoFrom(sheetIsOpen) {
539
+ const link = document.querySelector("#id-toggle-spreadsheet a.selected")
540
+ const mimetype = link.dataset.mimetype
541
+ let path = link.dataset.path
542
+ const options = link.dataset.options === undefined ? {} : JSON.parse(link.dataset.options)
543
+ const sheetData = removeEmptyRows(window.pluginSpreadsheet.getData())
544
+ let data
545
+ if (options.titles) {
546
+ data = convertDataIntoObjects(sheetData, options.titles)
547
+ } else {
548
+ data = sheetData
549
+ }
550
+ let contextData
551
+ if (path === ".") {
552
+ contextData = data
553
+ } else {
554
+ contextData = getContextData(mimetype)
555
+ setPayload(contextData, path, data)
556
+ }
557
+ try {
558
+ setDataIntoContext(contextData, {path: path, options: options})
559
+ } catch (error) {
560
+ displayError(error, gettext("Data serialization error"))
561
+ return false
562
+ }
563
+ const sheetConfig = getSpreadsheetConfig()
564
+ setSpreadsheetConfig(sheetConfig, path, sheetIsOpen)
565
+ destroySpreadsheet()
566
+ return true
567
+ }
568
+
569
+ function toggleSource(event) {
570
+ if (event.target.classList.contains("selected")) {
571
+ return
572
+ }
573
+ if (saveSpreadsheetIntoFrom(false)) {
574
+ toggleSelected(event.target)
575
+ appendSpreadsheetButtons()
576
+ }
577
+ }
578
+
579
+ function getColumnName(name, index) {
580
+ return name === undefined ? numberToColumn(index + 1) : name
581
+ }
582
+
583
+ function getUniqueName(name, names) {
584
+ let uname = name, index = 1
585
+ while (names.includes(uname)) {
586
+ uname = `${name}${++index}`
587
+ }
588
+ return uname
589
+ }
590
+
591
+ function convertDataIntoObjects(sheetData, titles) {
592
+ const data = []
593
+ for(let r=0; r < sheetData.length; r++) {
594
+ const line = {}
595
+ for(let c=0; c < sheetData[r].length; c++) {
596
+ const columnName = getUniqueName(getColumnName(titles[c], c), Object.keys(line))
597
+ line[columnName] = sheetData[r][c]
598
+ }
599
+ data.push(line)
600
+ }
601
+ return data
602
+ }
603
+
604
+ function createDefaultButton(linkFrame) {
605
+ const link = createLinkButton(gettext("Edit CSV"), gettext("Show data in spreadsheet."), ".")
606
+ link.addEventListener("click", (event) => {
607
+ document.querySelector("select[name=mimetype]").value = "text/csv"
608
+ openJsSheet(event.target)
609
+ })
610
+ linkFrame.appendChild(link)
611
+ }
612
+
613
+ function appendSeparatorBetweenButtons(linkFrame) {
614
+ const label = document.createElement("span")
615
+ label.appendChild(document.createTextNode(gettext("Spreadsheet") + ":"))
616
+ linkFrame.appendChild(label)
617
+ }
618
+
619
+ function removeAllChildNodes(parent) {
620
+ while (parent.firstChild) {
621
+ parent.removeChild(parent.firstChild);
622
+ }
623
+ }
624
+
625
+ function appendSpreadsheetButtons() {
626
+ let linkFrame = document.querySelector("#id-toggle-spreadsheet")
627
+ if (linkFrame) {
628
+ removeAllChildNodes(linkFrame)
629
+ } else {
630
+ const context = document.querySelector("textarea[name=context]")
631
+ linkFrame = document.createElement("div")
632
+ linkFrame.id = "id-toggle-spreadsheet"
633
+ context.before(linkFrame)
634
+ }
635
+ const link = createLinkButton(gettext("Source"), gettext("View source data."))
636
+ link.classList.add("selected")
637
+ link.addEventListener("click", toggleSource)
638
+ linkFrame.appendChild(link)
639
+ let data
640
+ try {
641
+ data = getContextData(document.querySelector("select[name=mimetype]").value)
642
+ } catch (error) {
643
+ displayError(error, gettext("Parse Data Error"))
644
+ return
645
+ }
646
+ appendSeparatorBetweenButtons(linkFrame)
647
+ if (!data) {
648
+ createDefaultButton(linkFrame)
649
+ return
650
+ }
651
+ const paths = getPathsToArrays(data)
652
+ if (paths.length) {
653
+ for(let path of paths) {
654
+ const payload = getPayload(data, path)
655
+ const tableOptions = convertDataToTableAndOptions(payload)[1]
656
+ tableOptions.table = getTableName(path)
657
+ tableOptions.row = getTableRowName(path)
658
+ const link = createLinkButton(path, gettext('Show data in spreadsheet.'), path, tableOptions)
659
+ link.addEventListener("click", (event) => openJsSheet(event.target))
660
+ linkFrame.appendChild(link)
661
+ }
662
+ } else {
663
+ const tableOptions = convertDataToTableAndOptions(data)[1]
664
+ tableOptions.table = "table"
665
+ tableOptions.row = "row"
666
+ const link = createLinkButton(gettext("Display"), gettext('Show data in spreadsheet.'), ".", tableOptions)
667
+ link.addEventListener("click", (event) => openJsSheet(event.target))
668
+ linkFrame.appendChild(link)
669
+ }
670
+ }
671
+
672
+ function openSpreadsheetIfRequired() {
673
+ const configValue = document.querySelector("textarea[name=config]").value
674
+ let config = {}
675
+ if (configValue) {
676
+ try {
677
+ config = JSON.parse(configValue)
678
+ } catch (error) {
679
+ displayError(error, gettext("Error in Source settings"))
680
+ return
681
+ }
682
+ }
683
+ if (config && config.openedPath && !window.pluginSpreadsheet) {
684
+ const button = document.querySelector(`#id-toggle-spreadsheet a[data-path="${config.openedPath}"]`)
685
+ if (button) {
686
+ openJsSheet(button)
687
+ }
688
+ }
689
+ }
690
+
691
+ function handleMimetypeSelect() {
692
+ document.querySelector("select[name=mimetype]").addEventListener("change", (event) => {
693
+ document.getElementById("id-toggle-spreadsheet").disabled = event.target.value === "application/vnd.oasis.opendocument.spreadsheet" ? "disabled" : ""
694
+ })
695
+ }
696
+
697
+ function sourceChanged() {
698
+ document.querySelector("textarea[name=context]").addEventListener("change", appendSpreadsheetButtons)
699
+ }
700
+
701
+ document.addEventListener('DOMContentLoaded', () => {
702
+ handleMimetypeSelect()
703
+ createSpreadsheetNode()
704
+ setSpreadsheetTranslations()
705
+ sourceChanged()
706
+ submitForm()
707
+ appendSpreadsheetButtons()
708
+ openSpreadsheetIfRequired()
709
+ })
710
+
711
+ })()