%%html

Hello!
%%js // required to allow cell to be JavaScript enabled

console.log("JavaScript/Jupyter Output Introduction");

// Browser Console output; debugging or tracing
console.log("This is an output using console.log()!");

// Set element in HTML above using DOM (Document Object Model)
document.getElementById("output").textContent = "This is an output using console.log()!";

// Jupyter built in magic element for testing and convenience of development
element.textContent = "This is an output using console.log()!";  // element is an output option as part of %%js magic

//alert("Hello, World!");
<IPython.core.display.Javascript object>
%%js
console.log("Variable Definition");

var msg = "This is text defined using var and used in later code to output this text, which increases efficiency!";

// Use msg to output code to Console and Jupyter Notebook
console.log(msg);  //right click browser select Inspect, then select Console to view
document.getElementById("output").textContent = msg;
element.append(msg);
//alert(msg);
<IPython.core.display.Javascript object>
%%js
console.log("Function Definition");

/* Function: logIt
 * Parameter: output
 * Description: The parameter is "output" to console and jupyter page
*/
function logIt(msg) {
    console.log(msg); 
    element.append(msg);
    document.getElementById("output").textContent = msg;
    //alert(output);
}

// sequence of code build logIt parameter using concatenation
var msg = "Hello!" // replaces content of variable
var welcome = "Welcome to this JSOutput with Objects Jupyter Notebook!"
logIt(msg + "  " + welcome); // concatenation of strings
<IPython.core.display.Javascript object>
%%js
console.log("Examine Data Types");

// Function to add typeof to output
function getType(output) {
    return typeof output + ": " + output;
}

// Function defintion
function logIt(msg) {
    console.log(getType(msg));  // logs string
    console.info(msg);          // logs object
    document.getElementById("output").textContent = msg;
    element.append(getType(msg) + " ");  // adds to Jupyter output
    //alert(getType(msg));
}

// Common Types
element.append("Common Types ");
logIt("This is some text"); // String
logIt(1776);    // Number
logIt(true);    // Boolean

// Object Type, this definition is often called a array or list
element.append("Object Type, array ");
var scores = [
    90,
    80, 
    100
];  
logIt(scores);

// Complex Object, this definition is often called hash, map, hashmap, or dictionary
element.append("Object Type, hash or dictionary ");
var person = { // key:value pairs seperated by comma
    "name": "Jason", 
    "role": "Students"
}; 
logIt(person);
logIt(JSON.stringify(person));  //method used to convert this object into readable format
<IPython.core.display.Javascript object>
%%js
console.log("Person objects");

/* class: Person
 * Description: A collection of Person data
*/
class Person {
  /* method: constructor
   * parameters: name, ghID - GitHub ID, classOf - Graduation Class 
   * description: returns object when "new Person()" is called with matching parameters
   * assignment: this.name, this.ghID, ... are properties retained in the returned object
   * default: role uses a default property, it is set to "Student"
  */
  constructor(name, ghID, classOf, role="Student") {
    this.name = name;
    this.ghID = ghID;
    this.classOf = classOf;
    this.role = role;
  }

  /* method: setter
   * parameters: role - role in classroom
   * description: this.role is updated from default value to value contained in role parameter
  */
  setRole(role) {
    this.role = role;
  }
  
  /* method: getter
   * description: turns properties of object into JSON object
   * return value: JSON object
  */
  getJSON() {
    const obj = {type: typeof this, name: this.name, ghID: this.ghID, classOf: this.classOf, role: this.role};
    const json = JSON.stringify(obj);
    return json;
  }

  /* method: logIT
   * description: this Person object is logged to console
  */
  
  logIt() {
    //Person Object
    console.info(this);
       
    // HTML output
    document.getElementById("output").textContent = this.getJSON();

    //Log to Jupter
    element.append(this.role + " object in JSON: ");
    element.append(this.getJSON());  
    element.append(" ");


    //alert(this.getJSON());
  }
    
}

// make a new Person Object
const teacher = new Person("Mr M", "jm1021", 1977); // object type is easy to work with in JavaScript
// update role to Teacher
var role = "Teacher";
teacher.setRole(role); // set the role
teacher.logIt();  // log to console

// make a new Person Object
const student = new Person("Jane Doe", "jane", 2007); // object type is easy to work with in JavaScript
student.logIt(); // log to console
<IPython.core.display.Javascript object>
%%js
console.log("Classroom object");

/* class: Person
 * Description: A collection of Person data
*/
class Person {
  /* method: constructor
   * parameters: name, ghID - GitHub ID, classOf - Graduation Class 
   * description: returns object when "new Person()" is called with matching parameters
   * assignment: this.name, this.ghID, ... are properties retained in the returned object
   * default: this.role is a default property retained in object, it is set to "Student"
  */
  constructor(name, ghID, classOf, role="Student") {
    this.name = name;
    this.ghID = ghID;
    this.classOf = classOf;
    this.role = role;
  }

  /* method: setter
   * parameters: role - role in classroom
   * description: this.role is updated from default value to value contained in role parameter
  */
  setRole(role) {
    this.role = role;
  }
  
  /* method: getter
   * description: turns properties of object into JSON object
   * return value: JSON object
  */
  getJSON() {
    const obj = {type: typeof this, name: this.name, ghID: this.ghID, classOf: this.classOf, role: this.role};
    const json = JSON.stringify(obj);
    return json;
  }

  /* method: logIT
   * description: this Person object is logged to console
  */
  logIt() {
    //Person Object
    console.info(this);
    // HTML output tag
    document.getElementById("output").textContent = this.getJSON();

    //Log to Jupter
    element.append("Person json <br>");
    element.append(this.getJSON() + "<br>"); 

    //alert(this.getJSON());
  }
    
}

/* class: Classroom
 * Description: A collection of Person objects
*/
class Classroom {
  /* method: constructor
   * parameters: teacher - a Person object, students - an array of Person objects
   * description: returns object when "new Classroom()" is called containing properties and methods of a Classroom
   * assignment: this.classroom, this.teacher, ... are properties retained in the returned object
  */
  constructor(teacher, students) {
    /* spread: this.classroom contains Teacher object and all Student objects
     * map: this.json contains of map of all persons to JSON
    */
    this.teacher = teacher;
    this.students = students;
    this.classroom = [teacher, ...students]; // ... spread option
    this.json = '{"classroom":[' + this.classroom.map(person => person.getJSON()) + ']}';
  }

  /* method: logIT
   * description: this Classroom object is logged to console
  */
  logIt() {
    //Classroom object
    console.log(this);

    // HTML output
    document.getElementById("data").textContent = this.json;
    document.getElementById("output").textContent = this.json;

    //Classroom json
    element.append("Classroom object in JSON: ");
    element.append(this.json);

    //alert(this.json);
  }
}

/* function: constructCompSciClassroom
 * Description: Create data for Classroom and Person objects
 * Returns: A Classroom Object
*/
function constructCompSciClassroom() {
    // define a Teacher object
    const teacher = new Person("Mr M", "jm1021", 1977, "Teacher");  // optional 4th parameter

    // define a student Array of Person objects
    const students = [ 
        new Person("Anthony", "tonyhieu", 2022),
        new Person("Bria", "B-G101", 2023),
        new Person("Allie", "xiaoa0", 2023),
        new Person("Tigran", "Tigran7", 2023),
        new Person("Rebecca", "Rebecca-123", 2023),
        new Person("Vidhi", "VidhiKulkarni", 2024)
    ];

    // make a CompSci classroom from formerly defined teacher and student objects
    return new Classroom(teacher, students);  // returns object
}

// assigns compsci to the object returned by "constructCompSciClassroom()" function
const compsci = constructCompSciClassroom();
// output of Objects and JSON in CompSci classroom
compsci.logIt();

<IPython.core.display.Javascript object>
%%js
console.log("Classroom Web Page");

// extract JSON text from output element in HTML page
const jsonText = document.getElementById("data").innerHTML;

// convert JSON text to a JavaScript Object to process
const classroom = JSON.parse(jsonText).classroom;
console.log(classroom);

// make an HTML Out format for pretty display
/* Template literals (`), can make HTML generation more concise;
 * the map functions generates row strings and the join method combines them;
 * this replaces longer and ugly for loop and string concatenation.
*/
const htmlOut = `
    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>GitHub ID</th>
                <th>Class Of</th>
                <th>Role</th>
            </tr>
        </thead>
        <tbody>
            ${classroom.map(row => `
                <tr>
                    <td>${row.name}</td>
                    <td>${row.ghID}</td>
                    <td>${row.classOf}</td>
                    <td>${row.role}</td>
                </tr>
            `).join('')}
        </tbody>
    </table>
`;

// assign/set htmlOut to output element in HTML page
document.getElementById("output").innerHTML = htmlOut;

// show raw HTML
console.log(htmlOut);
element.append(htmlOut);
<IPython.core.display.Javascript object>