"use strict";
/*global Egg*/
/**
* Editor and Output viewer for Egg code.
*
* @class TryItOut
*/
class TryItOut {
// eslint-disable-next-line valid-jsdoc
/**
* Creates an instance of TryItOut of a given height and width.
*
* @constructor
* @param {string} id unique identifier of new TryItOut instance
* @param {string} [height=500px] string HTML for height property of TryItOut window
* @param {string} [width=100%] string HTML for width property of TryItOut window
* @memberof TryItOut
* @returns {TryItOut}
*/
constructor(id, height = "500px", width = "100%") {
this.id = id;
this.OUTPUT_ID = id + "_output";
this.INPUT_ID = id + "_input";
this.ERROR_ID = id + "_error";
this.TRY_IT_OUT_ID = id + "_try_it_out";
this.height = height;
this.width = width;
this.egg = new Egg(this.OUTPUT_ID);
this.inputTextArea = null;
this.outputTextArea = null;
this.errorDiv = null;
this.sectionIsVertical = true;
this.themeIsDefault = true;
this.defaultTheme = ["dark-theme-level-1", "dark-theme-level-2"];
this.altTheme = ["light-theme-level-1", "light-theme-level-2"];
}
/**
* Toggle orientation of all editors and preview windows on page between horizontal and vertical
* @method
* @return {undefined}
*/
onClickRotate() {
let sections = document.getElementsByClassName("TIO-section");
for (let section of sections) {
if (this.sectionIsVertical) {
section.style = "width: calc(100% - 10px); height: calc(50% - 30px);";
} else {
section.style = "width: calc(50% - 10px); height: calc(100% - 50px);";
}
}
this.sectionIsVertical = !this.sectionIsVertical;
}
/**
* Toggle theme of all editors on page between default and alternative theme
* @method
* @memberof TryItOut
* @return {undefined}
*/
onClickChangeTheme() {
//let levels = [["tryItOut", "toolbar"], ["rotate", "theme", "run", "input"]];
let targetClasses = [["TIO", "TIO-toolbar"], ["TIO-toolbar-btn", "TIO-input"]];
let fromClasses = this.themeIsDefault ? this.defaultTheme : this.altTheme;
let toClasses = this.themeIsDefault ? this.altTheme : this.defaultTheme;
this.changeClassForElementsWithClasses(targetClasses[0], fromClasses[0], toClasses[0]);
this.changeClassForElementsWithClasses(targetClasses[1], fromClasses[1], toClasses[1]);
this.themeIsDefault = !this.themeIsDefault;
}
/**
* Provided an array of element class names,
* remove oldClass and add newClass to each element
* @method
* @param {Array} withClasses array of classes of HTML elements to change
* @param {string} oldClass css class name to be removed
* @param {string} newClass css class name to be added
* @returns {undefined}
*/
changeClassForElementsWithClasses(withClasses, oldClass, newClass) {
for (let i = 0; i < withClasses.length; i++) {
let elements = document.getElementsByClassName(withClasses[i]);
for (let el of elements) {
el.classList.remove(oldClass);
el.classList.add(newClass);
}
}
}
/**
* Run the code in the onscreen input textarea through Egg.
* Display errors in error div.
* @method
* @returns {undefined}
*/
onClickRun() {
this.hideErrorDiv();
this.outputTextArea.value = "";
let program = this.inputTextArea.value;
if (program.length > 0) {
try {
this.outputTextArea.value = this.egg.run(program);
} catch (error) {
this.errorDiv.classList.remove("TIO-hidden");
this.errorDiv.innerHTML = "Uncaught " + error.name + ". " + error.message;
}
}
}
/**
* Hide error div in this TryItOut
* @method
* @returns {undefined};
*/
hideErrorDiv() {
this.errorDiv.classList.add("TIO-hidden");
}
/**
* Clear contents of input area, output area, and hide the error div in this TryItOut
* @method
* @returns {undefined};
*/
onClickClear() {
this.outputTextArea.value = "";
this.inputTextArea.value = "";
this.hideErrorDiv();
}
/**
* Insert HTML for TryItOut inside an HTML element with provided ID.
* @method
* @param {string} outerElementId the HTML element ID for the element to contain TryItOut
* @memberof TryItOut
* @returns {undefined}
*/
buildHTML(outerElementId) {
let html = `
<div id="${this.TRY_IT_OUT_ID}" class="TIO" style="height:${this.height}; width:${this.width};">
<div id="" class="TIO-toolbar dark-theme-level-1">
<button id="${this.id}_rotate" class="TIO-toolbar-btn TIO-rotate dark-theme-level-2" >Rotate</button>
<button id="${this.id}_theme" class="TIO-toolbar-btn TIO-theme dark-theme-level-2" >Change Theme</button>
<button id="${this.id}_run" class="TIO-toolbar-btn TIO-run dark-theme-level-2" >Run >></button>
<button id="${this.id}_clear" class="TIO-toolbar-btn TIO-clear dark-theme-level-2" >Clear</button>
</div>
<div class="TIO-demo">
<div class="TIO-section">
<textarea id="${this.INPUT_ID}" class="TIO-textarea TIO-input dark-theme-level-2">print("Hello world")</textarea>
</div>
<div class="TIO-section">
<textarea id="${this.OUTPUT_ID}" class="TIO-textarea TIO-output" readonly></textarea>
</div>
<div id="${this.ERROR_ID}" class="TIO-hidden TIO-error"></div>
</div>
</div>`;
document.getElementById(outerElementId).innerHTML = html;
this.loadHTML();
}
/**
* Internal method to load object references to TryItOut DOM elements
*
* @method
* @memberof TryItOut
* @returns {undefined}
*/
loadHTML() {
this.inputTextArea = document.getElementById(this.INPUT_ID);
this.outputTextArea = document.getElementById(this.OUTPUT_ID);
this.errorDiv = document.getElementById(this.ERROR_ID);
document.getElementById(this.id + "_rotate").onclick = () => { this.onClickRotate(); };
document.getElementById(this.id + "_theme").onclick = () => { this.onClickChangeTheme(); };
document.getElementById(this.id + "_run").onclick = () => { this.onClickRun(); };
document.getElementById(this.id + "_clear").onclick = () => { this.onClickClear(); };
}
/**
* Set default code in TryItOut editor
*
* @method
* @param {string} code Egg code
* @memberof TryItOut
* @returns {undefined}
*/
placeCode(code){
this.onClickClear();
this.inputTextArea.value = code;
}
}