munchboka-edutools 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. munchboka_edutools/__init__.py +182 -0
  2. munchboka_edutools/_plotmath_shim.py +126 -0
  3. munchboka_edutools/_version.py +2 -0
  4. munchboka_edutools/directives/__init__.py +1 -0
  5. munchboka_edutools/directives/admonitions.py +356 -0
  6. munchboka_edutools/directives/cas_popup.py +272 -0
  7. munchboka_edutools/directives/dialogue.py +137 -0
  8. munchboka_edutools/directives/escape_room.py +296 -0
  9. munchboka_edutools/directives/factor_tree.py +549 -0
  10. munchboka_edutools/directives/ggb.py +209 -0
  11. munchboka_edutools/directives/ggb_icon.py +62 -0
  12. munchboka_edutools/directives/ggb_popup.py +165 -0
  13. munchboka_edutools/directives/horner.py +324 -0
  14. munchboka_edutools/directives/interactive_code.py +75 -0
  15. munchboka_edutools/directives/jeopardy.py +252 -0
  16. munchboka_edutools/directives/multi_plot.py +1126 -0
  17. munchboka_edutools/directives/pair_puzzle.py +191 -0
  18. munchboka_edutools/directives/parsons.py +109 -0
  19. munchboka_edutools/directives/plot.py +3012 -0
  20. munchboka_edutools/directives/poly_icon.py +91 -0
  21. munchboka_edutools/directives/polydiv.py +344 -0
  22. munchboka_edutools/directives/quiz.py +291 -0
  23. munchboka_edutools/directives/signchart.py +474 -0
  24. munchboka_edutools/directives/timed_quiz.py +436 -0
  25. munchboka_edutools/directives/turtle.py +157 -0
  26. munchboka_edutools/static/css/admonitions.css +2012 -0
  27. munchboka_edutools/static/css/cas_popup.css +242 -0
  28. munchboka_edutools/static/css/code_mirror_themes/github_dark_cm.css +112 -0
  29. munchboka_edutools/static/css/code_mirror_themes/github_dark_default_cm.css +40 -0
  30. munchboka_edutools/static/css/code_mirror_themes/github_dark_high_contrast_cm.css +141 -0
  31. munchboka_edutools/static/css/code_mirror_themes/github_light_cm.css +120 -0
  32. munchboka_edutools/static/css/code_mirror_themes/github_light_default_cm.css +108 -0
  33. munchboka_edutools/static/css/code_mirror_themes/one_dark_cm.css +121 -0
  34. munchboka_edutools/static/css/dialogue.css +92 -0
  35. munchboka_edutools/static/css/escapeRoom/escape-room.css +223 -0
  36. munchboka_edutools/static/css/figures.css +274 -0
  37. munchboka_edutools/static/css/general_style.css +74 -0
  38. munchboka_edutools/static/css/github-dark-high-contrast.css +141 -0
  39. munchboka_edutools/static/css/github-dark.css +112 -0
  40. munchboka_edutools/static/css/github-light.css +120 -0
  41. munchboka_edutools/static/css/interactive_code/style.css +575 -0
  42. munchboka_edutools/static/css/interactive_code.css +582 -0
  43. munchboka_edutools/static/css/jeopardy.css +476 -0
  44. munchboka_edutools/static/css/pairPuzzle/style.css +177 -0
  45. munchboka_edutools/static/css/parsons/parsonsPuzzle.css +331 -0
  46. munchboka_edutools/static/css/quiz.css +312 -0
  47. munchboka_edutools/static/css/timedQuiz.css +375 -0
  48. munchboka_edutools/static/icons/ggb/mode_evaluate.svg +1 -0
  49. munchboka_edutools/static/icons/ggb/mode_extremum.svg +1 -0
  50. munchboka_edutools/static/icons/ggb/mode_intersect.svg +1 -0
  51. munchboka_edutools/static/icons/ggb/mode_nsolve.svg +1 -0
  52. munchboka_edutools/static/icons/ggb/mode_numeric.svg +1 -0
  53. munchboka_edutools/static/icons/ggb/mode_point.svg +1 -0
  54. munchboka_edutools/static/icons/ggb/mode_solve.svg +1 -0
  55. munchboka_edutools/static/icons/misc/windows-logo.svg +1 -0
  56. munchboka_edutools/static/icons/outline/dark_mode/academic.svg +3 -0
  57. munchboka_edutools/static/icons/outline/dark_mode/backward.svg +3 -0
  58. munchboka_edutools/static/icons/outline/dark_mode/book.svg +3 -0
  59. munchboka_edutools/static/icons/outline/dark_mode/chat_bubble.svg +3 -0
  60. munchboka_edutools/static/icons/outline/dark_mode/check.svg +3 -0
  61. munchboka_edutools/static/icons/outline/dark_mode/cmd_line.svg +3 -0
  62. munchboka_edutools/static/icons/outline/dark_mode/file.svg +1 -0
  63. munchboka_edutools/static/icons/outline/dark_mode/fire.svg +4 -0
  64. munchboka_edutools/static/icons/outline/dark_mode/key.svg +3 -0
  65. munchboka_edutools/static/icons/outline/dark_mode/magnifying.svg +3 -0
  66. munchboka_edutools/static/icons/outline/dark_mode/pencil_square.svg +3 -0
  67. munchboka_edutools/static/icons/outline/dark_mode/play.svg +3 -0
  68. munchboka_edutools/static/icons/outline/dark_mode/question.svg +3 -0
  69. munchboka_edutools/static/icons/outline/dark_mode/square_check.svg +1 -0
  70. munchboka_edutools/static/icons/outline/dark_mode/stop.svg +3 -0
  71. munchboka_edutools/static/icons/outline/dark_mode/summary.svg +3 -0
  72. munchboka_edutools/static/icons/outline/dark_mode/undo.svg +3 -0
  73. munchboka_edutools/static/icons/outline/dark_mode/unlock.svg +3 -0
  74. munchboka_edutools/static/icons/outline/light_mode/academic.svg +3 -0
  75. munchboka_edutools/static/icons/outline/light_mode/backward.svg +3 -0
  76. munchboka_edutools/static/icons/outline/light_mode/book.svg +3 -0
  77. munchboka_edutools/static/icons/outline/light_mode/chat_bubble.svg +3 -0
  78. munchboka_edutools/static/icons/outline/light_mode/check.svg +3 -0
  79. munchboka_edutools/static/icons/outline/light_mode/cmd_line.svg +3 -0
  80. munchboka_edutools/static/icons/outline/light_mode/file.svg +1 -0
  81. munchboka_edutools/static/icons/outline/light_mode/fire.svg +4 -0
  82. munchboka_edutools/static/icons/outline/light_mode/key.svg +3 -0
  83. munchboka_edutools/static/icons/outline/light_mode/magnifying.svg +3 -0
  84. munchboka_edutools/static/icons/outline/light_mode/pencil_square.svg +3 -0
  85. munchboka_edutools/static/icons/outline/light_mode/play.svg +3 -0
  86. munchboka_edutools/static/icons/outline/light_mode/question.svg +3 -0
  87. munchboka_edutools/static/icons/outline/light_mode/square_check.svg +1 -0
  88. munchboka_edutools/static/icons/outline/light_mode/stop.svg +3 -0
  89. munchboka_edutools/static/icons/outline/light_mode/summary.svg +3 -0
  90. munchboka_edutools/static/icons/outline/light_mode/undo.svg +3 -0
  91. munchboka_edutools/static/icons/outline/light_mode/unlock.svg +3 -0
  92. munchboka_edutools/static/icons/polyicons/cubicdown.svg +3 -0
  93. munchboka_edutools/static/icons/polyicons/cubicup.svg +3 -0
  94. munchboka_edutools/static/icons/polyicons/frown.svg +3 -0
  95. munchboka_edutools/static/icons/polyicons/smile.svg +3 -0
  96. munchboka_edutools/static/icons/solid/dark_mode/academic.svg +5 -0
  97. munchboka_edutools/static/icons/solid/dark_mode/backward.svg +3 -0
  98. munchboka_edutools/static/icons/solid/dark_mode/book.svg +3 -0
  99. munchboka_edutools/static/icons/solid/dark_mode/brain.svg +1 -0
  100. munchboka_edutools/static/icons/solid/dark_mode/file.svg +1 -0
  101. munchboka_edutools/static/icons/solid/dark_mode/fire.svg +3 -0
  102. munchboka_edutools/static/icons/solid/dark_mode/key.svg +3 -0
  103. munchboka_edutools/static/icons/solid/dark_mode/pencil_square.svg +4 -0
  104. munchboka_edutools/static/icons/solid/dark_mode/play.svg +3 -0
  105. munchboka_edutools/static/icons/solid/dark_mode/python.svg +1 -0
  106. munchboka_edutools/static/icons/solid/dark_mode/scroll.svg +1 -0
  107. munchboka_edutools/static/icons/solid/dark_mode/stop.svg +3 -0
  108. munchboka_edutools/static/icons/solid/light_mode/academic.svg +5 -0
  109. munchboka_edutools/static/icons/solid/light_mode/backward.svg +3 -0
  110. munchboka_edutools/static/icons/solid/light_mode/book.svg +3 -0
  111. munchboka_edutools/static/icons/solid/light_mode/brain.svg +1 -0
  112. munchboka_edutools/static/icons/solid/light_mode/file.svg +1 -0
  113. munchboka_edutools/static/icons/solid/light_mode/fire.svg +3 -0
  114. munchboka_edutools/static/icons/solid/light_mode/key.svg +3 -0
  115. munchboka_edutools/static/icons/solid/light_mode/pencil_square.svg +4 -0
  116. munchboka_edutools/static/icons/solid/light_mode/play.svg +3 -0
  117. munchboka_edutools/static/icons/solid/light_mode/python.svg +1 -0
  118. munchboka_edutools/static/icons/solid/light_mode/scroll.svg +1 -0
  119. munchboka_edutools/static/icons/solid/light_mode/stop.svg +3 -0
  120. munchboka_edutools/static/icons/stickers/edit.svg +1 -0
  121. munchboka_edutools/static/icons/stickers/pencil_square.svg +3 -0
  122. munchboka_edutools/static/js/casThemeManager.js +99 -0
  123. munchboka_edutools/static/js/escapeRoom/escape-room.js +219 -0
  124. munchboka_edutools/static/js/geogebra-setup.js +6 -0
  125. munchboka_edutools/static/js/highlight-init.js +6 -0
  126. munchboka_edutools/static/js/interactiveCode/codeEditor.js +632 -0
  127. munchboka_edutools/static/js/interactiveCode/interactiveCodeSetup.js +348 -0
  128. munchboka_edutools/static/js/interactiveCode/pythonRunner.js +336 -0
  129. munchboka_edutools/static/js/interactiveCode/turtleCode.js +203 -0
  130. munchboka_edutools/static/js/interactiveCode/workerManager.js +353 -0
  131. munchboka_edutools/static/js/interactive_code/codeEditor.js +662 -0
  132. munchboka_edutools/static/js/interactive_code/interactiveCodeSetup.js +252 -0
  133. munchboka_edutools/static/js/interactive_code/pythonRunner.js +145 -0
  134. munchboka_edutools/static/js/interactive_code/turtleCode.js +56 -0
  135. munchboka_edutools/static/js/interactive_code/workerManager.js +204 -0
  136. munchboka_edutools/static/js/jeopardy.js +457 -0
  137. munchboka_edutools/static/js/pairPuzzle/draggableItem.js +64 -0
  138. munchboka_edutools/static/js/pairPuzzle/dropZone.js +119 -0
  139. munchboka_edutools/static/js/pairPuzzle/game.js +160 -0
  140. munchboka_edutools/static/js/parsons/parsonsPuzzle.js +641 -0
  141. munchboka_edutools/static/js/quiz.js +422 -0
  142. munchboka_edutools/static/js/skulpt/skulpt.js +35721 -0
  143. munchboka_edutools/static/js/timedQuiz/multipleChoiceQuestion.js +184 -0
  144. munchboka_edutools/static/js/timedQuiz/timedMultipleChoiceQuiz.js +244 -0
  145. munchboka_edutools/static/js/timedQuiz/utils.js +6 -0
  146. munchboka_edutools/static/js/utils.js +3 -0
  147. munchboka_edutools-0.1.0.dist-info/METADATA +107 -0
  148. munchboka_edutools-0.1.0.dist-info/RECORD +150 -0
  149. munchboka_edutools-0.1.0.dist-info/WHEEL +4 -0
  150. munchboka_edutools-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,191 @@
1
+ """
2
+ Pair Puzzle Directive
3
+ =====================
4
+
5
+ A Sphinx directive for creating interactive pairing puzzles where users drag and drop
6
+ items to match pairs. Uses KaTeX for math rendering.
7
+
8
+ Usage:
9
+ .. pair-puzzle::
10
+ :class: optional-css-class
11
+
12
+ Left item 1 : Right item 1
13
+ Left item 2 : Right item 2
14
+ Left item 3 : Right item 3
15
+
16
+ The directive accepts content as pairs separated by ':'. Each line represents a pair
17
+ that the user must match. Items can contain HTML, LaTeX math (using $ or $$), or code blocks.
18
+
19
+ Example:
20
+ .. pair-puzzle::
21
+
22
+ $x^2 + 2x + 1$ : $(x+1)^2$
23
+ $\\sin^2(x) + \\cos^2(x)$ : $1$
24
+ <code>print("hello")</code> : Python output function
25
+
26
+ MyST Syntax (colon-fence):
27
+ :::{pairpuzzle}
28
+ :class: optional-css-class
29
+
30
+ Left item 1 : Right item 1
31
+ Left item 2 : Right item 2
32
+ :::
33
+
34
+ Note: Due to MyST limitations with hyphens in directive names when using colon-fence
35
+ syntax (:::), the directive is also registered as "pairpuzzle" (no hyphen).
36
+ """
37
+
38
+ from docutils import nodes
39
+ from docutils.parsers.rst import Directive
40
+ from docutils.parsers.rst import directives
41
+ from sphinx.application import Sphinx
42
+ import uuid
43
+
44
+
45
+ class PairPuzzleNode(nodes.General, nodes.Element):
46
+ """Custom docutils node for pair puzzles."""
47
+
48
+ pass
49
+
50
+
51
+ class PairPuzzleDirective(Directive):
52
+ """
53
+ Directive for creating interactive pairing puzzles.
54
+
55
+ The directive parses content as colon-separated pairs and generates
56
+ HTML/JavaScript for an interactive drag-and-drop game.
57
+ """
58
+
59
+ has_content = True
60
+ option_spec = {
61
+ "class": directives.class_option,
62
+ }
63
+
64
+ def run(self):
65
+ """Parse the directive content and create the puzzle node."""
66
+ # Generate unique container ID
67
+ container_id = f"pair-puzzle-{uuid.uuid4()}"
68
+
69
+ # Parse pairs from content
70
+ pairs = self._parse_pairs()
71
+
72
+ if not pairs:
73
+ error = self.state_machine.reporter.error(
74
+ 'pair-puzzle directive requires at least one pair (format: "left : right")',
75
+ nodes.literal_block(self.block_text, self.block_text),
76
+ line=self.lineno,
77
+ )
78
+ return [error]
79
+
80
+ # Create the custom node
81
+ node = PairPuzzleNode()
82
+ node["container_id"] = container_id
83
+ node["pairs"] = pairs
84
+ node["classes"] = self.options.get("class", [])
85
+
86
+ return [node]
87
+
88
+ def _parse_pairs(self):
89
+ """
90
+ Parse content into pairs.
91
+
92
+ Expected format:
93
+ Left item 1 : Right item 1
94
+ Left item 2 : Right item 2
95
+
96
+ Returns:
97
+ List of tuples [(left1, right1), (left2, right2), ...]
98
+ """
99
+ pairs = []
100
+ for line in self.content:
101
+ line = line.strip()
102
+ if not line:
103
+ continue
104
+
105
+ # Split on first ':' only
106
+ if ":" in line:
107
+ left, right = line.split(":", 1)
108
+ pairs.append((left.strip(), right.strip()))
109
+ else:
110
+ # Skip lines without ':' separator
111
+ continue
112
+
113
+ return pairs
114
+
115
+
116
+ def visit_pair_puzzle_html(self, node):
117
+ """Generate HTML for the pair puzzle."""
118
+ container_id = node["container_id"]
119
+ pairs = node["pairs"]
120
+ extra_classes = " ".join(node["classes"])
121
+
122
+ # Build JavaScript pairs array
123
+ js_pairs = []
124
+ for left, right in pairs:
125
+ js_pairs.append(f'["{left}", "{right}"]')
126
+
127
+ pairs_js = ",\n ".join(js_pairs)
128
+
129
+ # Generate HTML container
130
+ html = f"""
131
+ <div id="{container_id}" class="pairing-puzzle-container {extra_classes}">
132
+ <!-- Content will be generated by JavaScript -->
133
+ </div>
134
+
135
+ <script>
136
+ // Initialize the pairing puzzle when DOM is ready
137
+ (function() {{
138
+ function initPuzzle() {{
139
+ const pairs = [
140
+ {pairs_js}
141
+ ];
142
+
143
+ // Check if initGame is available
144
+ if (typeof initGame === 'function') {{
145
+ initGame('{container_id}', pairs);
146
+ }} else {{
147
+ console.error('initGame function not found. Make sure game.js is loaded.');
148
+ }}
149
+ }}
150
+
151
+ // Wait for DOM and required dependencies
152
+ if (document.readyState === 'loading') {{
153
+ document.addEventListener('DOMContentLoaded', initPuzzle);
154
+ }} else {{
155
+ initPuzzle();
156
+ }}
157
+ }})();
158
+ </script>
159
+ """
160
+
161
+ self.body.append(html)
162
+
163
+
164
+ def depart_pair_puzzle_html(self, node):
165
+ """No closing tags needed."""
166
+ pass
167
+
168
+
169
+ def setup(app: Sphinx):
170
+ """
171
+ Setup the pair-puzzle directive.
172
+
173
+ Registers the directive under two names:
174
+ - "pair-puzzle" for RST compatibility
175
+ - "pairpuzzle" for MyST colon-fence compatibility (no hyphens allowed)
176
+ """
177
+ # Register the custom node
178
+ app.add_node(PairPuzzleNode, html=(visit_pair_puzzle_html, depart_pair_puzzle_html))
179
+
180
+ # Register directive with both names for compatibility
181
+ app.add_directive("pair-puzzle", PairPuzzleDirective)
182
+ app.add_directive("pairpuzzle", PairPuzzleDirective) # MyST compatibility
183
+
184
+ # Note: CSS and JS files are registered in __init__.py with the munchboka/ prefix
185
+ # No need to register them here to avoid duplicate/incorrect paths
186
+
187
+ return {
188
+ "version": "0.1",
189
+ "parallel_read_safe": True,
190
+ "parallel_write_safe": True,
191
+ }
@@ -0,0 +1,109 @@
1
+ """
2
+ Parsons Puzzle directive for creating code-reordering exercises.
3
+
4
+ This directive creates interactive puzzles where students must arrange shuffled
5
+ lines of code into the correct order through drag-and-drop.
6
+
7
+ Usage:
8
+ ```{parsons-puzzle} puzzle-id
9
+ :lang: python
10
+
11
+ def fibonacci(n):
12
+ if n <= 1:
13
+ return n
14
+ else:
15
+ return fibonacci(n-1) + fibonacci(n-2)
16
+ ```
17
+
18
+ Options:
19
+ - lang (optional): Programming language for syntax highlighting (default: python)
20
+
21
+ Arguments:
22
+ - Puzzle identifier (optional): If provided, creates a unique ID for the puzzle.
23
+ Otherwise, a random ID is generated.
24
+
25
+ Features:
26
+ - Drag-and-drop code lines into correct order
27
+ - Syntax highlighting with highlight.js
28
+ - Check solution button with visual feedback (toast notifications)
29
+ - Reset button to reshuffle and try again
30
+ - Modal popup showing complete code when solved
31
+ - Copy to clipboard functionality
32
+ - Theme-aware styling (light/dark mode)
33
+ """
34
+
35
+ from docutils import nodes
36
+ from docutils.parsers.rst import Directive, directives
37
+ import uuid
38
+
39
+
40
+ class ParsonsPuzzleDirective(Directive):
41
+ """
42
+ Directive for creating Parsons puzzles (code reordering exercises).
43
+
44
+ Students must drag and drop shuffled code lines into the correct order.
45
+ """
46
+
47
+ has_content = True
48
+ required_arguments = 0
49
+ optional_arguments = 1
50
+ final_argument_whitespace = True
51
+ option_spec = {
52
+ "lang": directives.unchanged,
53
+ }
54
+
55
+ def run(self):
56
+ """Generate HTML for the Parsons puzzle."""
57
+ # Generate a unique identifier or use the provided one
58
+ if self.arguments:
59
+ identifier = self.arguments[0]
60
+ else:
61
+ identifier = f"puzzle-{uuid.uuid4().hex[:8]}"
62
+
63
+ puzzle_container_id = f"container-parsons-puzzle-{identifier}"
64
+ editor_container_id = f"container-kode-{identifier}"
65
+
66
+ # Get code content from the directive content
67
+ code_content = "\n".join(self.content)
68
+
69
+ # Escape code for JavaScript
70
+ escaped_code = code_content.replace("`", "\\`").replace("$", "\\$")
71
+
72
+ # Create the HTML with the template
73
+ html = f"""
74
+ <div id="{puzzle_container_id}" class="puzzle-container"></div>
75
+ <div id="{editor_container_id}" style="display: none"></div>
76
+
77
+ <script type="text/javascript">
78
+ document.addEventListener("DOMContentLoaded", () => {{
79
+ const code =
80
+ `{escaped_code}`;
81
+
82
+ const puzzleContainerId = '{puzzle_container_id}';
83
+ const editorId = '{editor_container_id}';
84
+
85
+ const switchToCodeEditor = makeCallbackFunction(puzzleContainerId, editorId);
86
+ const puzzle = new ParsonsPuzzle(
87
+ puzzleContainerId,
88
+ code,
89
+ switchToCodeEditor,
90
+ );
91
+ }});
92
+ </script>
93
+ """
94
+
95
+ raw_node = nodes.raw("", html, format="html")
96
+ return [raw_node]
97
+
98
+
99
+ def setup(app):
100
+ """Register the parsons-puzzle directive with Sphinx."""
101
+ app.add_directive("parsons-puzzle", ParsonsPuzzleDirective)
102
+ # Also register without hyphen for MyST compatibility
103
+ app.add_directive("parsonspuzzle", ParsonsPuzzleDirective)
104
+
105
+ return {
106
+ "version": "0.1.0",
107
+ "parallel_read_safe": True,
108
+ "parallel_write_safe": True,
109
+ }