1067 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1067 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
class Task extends HTMLElement {
 | 
						|
    static sequence_number = 0;
 | 
						|
 | 
						|
    constructor(type) {
 | 
						|
        super();
 | 
						|
 | 
						|
        this.task_type = type;
 | 
						|
        this.sequence_number = Task.sequence_number++;
 | 
						|
        this.concluded = false;
 | 
						|
        this.view_only = false;
 | 
						|
        this.upload_answer_cb = null;
 | 
						|
        this.player_answer = null;
 | 
						|
        this.correct_answer = null;
 | 
						|
 | 
						|
 | 
						|
        this.shadow = this.attachShadow({mode: "open"});
 | 
						|
        this.createStyle();
 | 
						|
        this.createElements();
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        this.css = document.createElement("style");
 | 
						|
        this.css.innerHTML = `
 | 
						|
            span.question {
 | 
						|
                font-size: 1.3em;
 | 
						|
                font-weight: bold;
 | 
						|
                color: #176767;
 | 
						|
            }
 | 
						|
            section.task {
 | 
						|
                display: block;
 | 
						|
                position: relative;
 | 
						|
                margin: 0 auto;
 | 
						|
                width: 40em;
 | 
						|
                padding: 1em;
 | 
						|
                background-color: #d3e5e5;
 | 
						|
                margin-bottom: 0.5em;
 | 
						|
                border-radius: 0.3em;
 | 
						|
            }
 | 
						|
            section.seq-num, section.mark {
 | 
						|
                display: block;
 | 
						|
                position: absolute;
 | 
						|
                right: 0;
 | 
						|
                padding: 0.5em;
 | 
						|
                background-color: #176767;
 | 
						|
                color: whitesmoke;
 | 
						|
                width: 2em;
 | 
						|
                z-index: 10;
 | 
						|
            }
 | 
						|
            section.seq-num {
 | 
						|
                bottom: 0;
 | 
						|
                border-bottom-right-radius: 0.3em;
 | 
						|
                border-top-left-radius: 0.3em;
 | 
						|
            }
 | 
						|
            section.mark {
 | 
						|
                top: 0;
 | 
						|
                border-top-right-radius: 0.3em;
 | 
						|
                border-bottom-left-radius: 0.3em;
 | 
						|
            }
 | 
						|
            section.answer-container {
 | 
						|
                /* (empty) */
 | 
						|
            }
 | 
						|
            section.bad-answer {
 | 
						|
                background-color: #e5d8d3;
 | 
						|
            }
 | 
						|
            code {
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
            }
 | 
						|
            
 | 
						|
            section#correct-answer {
 | 
						|
                display: none;
 | 
						|
                width: 100%;
 | 
						|
                margin-top: 0.5em;
 | 
						|
            }
 | 
						|
            *[visible="true"] {
 | 
						|
                display: block !important;
 | 
						|
            }
 | 
						|
            section#comment {
 | 
						|
                display: none;
 | 
						|
                width: 100%;
 | 
						|
                margin-top: 0.5em;
 | 
						|
            }
 | 
						|
            .MathJax {
 | 
						|
                display: block;
 | 
						|
                margin: 0.5em auto;
 | 
						|
                font-size: 120%;   
 | 
						|
            }
 | 
						|
            @media only screen and (max-width: 800px) {
 | 
						|
                section.task {
 | 
						|
                   width: calc(100vw - 3em);
 | 
						|
                }
 | 
						|
                section.answer-container {
 | 
						|
                    margin-bottom: 1.5em;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        `;
 | 
						|
        this.shadow.append(this.css);
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        let task_box = document.createElement("section");
 | 
						|
        task_box.classList.add("task");
 | 
						|
        let question_span = document.createElement("span");
 | 
						|
        question_span.classList.add("question");
 | 
						|
        let answer_container = document.createElement("section");
 | 
						|
        answer_container.classList.add("answer-container");
 | 
						|
        let mark_section = document.createElement("section");
 | 
						|
        mark_section.classList.add("mark");
 | 
						|
        let seq_num_section = document.createElement("section");
 | 
						|
        seq_num_section.classList.add("seq-num");
 | 
						|
        seq_num_section.innerText = `${this.sequence_number + 1}.`;
 | 
						|
        let ca_section = document.createElement("section");
 | 
						|
        ca_section.id = "correct-answer";
 | 
						|
        let comment_sec = document.createElement("section");
 | 
						|
        comment_sec.id = "comment";
 | 
						|
 | 
						|
        task_box.append(question_span);
 | 
						|
        task_box.append(answer_container);
 | 
						|
        task_box.append(mark_section);
 | 
						|
        task_box.append(seq_num_section);
 | 
						|
        task_box.append(ca_section);
 | 
						|
        task_box.append(comment_sec);
 | 
						|
 | 
						|
        this.shadow.append(task_box);
 | 
						|
 | 
						|
        this.task_box = task_box;
 | 
						|
        this.question_span = question_span;
 | 
						|
        this.answer_container = answer_container;
 | 
						|
        this.mark_section = mark_section;
 | 
						|
        this.seq_num_section = seq_num_section;
 | 
						|
        this.ca_section = ca_section;
 | 
						|
        this.comment_sec = comment_sec;
 | 
						|
    }
 | 
						|
 | 
						|
    connectedCallback() {
 | 
						|
    }
 | 
						|
 | 
						|
    disconnectedCallback() {
 | 
						|
    }
 | 
						|
 | 
						|
    get type() {
 | 
						|
        return this.task_type;
 | 
						|
    }
 | 
						|
 | 
						|
    set type(type) {
 | 
						|
        this.task_type = type;
 | 
						|
    }
 | 
						|
 | 
						|
    get sequenceNumber() {
 | 
						|
        return this.sequence_number;
 | 
						|
    }
 | 
						|
 | 
						|
    setQuestion(question) {
 | 
						|
        this.question_span.innerHTML = preprocess_inserts(question);
 | 
						|
    }
 | 
						|
 | 
						|
    get isConcluded() {
 | 
						|
        return this.concluded;
 | 
						|
    }
 | 
						|
 | 
						|
    set isConcluded(concluded) {
 | 
						|
        this.concluded = concluded;
 | 
						|
        this.ca_section.setAttribute("visible", this.concluded ? "true" : "false");
 | 
						|
    }
 | 
						|
 | 
						|
    get isViewOnly() {
 | 
						|
        return this.view_only;
 | 
						|
    }
 | 
						|
 | 
						|
    set isViewOnly(viewOnly) {
 | 
						|
        this.view_only = viewOnly;
 | 
						|
    }
 | 
						|
 | 
						|
    get isCorrect() {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    set playerAnswer(player_answer) {
 | 
						|
        this.player_answer = player_answer;
 | 
						|
    }
 | 
						|
 | 
						|
    get playerAnswer() {
 | 
						|
        return this.player_answer;
 | 
						|
    }
 | 
						|
 | 
						|
    set correctAnswer(correct_answer) {
 | 
						|
        this.correct_answer = correct_answer;
 | 
						|
    }
 | 
						|
 | 
						|
    get correctAnswer() {
 | 
						|
        return this.correct_answer;
 | 
						|
    }
 | 
						|
 | 
						|
    set uploadAnswerCb(cb) {
 | 
						|
        this.upload_answer_cb = cb;
 | 
						|
    }
 | 
						|
 | 
						|
    set comment(comment) {
 | 
						|
        this.comment_sec.innerHTML = preprocess_inserts(comment);
 | 
						|
        MathJax.typeset([this.comment_sec]);
 | 
						|
    }
 | 
						|
 | 
						|
    uploadAnswer() {
 | 
						|
        if (this.upload_answer_cb !== null) {
 | 
						|
            this.upload_answer_cb(this.sequence_number, this.playerAnswer);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    displayCorrectAnswer() {
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    displayMarking() {
 | 
						|
        if (this.isConcluded) {
 | 
						|
            this.mark_section.innerText = `${this.mark}/${this.max_mark}`;
 | 
						|
        } else {
 | 
						|
            this.mark_section.innerText = `${this.max_mark}`;
 | 
						|
        }
 | 
						|
        this.mark_section.innerHTML += `<span style="font-size: 70%">p</span>`
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        this.setQuestion(a["question"]);
 | 
						|
        this.playerAnswer = a["player_answer"];
 | 
						|
        this.correctAnswer = a["correct_answer"];
 | 
						|
        this.max_mark = a["max_mark"];
 | 
						|
        this.mark = a["mark"];
 | 
						|
 | 
						|
        let comment = a["comment"];
 | 
						|
        if ((comment !== undefined) && (comment !== null) && (comment !== "")) {
 | 
						|
            this.comment = comment;
 | 
						|
            this.comment_sec.setAttribute("visible", "true");
 | 
						|
        }
 | 
						|
 | 
						|
        let mark = a["mark"];
 | 
						|
        if ((mark !== undefined) && (mark !== null) && (mark > -1) && (mark !== a["max_mark"])) {
 | 
						|
            this.task_box.classList.add("bad-answer");
 | 
						|
        }
 | 
						|
 | 
						|
        if (this.isConcluded) {
 | 
						|
            this.displayCorrectAnswer();
 | 
						|
        }
 | 
						|
 | 
						|
        this.displayMarking();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class PicturedTask extends Task {
 | 
						|
    constructor(type) {
 | 
						|
        super(type);
 | 
						|
 | 
						|
        this.img = null;
 | 
						|
        this.img_type = "none";
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += `
 | 
						|
            .question-image {
 | 
						|
                display: none;
 | 
						|
                position: relative;
 | 
						|
                margin: 1em auto;
 | 
						|
                border-radius: 0.3em;
 | 
						|
                max-width: 100%;
 | 
						|
                text-align: center;
 | 
						|
            }
 | 
						|
            .hljs {
 | 
						|
                padding: 0.3em;
 | 
						|
                border-radius: 3pt;
 | 
						|
            }
 | 
						|
        `;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
    }
 | 
						|
 | 
						|
    set imgData(data) {
 | 
						|
        switch (this.img_type) {
 | 
						|
            case "url":
 | 
						|
            {
 | 
						|
                this.img = document.createElement("img");
 | 
						|
                this.img.classList.add("question-image");
 | 
						|
 | 
						|
                data = data.trim();
 | 
						|
                this.img.src = data.trim();
 | 
						|
            }
 | 
						|
            break;
 | 
						|
            case "html":
 | 
						|
            case "code":
 | 
						|
            {
 | 
						|
                this.img = document.createElement("section");
 | 
						|
                this.img.classList.add("question-image");
 | 
						|
 | 
						|
                if (this.img_type === "html") {
 | 
						|
                    this.img.innerHTML = data;
 | 
						|
                } else if (this.img_type === "code") {
 | 
						|
                    let pre = document.createElement("pre");
 | 
						|
                    let code = document.createElement("code");
 | 
						|
                    pre.append(code);
 | 
						|
                    code.innerHTML = data;
 | 
						|
                    hljs.highlightElement(pre);
 | 
						|
 | 
						|
                    this.img.innerHTML = `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/base16/google-light.min.css"/>`;
 | 
						|
                    this.img.style.textAlign = "left";
 | 
						|
                    this.img.append(pre);
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (this.img != null) {
 | 
						|
            this.img.style.display = (data !== "") ? "block" : "none";
 | 
						|
            this.task_box.insertBefore(this.img, this.question_span);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    get imgData() {
 | 
						|
        return this.img.src;
 | 
						|
    }
 | 
						|
 | 
						|
    set imgType(t) {
 | 
						|
        this.img_type = t;
 | 
						|
    }
 | 
						|
 | 
						|
    get imgType() {
 | 
						|
        return this.img_type;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class SingleChoiceTask extends PicturedTask {
 | 
						|
    constructor() {
 | 
						|
        super("singlechoice");
 | 
						|
 | 
						|
        this.answers = []
 | 
						|
        this.correct_answer = -1;
 | 
						|
        this.player_answer = -1;
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += `
 | 
						|
            section.answer {
 | 
						|
                margin: 0.3em 0.8em;
 | 
						|
                display: block;
 | 
						|
            }
 | 
						|
            section.answer label {
 | 
						|
                margin-left: 0.5em;
 | 
						|
                padding: 0.3em 0.5em;
 | 
						|
                border-radius: 0.3em;
 | 
						|
            
 | 
						|
                display: inline-block;
 | 
						|
                max-width: 85%;
 | 
						|
                vertical-align: middle;
 | 
						|
            }            
 | 
						|
            section.answer label.correct-answer {
 | 
						|
                border: 2px solid #176767 !important;
 | 
						|
                background-color: #176767;
 | 
						|
                color: whitesmoke;
 | 
						|
                /*padding: 0.1em;*/
 | 
						|
            }
 | 
						|
            section.answer input[type="radio"]:checked+label:not(.correct-answer) {
 | 
						|
                background-color: #176767;
 | 
						|
                color: whitesmoke;
 | 
						|
            }
 | 
						|
            section.bad-answer section.answer input[type="radio"]:checked+label:not(.correct-answer) {
 | 
						|
                background-color: #aa8a7d;
 | 
						|
            }
 | 
						|
            @media only screen and (max-width: 800px) {
 | 
						|
                section.answer label {
 | 
						|
                    max-width: calc(100% - 4em);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        `;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
    }
 | 
						|
 | 
						|
    // --------
 | 
						|
 | 
						|
    setAnswers(answers) {
 | 
						|
        this.answers = answers;
 | 
						|
 | 
						|
        this.answers.forEach((answer, i) => {
 | 
						|
            let answer_section = document.createElement("section");
 | 
						|
            answer_section.classList.add("answer");
 | 
						|
            let answer_radio = document.createElement("input");
 | 
						|
            answer_radio.type = "radio";
 | 
						|
            answer_radio.id = `${this.sequenceNumber}_${i}`;
 | 
						|
            answer_radio.name = `task_${this.sequenceNumber}`;
 | 
						|
            answer_radio.disabled = this.isConcluded || this.isViewOnly;
 | 
						|
            let answer_N_snapshot = i;
 | 
						|
            answer_radio.addEventListener("input", () => {
 | 
						|
                this.playerAnswer = answer_N_snapshot;
 | 
						|
                this.uploadAnswer();
 | 
						|
            });
 | 
						|
 | 
						|
            let answer_text = document.createElement("label");
 | 
						|
            answer_text.innerHTML = preprocess_inserts(answer);
 | 
						|
            answer_text.htmlFor = answer_radio.id;
 | 
						|
            if (this.isConcluded && (this.correctAnswer === i)) {
 | 
						|
                answer_text.classList.add("correct-answer")
 | 
						|
 | 
						|
                if (this.playerAnswer !== this.correctAnswer) {
 | 
						|
                    this.task_box.classList.add("bad-answer");
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (this.playerAnswer === i) {
 | 
						|
                answer_radio.checked = true;
 | 
						|
            }
 | 
						|
 | 
						|
            answer_section.append(answer_radio, answer_text);
 | 
						|
            this.answer_container.append(answer_section);
 | 
						|
        });
 | 
						|
 | 
						|
        MathJax.typeset([this.task_box]);
 | 
						|
    }
 | 
						|
 | 
						|
    get isCorrect() {
 | 
						|
        return this.player_answer === this.correct_answer;
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        super.fromArray(a);
 | 
						|
 | 
						|
        this.setAnswers(a["answers"]);
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
class OpenEndedTask extends PicturedTask {
 | 
						|
    constructor() {
 | 
						|
        super("openended");
 | 
						|
 | 
						|
        this.ca_prefix = "<b>Lehetséges megoldások:</b>";
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += `
 | 
						|
            input[type="text"] {
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
                border-width: 0 0 2.2pt 0;
 | 
						|
                background-color: transparent;
 | 
						|
                width: calc(100% - 4em);
 | 
						|
                margin: 1em 0;
 | 
						|
                border-bottom-color: #176767;
 | 
						|
                font-size: 110%;
 | 
						|
            }
 | 
						|
            input[type="text"]:hover {
 | 
						|
                border-bottom-color: #408d8d;
 | 
						|
            }
 | 
						|
        `
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
 | 
						|
        let answer_tf = document.createElement("input");
 | 
						|
        answer_tf.type = "text";
 | 
						|
        answer_tf.placeholder = "(válasz)";
 | 
						|
 | 
						|
        answer_tf.onblur = () => {
 | 
						|
            this.uploadAnswer();
 | 
						|
        }
 | 
						|
        answer_tf.oninput = () => {
 | 
						|
            this.player_answer = answer_tf.value;
 | 
						|
        };
 | 
						|
 | 
						|
        this.answer_container.append(answer_tf);
 | 
						|
 | 
						|
        this.answer_tf = answer_tf;
 | 
						|
    }
 | 
						|
 | 
						|
    displayCorrectAnswer() {
 | 
						|
        if (this.correctAnswer !== null) {
 | 
						|
            this.ca_section.innerHTML = this.ca_prefix + "<br style='margin-bottom: 0.3em'>" + this.correctAnswer.join(", <i>VAGY</i><br>");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        super.fromArray(a);
 | 
						|
    }
 | 
						|
 | 
						|
    set playerAnswer(player_answer) {
 | 
						|
        if (player_answer === null) {
 | 
						|
            player_answer = "";
 | 
						|
        }
 | 
						|
        super.playerAnswer = player_answer;
 | 
						|
        this.answer_tf.value = this.playerAnswer;
 | 
						|
    }
 | 
						|
 | 
						|
    get playerAnswer() {
 | 
						|
        return super.playerAnswer;
 | 
						|
    }
 | 
						|
 | 
						|
    updateAnswerFieldState() {
 | 
						|
        this.answer_tf.disabled = this.isViewOnly || this.isConcluded;
 | 
						|
    }
 | 
						|
 | 
						|
    set isConcluded(concluded) {
 | 
						|
        super.isConcluded = concluded;
 | 
						|
        this.updateAnswerFieldState();
 | 
						|
    }
 | 
						|
 | 
						|
    get isConcluded() {
 | 
						|
        return super.isConcluded;
 | 
						|
    }
 | 
						|
 | 
						|
    set isViewOnly(is_view_only) {
 | 
						|
        super.isViewOnly = is_view_only;
 | 
						|
    }
 | 
						|
 | 
						|
    get isViewOnly() {
 | 
						|
        return super.isViewOnly;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class NumberConversionTask extends OpenEndedTask {
 | 
						|
    constructor() {
 | 
						|
        super();
 | 
						|
        this.type = "numberconversion";
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += `
 | 
						|
            input[type="text"] {
 | 
						|
                min-width: 5em;
 | 
						|
                width: unset;
 | 
						|
            }
 | 
						|
            section#src, section#dst {
 | 
						|
                position: relative;
 | 
						|
                display: inline-block;
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
                color: #176767;
 | 
						|
            }
 | 
						|
            section#src {
 | 
						|
                margin-right: 1ch;
 | 
						|
            }
 | 
						|
            sub {
 | 
						|
                position: relative; 
 | 
						|
                top: 0.8em;
 | 
						|
            }
 | 
						|
        `;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
 | 
						|
        let src_sec = document.createElement("section");
 | 
						|
        src_sec.id = "src";
 | 
						|
        let dst_sec = document.createElement("section");
 | 
						|
        dst_sec.id = "dst";
 | 
						|
 | 
						|
        this.answer_container.insertBefore(src_sec, this.answer_tf);
 | 
						|
        this.answer_container.append(dst_sec);
 | 
						|
 | 
						|
        this.src_sec = src_sec;
 | 
						|
        this.dst_sec = dst_sec;
 | 
						|
 | 
						|
        this.answer_tf.addEventListener("input", () => {
 | 
						|
            this.updateAnswerFieldLength();
 | 
						|
        })
 | 
						|
    }
 | 
						|
 | 
						|
    displayCorrectAnswer() {
 | 
						|
        this.ca_section.innerHTML = `Megoldás: <code>${this.correctAnswer}</code><sub>(${this.dst_base})</sub>`;
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        const regex = /([0-9]+)([suc]):([0-9]+)->([0-9]+)([suc]):([0-9]+)/g;
 | 
						|
        let parts = [...a["instruction"].matchAll(regex)][0];
 | 
						|
 | 
						|
        this.src_base = parts[1];
 | 
						|
        this.dst_base = parts[4];
 | 
						|
        this.src_len = parts[6];
 | 
						|
 | 
						|
        let src_exp = `${a["source"]}<sub>(${parts[1]})</sub> =`;
 | 
						|
        let dst_exp = `<sub>(${parts[4]})</sub> <i>(${parts[6]} digiten)</i>`;
 | 
						|
 | 
						|
        super.fromArray(a);
 | 
						|
 | 
						|
        this.src_sec.innerHTML = src_exp;
 | 
						|
        this.dst_sec.innerHTML = dst_exp;
 | 
						|
 | 
						|
        this.updateAnswerFieldLength();
 | 
						|
    }
 | 
						|
 | 
						|
    updateAnswerFieldLength() {
 | 
						|
        this.answer_tf.style.width = this.answer_tf.value.length + "ch";
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class Switch extends HTMLElement {
 | 
						|
    constructor() {
 | 
						|
        super();
 | 
						|
 | 
						|
        this.state = "-";
 | 
						|
        this.highlight = "-";
 | 
						|
        this.M = 2;
 | 
						|
        this.disabled = false;
 | 
						|
 | 
						|
        this.shadow = this.attachShadow({mode: "open"});
 | 
						|
        this.createStyle();
 | 
						|
        this.createElements();
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        this.css = document.createElement("style");
 | 
						|
        this.css.innerHTML = `
 | 
						|
            section.frame {
 | 
						|
                display: inline-block;
 | 
						|
                border: 1pt solid black;                
 | 
						|
            }
 | 
						|
            section.button {
 | 
						|
                display: inline-block;
 | 
						|
                padding: 0.2em 0.5em;
 | 
						|
                cursor: pointer;
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
            }
 | 
						|
            section.button[disabled="false"]:hover {
 | 
						|
                background-color: #408d8d;
 | 
						|
                color: white;
 | 
						|
            }
 | 
						|
            section.button[highlight="true"] {
 | 
						|
                background-color: #aa8a7d;
 | 
						|
                color: white;
 | 
						|
            }
 | 
						|
            section.button[selected="true"] {
 | 
						|
                background-color: #176767;
 | 
						|
                color: white;
 | 
						|
            }
 | 
						|
            section.button:not(:last-child) {
 | 
						|
                border-right: 1pt dotted black;
 | 
						|
            }
 | 
						|
        `;
 | 
						|
        this.shadow.append(this.css);
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        let frame = document.createElement("section");
 | 
						|
        frame.classList.add("frame");
 | 
						|
        let btns = [];
 | 
						|
        for (let i = 0; i < this.M; i++) {
 | 
						|
            let btn = document.createElement("section");
 | 
						|
            btn.classList.add("button");
 | 
						|
            btn.innerText = i.toString();
 | 
						|
            btn.id = "btn_" + i.toString();
 | 
						|
            btn.setAttribute("disabled", "false");
 | 
						|
            btns.push(btn);
 | 
						|
 | 
						|
            btn.addEventListener("click", (e) => {
 | 
						|
                if (!this.disabled) {
 | 
						|
                    this.setState(i);
 | 
						|
                    this.dispatchEvent(new Event("change"));
 | 
						|
                }
 | 
						|
            })
 | 
						|
 | 
						|
            frame.append(btn);
 | 
						|
        }
 | 
						|
 | 
						|
        document.createElement("section");
 | 
						|
 | 
						|
        this.frame = frame;
 | 
						|
        this.btns = btns;
 | 
						|
 | 
						|
        this.shadow.append(frame);
 | 
						|
 | 
						|
        this.setDisabled(false);
 | 
						|
    }
 | 
						|
 | 
						|
    setState(state) {
 | 
						|
        this.state = state;
 | 
						|
        for (let i = 0; i < this.M; i++) {
 | 
						|
            this.btns[i].setAttribute("selected", (i.toString() === this.state.toString()) ? "true" : "false");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    setHighlight(hl) {
 | 
						|
        this.highlight = hl;
 | 
						|
        for (let i = 0; i < this.M; i++) {
 | 
						|
            this.btns[i].setAttribute("highlight", (i.toString() === this.highlight.toString()) ? "true" : "false");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    getState() {
 | 
						|
        return this.state;
 | 
						|
    }
 | 
						|
 | 
						|
    setDisabled(disabled) {
 | 
						|
        this.disabled = disabled;
 | 
						|
        this.frame.setAttribute("disabled", disabled ? "true" : "false");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
var truth_table_css = `
 | 
						|
    table#tt {
 | 
						|
        border: 1.5pt solid #176767;
 | 
						|
        margin: 0.5em auto;
 | 
						|
        border-spacing: 0;
 | 
						|
        font-family: 'Source Code Pro', monospace;
 | 
						|
    }
 | 
						|
    table#tt tr:not(:last-child) td {
 | 
						|
        border-bottom: 1.2pt solid black;
 | 
						|
    }
 | 
						|
    table#tt th {
 | 
						|
        border-bottom: 1.5pt dotted black
 | 
						|
    }
 | 
						|
    table#tt td, table#tt th {
 | 
						|
        min-width: 3ch;
 | 
						|
        text-align: center;
 | 
						|
    }
 | 
						|
    table#tt td:last-child, table#tt th:last-child {
 | 
						|
        border-left: 1.5pt dashed black;
 | 
						|
    }
 | 
						|
`;
 | 
						|
 | 
						|
class TruthTableTask extends PicturedTask {
 | 
						|
    constructor() {
 | 
						|
        super("truthtable");
 | 
						|
 | 
						|
        this.input_variables = [];
 | 
						|
        this.output_variable = "";
 | 
						|
        this.output_switches = [];
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += truth_table_css;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
 | 
						|
        let tt = document.createElement("table");
 | 
						|
        tt.id = "tt";
 | 
						|
 | 
						|
        this.answer_container.append(tt);
 | 
						|
 | 
						|
        this.tt = tt;
 | 
						|
    }
 | 
						|
 | 
						|
    updatePlayerAnswer() {
 | 
						|
        let pa = "";
 | 
						|
        for (let i = 0; i < this.output_switches.length; i++) {
 | 
						|
            pa += this.output_switches[i].getState();
 | 
						|
        }
 | 
						|
        super.playerAnswer = pa;
 | 
						|
    }
 | 
						|
 | 
						|
    buildTTable() {
 | 
						|
        let N = this.input_variables.length;
 | 
						|
        let M = (1 << N);
 | 
						|
 | 
						|
        let inside = "<tr>"
 | 
						|
        for (let i = 0; i < N; i++) {
 | 
						|
            inside += "<th>" + this.input_variables[i] + "</th>";
 | 
						|
        }
 | 
						|
        inside += "<th>" + this.output_variable + "</th>";
 | 
						|
        inside += "</tr>";
 | 
						|
        for (let i = 0; i < M; i++) {
 | 
						|
            inside += "<tr>";
 | 
						|
            for (let j = 0; j < N; j++) {
 | 
						|
                inside += "<td>" + ((i >> (N - j - 1)) & 1).toString() + "</td>";
 | 
						|
            }
 | 
						|
            inside += "<td><slide-switch id='out_" + i + "'></slide-switch></td>"
 | 
						|
            inside += "</tr>";
 | 
						|
        }
 | 
						|
 | 
						|
        this.tt.innerHTML = inside;
 | 
						|
 | 
						|
        for (let i = 0; i < M; i++) {
 | 
						|
            let sw = this.shadow.getElementById("out_" + i);
 | 
						|
            sw.addEventListener("change", () => {
 | 
						|
                this.updatePlayerAnswer();
 | 
						|
                this.uploadAnswer();
 | 
						|
            });
 | 
						|
            sw.setDisabled(this.isConcluded || this.isViewOnly);
 | 
						|
            this.output_switches[i] = sw;
 | 
						|
        }
 | 
						|
 | 
						|
        this.playerAnswer = "-".repeat(M);
 | 
						|
    }
 | 
						|
 | 
						|
    set playerAnswer(playerAnswer) {
 | 
						|
        if (playerAnswer !== null) {
 | 
						|
            super.playerAnswer = playerAnswer;
 | 
						|
        }
 | 
						|
 | 
						|
        for (let i = 0; i < this.output_switches.length; i++) {
 | 
						|
            let sw = this.output_switches[i];
 | 
						|
            let pac = this.playerAnswer.charAt(i);
 | 
						|
            if (!this.isConcluded) {
 | 
						|
                sw.setState(pac);
 | 
						|
            } else {
 | 
						|
                let cac = this.correctAnswer.charAt(i);
 | 
						|
                if (cac !== pac) {
 | 
						|
                    sw.setHighlight(pac);
 | 
						|
                }
 | 
						|
                sw.setState(cac);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    get playerAnswer() {
 | 
						|
        return super.playerAnswer;
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        super.fromArray(a);
 | 
						|
 | 
						|
        this.input_variables = a["input_variables"];
 | 
						|
        this.output_variable = a["output_variable"];
 | 
						|
 | 
						|
        this.buildTTable();
 | 
						|
 | 
						|
        this.playerAnswer = a["player_answer"];
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class LogicFunctionTask extends OpenEndedTask {
 | 
						|
    constructor() {
 | 
						|
        super();
 | 
						|
        this.type = "logicfunction";
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += truth_table_css;
 | 
						|
        this.css.innerHTML += `
 | 
						|
            section#assignment-sec {
 | 
						|
                position: relative;
 | 
						|
                display: inline-block;
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
                color: #176767;
 | 
						|
                margin-right: 1ch;
 | 
						|
            }
 | 
						|
            input[type="text"] {
 | 
						|
                min-width: 5em;
 | 
						|
                width: 85%;
 | 
						|
                font-family: 'Source Code Pro', monospace;
 | 
						|
            }
 | 
						|
        `;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
 | 
						|
        let assignment_sec = document.createElement("section");
 | 
						|
        assignment_sec.id = "assignment-sec";
 | 
						|
 | 
						|
        this.answer_container.insertBefore(assignment_sec, this.answer_tf);
 | 
						|
 | 
						|
        this.assignment_sec = assignment_sec;
 | 
						|
    }
 | 
						|
 | 
						|
    drawTruthTable() {
 | 
						|
        let N = this.input_variables.length;
 | 
						|
        let M = (1 << N);
 | 
						|
 | 
						|
        let table = "<table id='tt'>";
 | 
						|
        table += "<tr>";
 | 
						|
        for (let i = 0; i < N; i++) {
 | 
						|
            table += "<th>" + this.input_variables[i] + "</th>";
 | 
						|
        }
 | 
						|
        table += "<th>" + this.output_variable + "</th>";
 | 
						|
        table += "</tr>";
 | 
						|
        for (let i = 0; i < M; i++) {
 | 
						|
            table += "<tr>";
 | 
						|
            for (let j = 0; j < N; j++) {
 | 
						|
                table += "<td>" + ((i >> (N - j - 1)) & 1).toString() + "</td>";
 | 
						|
            }
 | 
						|
            table += "<td>" + this.truth_table.charAt(i) + "</td>"
 | 
						|
            table += "</tr>";
 | 
						|
        }
 | 
						|
        table += "</table>";
 | 
						|
 | 
						|
        this.imgType = "html";
 | 
						|
        this.imgData = table;
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        super.fromArray(a);
 | 
						|
 | 
						|
        this.input_variables = a["input_variables"];
 | 
						|
        this.output_variable = a["output_variable"];
 | 
						|
        this.truth_table = a["truthtable"];
 | 
						|
 | 
						|
        this.assignment_sec.innerHTML = `${a["output_variable"]} = `;
 | 
						|
 | 
						|
        if ((this.truth_table !== undefined) && (this.truth_table !== null) && (this.truth_table !== "")) {
 | 
						|
            this.drawTruthTable();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    set correctAnswer(correct_answer) {
 | 
						|
        super.correctAnswer = [ "<code>" + correct_answer + "</code>" ];
 | 
						|
    }
 | 
						|
 | 
						|
    get correctAnswer() {
 | 
						|
        return super.correctAnswer;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class VerilogTask extends PicturedTask {
 | 
						|
    //static observedAttributes = ["language"]
 | 
						|
    constructor() {
 | 
						|
        super("verilog");
 | 
						|
    }
 | 
						|
 | 
						|
    createStyle() {
 | 
						|
        super.createStyle();
 | 
						|
 | 
						|
        this.css.innerHTML += `
 | 
						|
            section.editor-sec {
 | 
						|
                margin-top: 1em;
 | 
						|
                min-height: 24em;
 | 
						|
                font-family: 'JetBrains Mono', monospace;
 | 
						|
            }
 | 
						|
            div.ace_content {
 | 
						|
                font-variant-ligatures: none;
 | 
						|
            }
 | 
						|
            section#explain-sec {
 | 
						|
                font-family: 'JetBrains Mono', monospace;
 | 
						|
                margin-top: 0.5em;
 | 
						|
                width: calc(100% - 0.4em);
 | 
						|
                padding: 0.2em;
 | 
						|
                background: #e5e5e57f;
 | 
						|
            }
 | 
						|
            section#correct-answer-title {
 | 
						|
                padding: 1em 0 0.5em 0.2em;
 | 
						|
                font-weight: bold;
 | 
						|
            }
 | 
						|
        `;
 | 
						|
    }
 | 
						|
 | 
						|
    createElements() {
 | 
						|
        super.createElements();
 | 
						|
 | 
						|
        let editor_sec = document.createElement("section");
 | 
						|
        editor_sec.classList.add("editor-sec");
 | 
						|
        this.answer_container.append(editor_sec);
 | 
						|
 | 
						|
        let editor = ace.edit(editor_sec, {
 | 
						|
            theme: "ace/theme/chrome",
 | 
						|
            mode: "ace/mode/verilog"
 | 
						|
        });
 | 
						|
        editor.renderer.attachToShadowRoot();
 | 
						|
 | 
						|
        editor.addEventListener("blur", () => {
 | 
						|
            this.uploadAnswer();
 | 
						|
        });
 | 
						|
 | 
						|
        let explain_sec = document.createElement("section");
 | 
						|
        explain_sec.id = "explain-sec";
 | 
						|
        this.ca_section.append(explain_sec);
 | 
						|
 | 
						|
        let solution_title_sec = document.createElement("section");
 | 
						|
        solution_title_sec.innerText = "Egy lehetséges megoldás:";
 | 
						|
        solution_title_sec.id = "correct-answer-title";
 | 
						|
 | 
						|
        this.ca_section.append(solution_title_sec);
 | 
						|
 | 
						|
        let solution_sec = document.createElement("section");
 | 
						|
        solution_sec.id = "solution-sec";
 | 
						|
        solution_sec.classList.add("editor-sec");
 | 
						|
        let solution_editor = ace.edit(solution_sec, {
 | 
						|
            theme: "ace/theme/chrome",
 | 
						|
            mode: "ace/mode/verilog",
 | 
						|
        });
 | 
						|
        solution_editor.setReadOnly(true);
 | 
						|
        solution_editor.renderer.attachToShadowRoot();
 | 
						|
 | 
						|
        this.ca_section.append(solution_sec);
 | 
						|
 | 
						|
        this.editor_sec = editor_sec;
 | 
						|
        this.editor = editor;
 | 
						|
        this.explain_sec = explain_sec;
 | 
						|
        this.solution_title_sec = solution_title_sec;
 | 
						|
        this.solution_sec = solution_sec;
 | 
						|
        this.solution_editor = solution_editor;
 | 
						|
    }
 | 
						|
 | 
						|
    set playerAnswer(player_answer) {
 | 
						|
        this.editor.setValue(player_answer);
 | 
						|
        this.editor.clearSelection();
 | 
						|
    }
 | 
						|
 | 
						|
    get playerAnswer() {
 | 
						|
        return this.editor.getValue();
 | 
						|
    }
 | 
						|
 | 
						|
    set correctAnswer(player_answer) {
 | 
						|
        this.solution_editor.setValue(player_answer);
 | 
						|
        this.solution_editor.clearSelection();
 | 
						|
    }
 | 
						|
 | 
						|
    get correctAnswer() {
 | 
						|
        return super.correctAnswer;
 | 
						|
    }
 | 
						|
 | 
						|
    fromArray(a) {
 | 
						|
        super.fromArray(a);
 | 
						|
 | 
						|
        this.explain_sec.innerText = a["compile_log"];
 | 
						|
    }
 | 
						|
 | 
						|
    updateEditorFreezeState() {
 | 
						|
        this.editor.setReadOnly(this.isConcluded || this.isViewOnly);
 | 
						|
    }
 | 
						|
 | 
						|
    set isConcluded(concluded) {
 | 
						|
        super.isConcluded = concluded;
 | 
						|
 | 
						|
        this.updateEditorFreezeState();
 | 
						|
 | 
						|
        if (concluded) {
 | 
						|
            this.solution_editor.setValue(this.correctAnswer);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    get isConcluded() {
 | 
						|
        return super.isConcluded;
 | 
						|
    }
 | 
						|
 | 
						|
    set isViewOnly(viewOnly) {
 | 
						|
        super.isViewOnly = viewOnly;
 | 
						|
 | 
						|
        this.updateEditorFreezeState();
 | 
						|
    }
 | 
						|
 | 
						|
    get isViewOnly() {
 | 
						|
        return super.isViewOnly;
 | 
						|
    }
 | 
						|
 | 
						|
    // attributeChangedCallback(name, oldVal, newVal) {
 | 
						|
    //     switch (name) {
 | 
						|
    //         case "language":
 | 
						|
    //             editor.session.setMode("ace/mode/" + newVal.toLowerCase());
 | 
						|
    //             break;
 | 
						|
    //     }
 | 
						|
    // }
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
customElements.define('singlechoice-task', SingleChoiceTask);
 | 
						|
customElements.define('openended-task', OpenEndedTask);
 | 
						|
customElements.define('numberconversion-task', NumberConversionTask);
 | 
						|
customElements.define('slide-switch', Switch);
 | 
						|
customElements.define('truthtable-task', TruthTableTask);
 | 
						|
customElements.define('logicfunction-task', LogicFunctionTask);
 | 
						|
customElements.define('verilog-task', VerilogTask);
 | 
						|
 | 
						|
 |