From 95c2612536024d61e66a3afdaaca5249fa2bec23 Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Tue, 23 Mar 2021 18:26:14 +0100 Subject: [PATCH] Improve Debug presentation for nested structures. --- .../web/Debug/controlpi-debug.css | 12 +- .../web/Debug/controlpi-debug.js | 145 ++++++++++++------ 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/controlpi_plugins/web/Debug/controlpi-debug.css b/controlpi_plugins/web/Debug/controlpi-debug.css index ac85cc1..64d56da 100644 --- a/controlpi_plugins/web/Debug/controlpi-debug.css +++ b/controlpi_plugins/web/Debug/controlpi-debug.css @@ -71,7 +71,7 @@ .object.red { background-color: #ee96a8; } -.object > h2 { +.object > h3 { margin-top: 5px; margin-left: 5px; margin-right: 3px; @@ -86,7 +86,7 @@ display: flex; flex-direction: row; } -.property > .key, .property > .value, .property > .object { +.property > * { margin-top: 2px; margin-left: 2px; } @@ -95,6 +95,14 @@ display: flex; flex-direction: row; flex-wrap: wrap; + background-color: #bcdaf8; + padding-right: 4px; + padding-bottom: 4px; +} +.array > * { + background-color: #79b5e7; + margin-top: 4px; + margin-left: 4px; } /* TODO: Remove and use property-key-value structure: */ diff --git a/controlpi_plugins/web/Debug/controlpi-debug.js b/controlpi_plugins/web/Debug/controlpi-debug.js index d7650d0..420570e 100644 --- a/controlpi_plugins/web/Debug/controlpi-debug.js +++ b/controlpi_plugins/web/Debug/controlpi-debug.js @@ -109,71 +109,44 @@ function createClient(client, plugin) { } // Create structure for arbirary JSON element: -function create(thing, parentType) { +function create(thing) { if (typeof(thing) == 'object') { if (Array.isArray(thing)) { - return createArray(thing, parentType) - } else if (parentType == 'template') { - if ('const' in thing) { - return create(thing['const']) - } - if ('type' in thing) { - if (thing['type'] == 'object') { - return createObject(thing, type) - } else { - const valueDiv = document.createElement('div') - valueDiv.setAttribute('class', 'value') - valueDiv.appendChild(document.createTextNode( - '<' + thing['type'] + '>')) - return valueDiv - } - } - } else { - type = parentType - if (parentType == 'message') { - type = '' - } - return createObject(thing, type) + return createArray(thing) } - } else { - const valueDiv = document.createElement('div') - valueDiv.setAttribute('class', 'value') - valueDiv.appendChild(document.createTextNode(JSON.stringify(thing))) - return valueDiv + return createObject(thing) } + const valueDiv = document.createElement('div') + valueDiv.setAttribute('class', 'value') + valueDiv.appendChild(document.createTextNode(JSON.stringify(thing))) + return valueDiv } // Create structure for array: -function createArray(array, parentType) { - arrayDiv = document.createElement('div') +function createArray(array) { + const arrayDiv = document.createElement('div') arrayDiv.setAttribute('class', 'array') - arrayDiv.appendChild(document.createTextNode('[')) - var counter = array.length for (const item of array) { - arrayDiv.appendChild(create(item, parentType)) - if (--counter) { - arrayDiv.appendChild(document.createTextNode(', ')) - } + arrayDiv.appendChild(create(item)) } - arrayDiv.appendChild(document.createTextNode(']')) + return arrayDiv } // Create structure for object: -function createObject(object, type) { +function createObject(object, type='') { const objectDiv = document.createElement('div') objectDiv.setAttribute('class', 'object') if (type == 'message') { // Current (receive) time as heading: const time = new Date().toLocaleTimeString() - const h4 = document.createElement('h4') - const h4Content = document.createTextNode(time) - h4.appendChild(h4Content) - objectDiv.appendChild(h4) + const timeElement = document.createElement('h4') + timeElement.appendChild(document.createTextNode(time)) + objectDiv.appendChild(timeElement) } if (type == 'template') { if (Object.keys(object).length === 0) { - // Create span with '*' for empty templates: - const wildcard = document.createElement('h2') + // Create element with '*' for empty templates: + const wildcard = document.createElement('h3') wildcard.appendChild(document.createTextNode('*')) objectDiv.appendChild(wildcard) } @@ -202,13 +175,95 @@ function createObject(object, type) { keyDiv.appendChild(document.createTextNode(key + ':')) propertyDiv.appendChild(keyDiv) // Create value element and append to property div: - propertyDiv.appendChild(create(object[key], type)) + if (type == 'template') { + propertyDiv.appendChild(createSchema(object[key])) + } else { + propertyDiv.appendChild(create(object[key])) + } // Append property div to object div: objectDiv.append(propertyDiv) } return objectDiv } +// Create structure for an arbitrary JSON schema: +function createSchema(schema) { + if ('const' in schema) { + return create(schema['const']) + } + if ('type' in schema) { + if (schema['type'] == 'array') { + const arrayDiv = document.createElement('div') + arrayDiv.setAttribute('class', 'array') + if ('items' in schema) { + arrayDiv.appendChild(createSchema(schema['items'])) + } else { + // Create element with '*' for arrays with unrestricted + // items: + const wildcard = document.createElement('div') + wildcard.appendChild(document.createTextNode('*')) + arrayDiv.appendChild(wildcard) + } + return arrayDiv + } else if (schema['type'] == 'object') { + const objectDiv = document.createElement('div') + objectDiv.setAttribute('class', 'object') + empty = true + if ('properties' in schema) { + for (const key in schema['properties']) { + // Create property div: + const propertyDiv = document.createElement('div') + propertyDiv.setAttribute('class', 'property') + // Create key div and append to property div: + const keyDiv = document.createElement('div') + keyDiv.setAttribute('class', 'key') + keyDiv.appendChild(document.createTextNode(key + ':')) + propertyDiv.appendChild(keyDiv) + // Create value element and append to property div: + propertyDiv.appendChild(createSchema(schema['properties'][key])) + // Append property div to object div: + objectDiv.append(propertyDiv) + } + empty = false + } + if ('patternProperties' in schema) { + for (const key in schema['patternProperties']) { + // Create property div: + const propertyDiv = document.createElement('div') + propertyDiv.setAttribute('class', 'property') + // Create key div and append to property div: + const keyDiv = document.createElement('div') + keyDiv.setAttribute('class', 'key') + keyDiv.appendChild(document.createTextNode('/' + key + '/:')) + propertyDiv.appendChild(keyDiv) + // Create value element and append to property div: + propertyDiv.appendChild(createSchema(schema['patternProperties'][key])) + // Append property div to object div: + objectDiv.append(propertyDiv) + } + empty = false + } + if (empty) { + // Create element with '*' for unrestricted objects: + const wildcard = document.createElement('h3') + wildcard.appendChild(document.createTextNode('*')) + objectDiv.appendChild(wildcard) + } + return objectDiv + } else { + const valueDiv = document.createElement('div') + valueDiv.setAttribute('class', 'value') + valueDiv.appendChild(document.createTextNode( + '<' + schema['type'] + '>')) + return valueDiv + } + } + const valueDiv = document.createElement('div') + valueDiv.setAttribute('class', 'value') + valueDiv.appendChild(document.createTextNode(JSON.stringify(thing))) + return valueDiv +} + // Create div, form and table for command template: function createForCommand(template) { const div = document.createElement('div') -- 2.34.1