-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathchallenge_area.html
More file actions
169 lines (157 loc) · 6.06 KB
/
challenge_area.html
File metadata and controls
169 lines (157 loc) · 6.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<div class="challenge-header">
<div class="challenge-header__title">
<span>Challenge - {{ name }}</span>
{%include 'components/badge.html' with context %}
</div>
<p class="challenge-header__exerpt">
Complete code following the instructions, so that lines followed by
<code># expect-type-error</code> (if any)
fail type check, while others can pass.<br>
Hit the "▶️ Run" button to see result.
</p>
<div class="hints-container">
{% if hints_for_display %}
<a id="read-hints" role="button" class="secondary outline" href="javascript:void(0);">💡 Read Hints</a>
{% else %}
<div id="hints-missing">💡 No Hints Available</div>
{% endif %}
<article class="hints-message">{{hints_for_display | safe}}</article>
</div>
</div>
<div class="challenge-main" {{challenge_main_htmx}}>
<div class="codemirror-container">
<div id="editor">
<a id="playground-link" target="_blank" rel="noopener noreferrer">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4m-8-2l8-8m0 0v5m0-5h-5" />
</svg>
<span>Open Pyright Playground</span>
</a>
</div>
<div class="editor-actions">
<p id="answer-link">Stuck? Check out
<a target="_blank" rel="noopener noreferrer"
href="https://github.com/laike9m/Python-Type-Challenges/tree/main/challenges/{{level}}-{{name}}/solution.py">
solution
</a>
</p>
<button id="reset-button" class="secondary">
Reset
</button>
<button id="run-button">
▶️ Run
</button>
</div>
</div>
<div class="tests-result-container">
<div id="tests"></div>
<div id="result"></div>
</div>
</div>
<script type="module">
import passedState from "{{ url_for('static', filename='js/passed-state.js')}}";
/**
* Render the code area with CodeMirror and Jinja2.
*
* @param {string} code_under_test - The code to be tested.
* @param {string} test_code - The test code.
* @param {'basic'|'intermediate'|'advanced'|'extreme'} level - The level of the challenge.
* @param {string} name - The name of the challenge.
*/
function renderCodeArea(code_under_test, test_code, level, name) {
let confetti = new JSConfetti();
let initTheme = localStorage.getItem('theme') === 'dark' ? "material-darker" : "default"
let sharedCodeMirrorOptions = {
mode: "python",
lineWrapping: true,
lineNumbers: true,
indentUnit: 4,
theme: initTheme,
}
let myCodeMirror = CodeMirror(document.getElementById("editor"), {
value: code_under_test,
...sharedCodeMirrorOptions,
});
let testCodeMirror = CodeMirror(document.getElementById("tests"), {
value: test_code,
readOnly: "nocursor",
...sharedCodeMirrorOptions,
});
let playgroundLink = document.getElementById("playground-link");
playgroundLink.addEventListener('click', function (event) {
const code = myCodeMirror.getValue() + testCodeMirror.getValue();
this.href = "https://pyright-play.net/?code=" + LZString.compressToEncodedURIComponent(code);
});
window.addEventListener('themeSwitch', function (event) {
let theme = localStorage.getItem('theme') === 'dark' ? "material-darker" : "default"
myCodeMirror.setOption("theme", theme);
testCodeMirror.setOption("theme", theme);
})
let runButton = document.getElementById('run-button')
runButton.onclick = function () {
console.log(`Run challenge at: ${new Date().toLocaleString()}`);
// set button spinner
let rawInnerText = runButton.innerText;
runButton.ariaBusy = true;
runButton.innerText = ""
let code = myCodeMirror.getValue();
fetch(`/run/${level}/${name}`, {
method: 'POST',
body: code
})
.then(response => response.json())
.then(json => {
// add confetti effect when passed
if (json.passed) {
confetti.addConfetti()
// passedState is defined in challenge_sidebar.html
passedState.setPassed(level, name);
document.getElementById(`${level}-${name}`).parentNode.classList.add('passed');
}
setTimeout(() => {
document.getElementById('answer-link').style.display = 'block';
}, 500);
document.getElementById("result").innerHTML = json.message;
if (json.debug_info !== undefined) {
console.log(json.debug_info);
}
})
.catch((error) => {
console.error('Error:', error);
})
.finally(() => {
// reset button spinner
runButton.ariaBusy = false;
runButton.innerText = rawInnerText;
});
};
let resetButton = document.getElementById('reset-button')
resetButton.onclick = function () {
myCodeMirror.setValue(code_under_test);
};
// Set up hints events and functions
let hintBtn = document.getElementById('read-hints')
if (hintBtn !== null) {
hintBtn.onclick = function () {
// Toggle the display of the hints message.
let msgElem = document.getElementsByClassName('hints-message')[0];
if (msgElem.style.display === 'block') {
msgElem.style.display = 'none';
} else {
msgElem.style.display = 'block';
}
};
// Make sure to open links in hints in new tab.
document.querySelectorAll('.hints-message a').forEach(function(elem) {
elem.setAttribute('target', '_blank');
})
}
// Make sure the current challenge is visible to user.
let activeChallengeInList = document.getElementById(`${level}-${name}`);
activeChallengeInList.parentNode.classList.add('active-challenge'); // Highlight
}
let codeUnderTest = {{code_under_test | tojson}};
let testCode = {{test_code | tojson}};
renderCodeArea(codeUnderTest, testCode, "{{level}}", "{{name}}");
</script>