Online IDE Support JS

Injects elements into a codepen IDE for demonstration purposes

As of 2022-07-20. See the latest version.

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/438329/1072343/Online%20IDE%20Support%20JS.js

let demo;
let sources;
let initCounter = 10;
const deprecatedEvents = {
  dropdown: [`getValue`]
};

const pen = {
  actions: {
    log: (msg) => {
      const logEl = pen.elements.logContent;
      pen.elements.logLabel.classList.add(`highlight`);
      setTimeout(() => {
        pen.elements.logLabel.classList.remove(`highlight`);
      }, 500);
      logEl.innerText = `${msg}\n${logEl.innerText}`;
      if (msg) console.log(msg);
    },
    api: {
      addButton: (lText, lAction) => {
        if (typeof lText === `string`) {
          const newButton = pen.utils.createElement(`button`, {
            role: `button`,
            type: `button`,
            class: `dds__btn dds__btn-primary dds__btn-sm dds__button dds__button--mini dds__text-truncate`,
            text: lText
          });
          newButton.addEventListener(`click`, (e) => {
            let actionResponse;
            if (lAction.length > 0) {
              try {
                actionResponse = lAction(0);
              } catch (e) {
                try {
                  actionResponse = lAction("0");
                } catch (e) {
                  try {
                    actionResponse = lAction(["0"]);
                  } catch (e) {
                    try {
                      actionResponse = lAction([0]);
                    } catch (e) {
                      try {
                        actionResponse = lAction(new Date());
                      } catch (e) {
                        try {
                          actionResponse = lAction({ "alignment": "end" });
                        } catch (e) {
                          try {
                            actionResponse = lAction(document.querySelector(`.dds__side-nav__item`));
                          } catch (e) {
                            try {
                              actionResponse = lAction(0, `descending`);
                            } catch (e) {
                              try {
                                actionResponse = lAction("1");
                              } catch (e) {
                                console.error(e);
                                actionResponse = lAction();
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            } else {
              actionResponse = lAction();
            }
            if (actionResponse) pen.actions.log(actionResponse);
          });
          pen.elements.apiContent.appendChild(newButton);
        } else { // presume we are moving an existing element to the pen nav
          pen.elements.apiContent.appendChild(lText);
        }
      }
    },
  },
  elements: {
    logId: `log`,
    apiId: `api`,
  },
  utils: {
    addStyle: (styles) => {
      /* Create style document */
      var css = document.createElement('style');
      css.type = 'text/css';
      if (css.styleSheet)
        css.styleSheet.cssText = styles;
      else
        css.appendChild(document.createTextNode(styles));
      /* Append style to the tag name */
      document.getElementsByTagName("head")[0].appendChild(css);
    },
    /**
             * converts kebab-case words into camelCase ones
             * @param {string} key - a string with some number of dashes
             * @return {string} a camelCase version of whatever string was entered
             */
    dashCamel: function (key) {
      return key.replace(/-[a-z]/g, (m) => m.toUpperCase().replace(/-/gi, ""));
    },
    capitalize: (what) => {
      return what.charAt(0).toUpperCase() + what.slice(1);
    },
    createElement: (nodeType, props) => {
      const domNode = document.createElement(nodeType);
      if (props && "object" === typeof props) {
        for (const prop in props) {
          if (prop === "html") {
            domNode.innerHTML = props[prop];
          } else if (prop === "text") {
            domNode.textContent = props[prop];
          } else {
            if (prop.slice(0, 5) === "aria_" || prop.slice(0, 4) === "data_") {
              const attr = prop.slice(0, 4) + "-" + prop.slice(5);
              domNode.setAttribute(attr, props[prop]);
            } else {
              domNode.setAttribute(prop, props[prop]);
            }
          }
          // Set attributes on the element if passed
          if (["role", "aria-label"].includes(prop)) domNode.setAttribute(prop, props[prop]);
        }
      }
      return domNode;
    },
    random: (min = 100000000, max = 999999999) => {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min) + min);
    },
    load: (script) => {
      document.write('<'+'script src="'+script+'" type="text/javascript"><' + '/script>');
    },
  },
  initialize: () => {
    if (demo == null) {
      setTimeout(() => {
        initCounter--;
        if (initCounter > 0) {
          pen.initialize();
        }
      }, 50);
      if (initCounter === 1) {
        document.getElementById(`penlay`).remove();
        demo = {
          version: `2.14.1`
        };
        sources = pen.addLinks();
      }
      return;
    }
    if (demo.version) {
      sources = pen.addLinks();
    }
    setTimeout(() => {
      document.getElementById(`penlay`).remove();
      demo.components = [];
      const method = pen.utils.capitalize(pen.utils.dashCamel(demo.selector));
      document.querySelectorAll(`[data-dds="${demo.selector}"]`).forEach((element) => {
        demo.components.push(new DDS[method](element, demo.options));
      });
      Object.keys(pen.elements).forEach(key => {
        if (key.indexOf(`Id`) > 0) {
          const elString = key.replace(`Id`, ``);
          pen.elements[elString] = pen.utils.createElement(`div`, {
            id: elString,
          });
          if (elString === 'log' && (demo.log == null || demo.log !== `open`)) {
            pen.elements[elString].classList.add(`closed`);
          }
          if (elString === 'api' && (demo.api == null || demo.api !== `open`)) {
            pen.elements[elString].classList.add(`closed`);
          }
          pen.elements[`${elString}Label`] = pen.utils.createElement(`div`, {
            class: `label`
          });
          pen.elements[`${elString}Label`].innerText = elString;

          pen.elements[`${elString}Content`] = pen.utils.createElement(`div`, {
            class: `content`
          });
        }
      });
      Object.keys(pen.elements).forEach(key => {
        if (!key.match(/(Id|Label|Content)/g)) {
          document.querySelector(`body`).appendChild(pen.elements[key]);
          pen.elements[key].appendChild(pen.elements[`${key}Label`]);
          pen.elements[key].appendChild(pen.elements[`${key}Content`]);
        }
        if (key.indexOf(`Label`) > 0) {
          pen.elements[key].addEventListener(`click`, () => {
            pen.elements[key.replace(`Label`, ``)].classList.toggle(`closed`);
          });
        }
      });

      let hasDispose = false;
      const comp = demo.components[0]
      Object.keys(comp).forEach(key => {
        const method = pen.utils.capitalize(pen.utils.dashCamel(demo.selector));
        const selectorScript = `document.querySelector('[data-dds="${demo.selector}"]').${method}`;
        if (typeof comp[key] === `function`) {
          if (key !== `dispose`) {
            if (!deprecatedEvents[demo.selector] || !deprecatedEvents[demo.selector].includes(key)) {
              const parameterCount = comp[key].length;
              let comment = parameterCount > 0 ? ` // takes ${parameterCount} parameters` : ``;
              pen.actions.api.addButton(key, comp[key]);
              pen.actions.log(`${selectorScript}.${key}();${comment}`);
            }
          } else {
            hasDispose = true;
            pen.actions.log(`${selectorScript}.dispose()`);
          }
        } else {
          pen.actions.log(`${selectorScript}.${key} = ${comp[key]}`);
        }
      });
      pen.actions.log(`:::::::::::::::::::::::::::::::::::::::::::::::::::`);
      pen.actions.log(`\n\n${demo.selector} properties / methods:::::::::::::::::::::::`);

      hasDispose && (pen.actions.api.addButton(`dispose`, () => {
        comp[`dispose`]();
        pen.elements.api.querySelectorAll(`button`).forEach(b => b.disabled = `true`);
      }));


      demo.events.forEach((ev) => {
        pen.actions.log(`
document.addEventListener('${ev}', (event) => {
    console.log(event.detail);
})`);
        document.addEventListener(ev, (e) => {
          let output;
          pen.actions.log(`${ev} was fired with {event}.detail = ${JSON.stringify(e.detail)}`);
          try {
            output = JSON.stringify(e);
            pen.actions.log(output);
          } catch (error) {
            output = e;
            console.error(ev, output);
          }
        });
      });
      pen.actions.log(`::::::::::::::::::::::::::::::::::::::`);
      pen.actions.log(`\n${demo.selector} events:::::::::::::::::::::::`);
      
      // BEGIN LOGGING INITIALIZATION
      pen.actions.log(`
let components = [];
document.querySelectorAll('[data-dds="${demo.selector}"]').forEach((element) => {
  components.push(new DDS.${method}(element));
});
      `);
      sources.scripts.forEach(scrp => {        
        pen.actions.log(`<script src="${scrp}"></script>`);
      })
      sources.styles.forEach(styl => {        
        pen.actions.log(`<link rel="stylesheet" crossorigin href="${styl}" />`);
      })
      pen.actions.log(`::::::::::::::::::::::::::::::::::::::`);
      pen.actions.log(`\n INITIALIZATION :::::::::::::::::::::::`);
    }, 500);
  },
  addLinks: () => {
    const links = [
      `https://dds.dell.com/components/${demo.version}/css/dds-reboot.min.css`,
      `https://dds.dell.com/components/${demo.version}/css/dds-fonts.min.css`,
      `https://dds.dell.com/components/${demo.version}/css/dds-icons.min.css`,
      `https://dds.dell.com/components/${demo.version}/css/dds-helpers.min.css`,
      `https://dds.dell.com/components/${demo.version}/css/dds-main.min.css`,
    ];
    links.forEach((href) => {
      let link = pen.utils.createElement(`link`, {
        rel: 'stylesheet',
        crossorigin: '',
        href: href
      });
      document.querySelector(`head`).appendChild(link);
    });
    // DOESN'T WORK pen.utils.load(`https://dds.dell.com/components/${demo.version}/js/index.min.js`);

    const scripts = [`https://dds.dell.com/components/${demo.version}/js/index.min.js`];
    scripts.forEach((href) => {
      let scrp = pen.utils.createElement(`script`, {
        type: `text/javascript`,
        src: href
      });
      document.querySelector(`head`).appendChild(scrp);
    });
    return {
      styles: links,
      scripts: scripts,
    }
    pen.ready = true;
  },
  addCss: () => {
    pen.utils.addStyle(`
body {
  max-width: 1900px !important;
  padding: 5rem 4rem !important;
}
#log,
#api {
    transition: all 0.5s ease-in-out;
    position: absolute;
    z-index: 9999;
    height: 49vh;
    width: 80%;
    top: 50%;
    margin-left: 5%;
    color: white;
    background: black;
    font-size: 0.7rem;
    font-family: monospace;
    line-height: 0.9rem;
    padding: 1rem;
    border-bottom-right-radius: 0.625rem;
}

#log .label,
#api .label {
    font-family: Roboto;
    background: black;
    color: white;
    position: relative;
    float: right;
    top: .7rem;
    left: 4rem;
    max-width: 6rem;
    min-width: 5.25rem;
    text-align: center;
    padding: 0.5rem 0.625rem;
    transform: rotate(-90deg);
    cursor: pointer;
    border-bottom-right-radius: 0.625rem;
    border-bottom-left-radius: 0.625rem;
    white-space: nowrap;
}
#log .content {
  position: relative;
  top: -2rem;
  width: 98%;
  max-height: 46vh;
  overflow: auto;
}

.highlight {
  background: rgb(2,0,36) !important;
  background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%) !important;
}

#api {
    top: 0;
    height: unset;
    min-height: 4.55rem;
    background: aliceblue;
    padding: 0.625rem;
}

#api button {
  margin-left: 0.3rem;
  margin-bottom: 0.1rem;
}

#api .label {
    top: 0;
    background: aliceblue;
    color: black;
    font-weight: bold;
}

.closed {
    transform: translateX(-110%);
}

.content::-webkit-scrollbar {
    width: 15px;
}
 
.content::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.1);
	border-radius: 15px;
}
 
.content::-webkit-scrollbar-thumb {
    border-radius: 15px;
    background: rgba(255, 255, 255, 0.15);
}

`);
  },
  addButton: (label, callback, target) => {
    const newBtn = pen.utils.createElement(`button`, {
      role: `button`,
      type: `button`,
      class: `dds__btn dds__btn-primary dds__btn-sm dds__button dds__button--mini dds__text-truncate`,
      text: label,
      style: `margin-right: 0.625rem; margin-bottom: 0.625rem;`,
    });
    newBtn.addEventListener(`click`, callback);
    if (target) {
      target.appendChild(newBtn);
    } else {
      document.querySelector(`body`).prepend(newBtn);
    }
  },
  whenReady: (callback) => {
    if (!pen.ready) {
        setTimeout(() => {
            pen.whenReady(callback);
        }, 100);
    } else {
        callback();
    }
  }
};

const penlay = pen.utils.createElement(`div`, {
  id: `penlay`,
  style: `
  background-color: white;
  overflow:hidden;
  position:absolute;
  top:0px;
  right:0px;
  bottom:0px;
  left:0px;
  z-index: 99999999;
  `
});
penlay.innerHTML = `<div class="dds__loading-indicator">
  <div class="dds__loading-indicator__spinner"></div>
</div>`;
document.querySelector(`body`).appendChild(penlay);

(() => {
  pen.addCss();
  setTimeout(() => {
    pen.initialize();
  }, 1000)
})();