Improve Debug presentation for nested structures.
authorBenjamin Braatz <bb@bbraatz.eu>
Tue, 23 Mar 2021 17:26:14 +0000 (18:26 +0100)
committerBenjamin Braatz <bb@bbraatz.eu>
Tue, 23 Mar 2021 17:26:14 +0000 (18:26 +0100)
controlpi_plugins/web/Debug/controlpi-debug.css
controlpi_plugins/web/Debug/controlpi-debug.js

index ac85cc171631ff1df29aad58846ea599d9fb6f8b..64d56da069597c3bbf18c3342ab0d26fd439762f 100644 (file)
@@ -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;
 }
     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: */
index d7650d04ca75cb084e93a32ca74021c3443a1561..420570e5cc113c308f248f1283fe8d4c1cad96d2 100644 (file)
@@ -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')