<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<!-- question: 1916  -->
  <question type="coderunner">
    <name>
      <text>LOCAL_PROTOTYPE_HTML_via_python</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<p dir="ltr" style="text-align: left;">This question type is an attempt to grade HTML programmatically.</p>]]></text>
    </questiontext>
    <generalfeedback format="html">
      <text></text>
    </generalfeedback>
    <defaultgrade>1</defaultgrade>
    <penalty>0</penalty>
    <hidden>0</hidden>
    <idnumber></idnumber>
    <coderunnertype>HTML_via_python</coderunnertype>
    <prototypetype>2</prototypetype>
    <allornothing>1</allornothing>
    <penaltyregime>10, 20, ...</penaltyregime>
    <precheck>0</precheck>
    <showsource>0</showsource>
    <answerboxlines>18</answerboxlines>
    <answerboxcolumns>100</answerboxcolumns>
    <answerpreload></answerpreload>
    <globalextra><![CDATA[<script>
// Based on https://github.com/tomhodgins/liveeditor.
$(document).ready(function() {
    var doc = $(document),
        html = $('#crui_html'),
        css = $('#crui_css'),
        js = $('#crui_js'),
        clear = $('#crui_clearall');

    // Display combined content from HTML, CSS, and JS textareas in the iframe.
    function show_preview() {
        var iframedoc = document.getElementById("preview").contentWindow.document;
        iframedoc.write("<head><style>" + css.val() + "<\/style><\/head><body>" + html.val() + "<script>" + js.val() + "</\script><\/body>");
        iframedoc.close();
    }

    function handle_tab(event) {
        var target, start, end, value;
        if (event.keyCode === 9) {
            target = event.target;
            start = target.selectionStart;
            end = target.selectionEnd;
            value = target.value;
            target.value = value.substring(0, start) + "  " + value.substring(end);
            target.selectionStart = target.selectionEnd = start + 2;
            event.preventDefault();
        }
    }

    function clearAll() {
        html.val('');
        css.val('');
        js.val('');
    }

    doc.keydown(handle_tab);
    doc.keyup(show_preview);
    clear.click(clearAll);
    show_preview();
});
</script>

<h1>HTML Demo question</h1>
<a id="crui_clearall" href="#" title="Click to clear all">Clear all</a>
<br>
<textarea id="crui_html" rows="5" cols="80" value="" class="coderunner-ui-element" name='crui_html' spellcheck="false" placeholder="HTML" autocapitalize="off" autofocus
style="font-family: monospace"></textarea>
<br>
<textarea id="crui_css" rows="3" cols="80" value="" placeholder="CSS" class="coderunner-ui-element" name='crui_css' spellcheck="false" autocapitalize="off"
style="font-family: monospace"></textarea>
<br>
<textarea id="crui_js" rows="3" cols="80" value="" class="coderunner-ui-element" name='crui_js' spellcheck="false" placeholder="JavaScript" autocapitalize="off" style="font-family: monospace"></textarea>
<br>
<iframe id="preview" width="700" height="200"></iframe>]]></globalextra>
    <useace>1</useace>
    <resultcolumns></resultcolumns>
    <template><![CDATA[from html.parser import HTMLParser
import json

class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.output = []

    def handle_starttag(self, tag, attrs):
        self.output.append(["startTag",f"<{tag}>"])

    def handle_endtag(self, tag):
        self.output.append(["endTag",f"</{tag}>"])

    def handle_data(self, data):
        if not data.isspace():
            self.output.append(["data",data])

studentAnswer = json.loads("""{{ STUDENT_ANSWER | e('py') }}""")

studentHTML = studentAnswer["crui_html"][0]
studentHTMLParser = MyHTMLParser()
studentHTMLParser.feed(studentHTML)
correctAnswer = """{{ QUESTION.answer | e('py') }}"""
correctAnswerParser = MyHTMLParser()
correctAnswerParser.feed(correctAnswer)
result = "OK"
lastTag = None

if len(correctAnswerParser.output) < len(studentHTMLParser.output):
    result = "Too much!"
else:
    for count,x in enumerate(correctAnswerParser.output):
        lastTag = x[1]
        try:
            if x[0] == "startTag" or x[0] == "endTag":
                if x[1] != studentHTMLParser.output[count][1]:
                    result = "Missing: " + x[1]
                    break
            if x[0] == "data":
                if x[1] == "\n":
                    break
                if x[1] == studentHTMLParser.output[count][1]:
                    result = "Don't copy my example!"
                    break
                
                #Student put nothing between some tags
                if studentHTMLParser.output[count][0] != "data":
                    result = "Missing: " + x[1]
                    break
                
                #Student data is nothing but spaces
                if studentHTMLParser.output[count][1].isspace():
                    result = "Missing: " + x[1]
                    break
                
        except IndexError:
            result = "Missing: " + lastTag
            
print(result)]]></template>
    <iscombinatortemplate>0</iscombinatortemplate>
    <allowmultiplestdins>0</allowmultiplestdins>
    <answer></answer>
    <validateonsave>1</validateonsave>
    <testsplitterre></testsplitterre>
    <language>python3</language>
    <acelang></acelang>
    <sandbox></sandbox>
    <grader>EqualityGrader</grader>
    <cputimelimitsecs></cputimelimitsecs>
    <memlimitmb></memlimitmb>
    <sandboxparams></sandboxparams>
    <templateparams></templateparams>
    <hoisttemplateparams>1</hoisttemplateparams>
    <twigall>0</twigall>
    <uiplugin>html</uiplugin>
    <attachments>0</attachments>
    <attachmentsrequired>0</attachmentsrequired>
    <maxfilesize>10240</maxfilesize>
    <filenamesregex></filenamesregex>
    <filenamesexplain></filenamesexplain>
    <displayfeedback>1</displayfeedback>
    <testcases>
    </testcases>
  </question>

</quiz>