Skip to main content
Tweeted twitter.com/StackCodeReview/status/1017150641431556096
deleted 65 characters in body
Source Link
Ivan
  • 450
  • 4
  • 15

HTML templates

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>

JavaScript code:

/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        // all types need different formatting
        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, { once: true });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};

Full code:

HTML templates

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>
 

JavaScript codeIssues:

/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        // all types need different formatting
        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, { once: true });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};

I have some issues:

  • by adding code I feel like I havemy function too much code in a single function. I am unsure I'm using ES6 properly..showObject seems to big.

  • some of the naming bother me: Unsure if I'm using ECMAScript 6 properly

  • some of the variable names bother me (element, childrenPreview, isContainer) as they aren't very clear to me.

  • I can't attach an event listener on the imported template <details> because it is a DocumentFragment. To fix that I had to (line 62 of the snippet):

Overall the first two points are the most important at the moment.

I'm looking forward to reading your comments.I'm looking forward to reading your comments.

HTML templates

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>

JavaScript code:

/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        // all types need different formatting
        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, { once: true });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};

I have some issues:

  • by adding code I feel like I have too much code in a single function. I am unsure I'm using ES6 properly...

  • some of the naming bother me: element, childrenPreview, isContainer aren't very clear to me.

  • I can't attach an event listener on the imported template <details> because it is a DocumentFragment. To fix that I had to (line 62 of the snippet):

Overall the first two points are the most important at the moment.

I'm looking forward to reading your comments.

HTML templates

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>

JavaScript code:

/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        // all types need different formatting
        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, { once: true });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};

Full code:

 

Issues:

  • my function showObject seems to big.

  • Unsure if I'm using ECMAScript 6 properly

  • some of the variable names bother me (element, childrenPreview, isContainer) as they aren't very clear.

  • I can't attach an event listener on the imported template <details> because it is a DocumentFragment. To fix that I had to (line 62 of the snippet):

I'm looking forward to reading your comments.

link to initial question was broken
Source Link
Ivan
  • 450
  • 4
  • 15

This is a follow-up post of my previous question: Displaying JavaScript object's structure on page with HTMLDisplaying JavaScript object's structure on page with HTML which looked at how to display all properties of a JavaScript object on a page similar to how the console behaves in browsers. In this first question, I had figured out how to render object that had cycles.

This is a follow-up post of my previous question: Displaying JavaScript object's structure on page with HTML which looked at how to display all properties of a JavaScript object on a page similar to how the console behaves in browsers. In this first question, I had figured out how to render object that had cycles.

This is a follow-up post of my previous question: Displaying JavaScript object's structure on page with HTML which looked at how to display all properties of a JavaScript object on a page similar to how the console behaves in browsers. In this first question, I had figured out how to render object that had cycles.

Source Link
Ivan
  • 450
  • 4
  • 15

Replicating Chrome console's JavaScript object explorer

This is a follow-up post of my previous question: Displaying JavaScript object's structure on page with HTML which looked at how to display all properties of a JavaScript object on a page similar to how the console behaves in browsers. In this first question, I had figured out how to render object that had cycles.

Receiving valuable advice from Gerrit0, I changed a couple of things:

  • used template to prepare the HTML elements with JavaScript this allows to safely parse string as strings, not HTML (using textContent instead of innerHTML)

  • used the details element to make the foldable containers

  • added some CSS styling

Here's how it looks like:

enter image description here


/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, {
        once: true
      });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};


/**
  * For demonstration purposes
  */
const obj = {
  integer: 12,
  string: 'Hello World',
  boolean: true,
  htmlString: '<b>Nope, not bold</b>',
  object: {
    innerArray: ['first', 'second'],
    innerString: 'yes',
    innerInteger: 12,
    innerObject: {
      first: 1,
      second: 2
    }
  },
  array: ['<b>bold text</b>', 'two'],
  function: function() {}
};

obj['cycle'] = obj;
showObject(obj, document.querySelector('.container'))
/**
  *  // all properties for the console get the prefix "csle-"
  */


/**
  * Console frame
  */

.container {
    background: #242424;
    padding: 8px 15px;
}


/**
  * Property value's styling 
  * csle-{boolean, undefined, string, Array, Object}
  */
  
.csle-boolean,
.csle-undefined {
    color: #9283d1;
}
.csle-string {
    color: #ca3b38; /*#e93f3b;*/
}

.csle-string:before,
.csle-string:after { content: '"'; }

.csle-Array:before { content: '['; }
.csle-Array:after { content: ']'; }

.csle-Object:before { content: '{'; }
.csle-Object:after { content: '}'; }


/**
  * <summary> styling
  */

summary {
  margin-left: 18px;
  padding-left: 0px;
  font-size: 20px;
  display: flex;
  align-items: center;
  margin-bottom: 2px;
}
summary::-webkit-details-marker {
  color: #8d8d8d;
  text-shadow: 1em 0.1em #242424;
}

/**
  * properties styling
  */
  
details > *:not(:first-child) {
  margin-left: 22px;
}

summary > div {
  display: inline-block;
  width: 100%;
}
.csle-property, summary {
  font-family: "Lucida Grande", sans-serif;
  font-size: 17px;
  padding: 1px;
  overflow: hidden;
  padding-left: 17px;
  color: #acabab;
}
.csle-property {
  line-height: 23px;
  margin-bottom: 2px;
  font-size: 18px;
}
.csle-property > span {
  font-size: 17px;
}
.csle-preview > .csle-property {
  display: inline;
  margin: 0px;
  padding: 0px;
  margin: -2px;
  color: #acabab;
  font-size: 18px;
}

.csle-preview > .csle-property > span {
  font-size: 17px;
}

.csle-preview > .csle-property:not(:first-child) > .csle-key:before  {
  content: ', ';
}


.csle-key, summary {
  color: #a545ac;
  font-size: 17px
}
.csle-key, .csle-preview {
  display: inline;
}
<div class="container"></div>

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>

HTML templates

<template id="keyValue">
  <div class="csle-property">
    <span class="csle-key"></span>:
    <span class="csle-value"></span>
  </div>
</template>

<template id="folder">
  <summary>
    <div>
      <div class="csle-key"></div>: 
      <div class="csle-preview"></div>
    </div>
  </summary>
</template>

JavaScript code:

/**
  * Shows all the object's properties with a depth of 1 
  * @params {Object} object, its first level properties are shown
  *         {HTMLElement} parent the element in which are displayed the properties
  * @return {undefined}
  */
const showObject = (object, parent = document.body) => {

  const template = {
    keyValue: document.querySelector('template#keyValue'),
    folder: document.querySelector('template#folder')
  }

  Object.entries(object).forEach(([key, value]) => {

    const objectClass = (value && value.constructor) ? value.constructor : undefined;
    const isContainer = (objectClass == Object) || (objectClass == Array);

    if (isContainer) { // !better naming for (objects, arrays, maps, sets)?


      const element = document.importNode(template.folder.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        preview: element.querySelector('.csle-preview')
      }

      children.key.textContent = key;
      children.preview.classList.add('csle-' + objectClass.name);

      // show four properties maximum per preview
      Object.entries(value).some(([k, v], i) => {
        type = (v && v.constructor) ? v.constructor : undefined;

        const keyValue = document.importNode(template.keyValue.content, true);
        const keyValueElement = {
          key: keyValue.querySelector('.csle-key'),
          value: keyValue.querySelector('.csle-value')
        }

        // all types need different formatting
        switch (type) {

          case Object:
            keyValueElement.value.textContent = `{...}`;
            break;

          case Array:
            keyValueElement.value.textContent = `Array(${v.length})`;
            break

          default:
            keyValueElement.value.textContent = `${v}`;

        }

        keyValueElement.key.textContent = k;
        keyValueElement.value.setAttribute('class', 'csle-' + typeof v);
        children.preview.appendChild(keyValue);
        return i == 4;
      });

      const wrapper = document.createElement('details'); // !couldn't add event listener on <details>
      wrapper.appendChild(element)
      wrapper.addEventListener('toggle', () => {
        showObject(value, wrapper)
      }, { once: true });

      parent.appendChild(wrapper);


    } else {

      const element = document.importNode(template.keyValue.content, true);
      const children = {
        key: element.querySelector('.csle-key'),
        value: element.querySelector('.csle-value')
      }

      children.key.textContent = key;

      children.value.textContent = value; // !undefined and null won't be parsed
      children.value.setAttribute('class', 'csle-' + typeof value);

      parent.appendChild(element);
    }

  });

};

I have some issues:

  • by adding code I feel like I have too much code in a single function. I am unsure I'm using ES6 properly...

  • some of the naming bother me: element, childrenPreview, isContainer aren't very clear to me.

  • I can't attach an event listener on the imported template <details> because it is a DocumentFragment. To fix that I had to (line 62 of the snippet):

  1. only import <summary> as a template
  2. create the <details> element manually
  3. append <summary> inside <details>
  4. attach the event listener to <details>


Any workaround?

Overall the first two points are the most important at the moment.

I'm looking forward to reading your comments.