Online IDE Support JS

Injects elements into a codepen IDE for demonstration purposes

目前为 2023-01-28 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/438329/1142963/Online%20IDE%20Support%20JS.js

// Online IDE Support JS

let demo;
let sources;
let initCounter = 10;
let defaultVersion = `2.20.0`;
const deprecatedEvents = {
  dropdown: [`getValue`]
};
 
const pen = {
  actions: {
    log: (msg) => {
      if (demo.log !== `off`) {
        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;
            setTimeout(() => {
              if (lAction.length > 0) {
                try {
                  actionResponse = lAction(document.querySelector(`.dds__side-nav__item`));
                } 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(0);
                            } 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);
    },
    arraysEqual: (first, second) => {
      if(first.length !== second.length){
        return false;
      };
      for(let i = 0; i < first.length; i++){
        if(!second.includes(first[i])){
          return false;
        };
      };
      return true;
    },
    arrayRemove: (arr, value) => { 
        return arr.filter(function(ele){ 
            return ele != value; 
        });
    },
    /**
    * converts camelCased words into dashed-cased ones
    * @param {string} key - a string with some number of capitalized letters
    * @return {string} a dashed version of whatever string was entered
    */
    camelDash: (key) => {
        return key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
    },
    /**
    * 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, ""));
    },
    debounce: (func, timeout = 780) => {
        let timer;
        return (...args) => {
            clearTimeout(timer);
            timer = setTimeout(() => {
                func.apply(this, args);
            }, timeout);
        };
    },
    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) {
        const penLay = document.getElementById(`penlay`);
        if (penLay) penLay.remove();
        demo = {
          version: defaultVersion
        };
        sources = pen.addLinks();
      }
      return;
    }
    if (demo.version) {
      sources = pen.addLinks();
    }
    setTimeout(() => {
      const penLay = document.getElementById(`penlay`);
      if (penLay) penLay.remove();
      if (!demo.components) {
          demo.components = [];
          demo.components.push({ // for backward compatibility
            selector: demo.selector,
            options: demo.options,
            events: demo.events,
          });
      }
      demo.components.forEach(demoComp => {
        const method = pen.utils.capitalize(pen.utils.dashCamel(demoComp.selector));
        document.querySelectorAll(`[data-dds="${demoComp.selector}"]`).forEach((element) => {
          if (!element[method]) {
              demoComp.api = DDS[method](element, demoComp.options);
          } else {
              demoComp.api = element[method];
          }
        });
      });
      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 === 'log' && (demo.log === `off` || demo.log === false)) {
            pen.elements[elString].classList.add(`pen__none`);
          }
          if (elString === 'api' && (demo.api == null || demo.api !== `open`)) {
            pen.elements[elString].classList.add(`closed`);
          }
          if (elString === 'api' && (demo.api === `off` || demo.api === false)) {
            pen.elements[elString].classList.add(`pen__none`);
          }
          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;
      demo.components.forEach(demoComp => {
          const comp = demoComp.api;
          if (comp) {
              const method = pen.utils.capitalize(pen.utils.dashCamel(demoComp.selector));
              Object.keys(comp).forEach((key, index) => {
                const selectorScript = `document.querySelector('[data-dds="${demoComp.selector}"]').${method}`;
                if (typeof comp[key] === `function`) {
                  if (key !== `dispose`) {
                    if (!deprecatedEvents[demoComp.selector] || !deprecatedEvents[demoComp.selector].includes(key)) {
                      const parameterCount = comp[key].length;
                      let comment = parameterCount > 0 ? ` // takes ${parameterCount} parameters` : ``;
                      pen.actions.api.addButton(key, comp[key]);
                      const logComment = `${selectorScript}.${key}();${comment}`;
                      pen.actions.log(logComment);
                    }
                  } else {
                    hasDispose = true;
                    pen.actions.log(`${selectorScript}.dispose()`);
                  }
                } else {
                  pen.actions.log(`${selectorScript}.${key} = ${comp[key]}`);
                }
            });
            pen.actions.log(`:::::::::::::::::::::::::::::::::::::::::::::::::::`);
            pen.actions.log(`\n\n${demoComp.selector} properties / methods:::::::::::::::::::::::`);
       
            hasDispose && (pen.actions.api.addButton(`dispose`, () => {
              comp[`dispose`]();
              pen.elements.api.querySelectorAll(`button`).forEach(b => b.disabled = `true`);
            }));
       
       
            if (demoComp.events) {
                demoComp.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${demoComp.selector} events:::::::::::::::::::::::`);
            
            // BEGIN LOGGING INITIALIZATION
            pen.actions.log(`
  let components = [];
  document.querySelectorAll('[data-dds="${demoComp.selector}"]').forEach((element) => {
      components.push(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,
        'data-dds': 'stylesheet',
      });
      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,
        'data-dds': 'script',
      });
      document.querySelector(`head`).appendChild(scrp);
    });
    pen.ready = true;
    return {
      styles: links,
      scripts: scripts,
    }
  },
  removeLinks: () => {
    document.querySelectorAll(`[data-dds="stylesheet"]`).forEach(stylesheet => {
        stylesheet.remove(); 
    });
    document.querySelectorAll(`[data-dds="script"]`).forEach(script => {
        script.remove(); 
    });
  },
  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%);
}
.pen__none {
    display: none;
}
 
.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: (options = {
    label: `label`,
    callback: () => {console.log(`callback`);},
    target: undefined,
    class: undefined
  },
  deprecated1,
  deprecated2,
  ) => {
    if (typeof options == `string`) {
        options = {
            label: options,
            callback: deprecated1,
            target: deprecated2,
        }
    }
    if (typeof options.target === 'string') {
        options.target = document.querySelector(options.target);
    }
    if (!options.class) {
        options.class = `dds__button--mini`;
    }
    const btnId = options.label.replace(/[^0-9a-zA-Z]+/, ``);
    const newBtn = pen.utils.createElement(`button`, {
        id: btnId,
      role: `button`,
      type: `button`,
      class: `dds__btn dds__btn-primary dds__btn-sm dds__button ${options.class} dds__text-truncate`,
      text: options.label,
      style: `margin-right: 0.625rem; margin-bottom: 0.625rem;`,
    });
    newBtn.addEventListener(`click`, options.callback);
    if (!document.getElementById(btnId)) {
        if (options.target) {
            options.target.appendChild(newBtn);
        } else {
          document.querySelector(`body`).prepend(newBtn);
        }
    }
  },
  whenReady: (callback) => {
    if (!pen.ready) {
        setTimeout(() => {
            pen.whenReady(callback);
        }, 100);
    } else {
        callback();
    }
  },
  reset: () => {
    demo.components.forEach(demoComp => {
        const method = pen.utils.capitalize(pen.utils.dashCamel(demoComp.selector));
     
        // remove element properties
        document.querySelectorAll(`[data-dds="${demoComp.selector}"]`).forEach((element) => {
            element[method] = undefined;
        });
     
        // dispose of components
        try {
        demoComp.api.dispose();
        } catch (err) {
           console.log(err);
        }
        demoComp.api = undefined;
    });
 
    // dispose of library
    DDS = undefined;
 
    // remove pen elements
    document.getElementById("log").remove();
	document.getElementById("api").remove();
 
    pen.removeLinks();
    pen.ready = false;
    pen.showLoader();
  },
  showLoader: () => {
    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.showLoader();
 
(() => {
  pen.addCss();
  setTimeout(() => {
    pen.initialize();
  }, 1000)
})();