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.
- munchboka_edutools/__init__.py +182 -0
- munchboka_edutools/_plotmath_shim.py +126 -0
- munchboka_edutools/_version.py +2 -0
- munchboka_edutools/directives/__init__.py +1 -0
- munchboka_edutools/directives/admonitions.py +356 -0
- munchboka_edutools/directives/cas_popup.py +272 -0
- munchboka_edutools/directives/dialogue.py +137 -0
- munchboka_edutools/directives/escape_room.py +296 -0
- munchboka_edutools/directives/factor_tree.py +549 -0
- munchboka_edutools/directives/ggb.py +209 -0
- munchboka_edutools/directives/ggb_icon.py +62 -0
- munchboka_edutools/directives/ggb_popup.py +165 -0
- munchboka_edutools/directives/horner.py +324 -0
- munchboka_edutools/directives/interactive_code.py +75 -0
- munchboka_edutools/directives/jeopardy.py +252 -0
- munchboka_edutools/directives/multi_plot.py +1126 -0
- munchboka_edutools/directives/pair_puzzle.py +191 -0
- munchboka_edutools/directives/parsons.py +109 -0
- munchboka_edutools/directives/plot.py +3012 -0
- munchboka_edutools/directives/poly_icon.py +91 -0
- munchboka_edutools/directives/polydiv.py +344 -0
- munchboka_edutools/directives/quiz.py +291 -0
- munchboka_edutools/directives/signchart.py +474 -0
- munchboka_edutools/directives/timed_quiz.py +436 -0
- munchboka_edutools/directives/turtle.py +157 -0
- munchboka_edutools/static/css/admonitions.css +2012 -0
- munchboka_edutools/static/css/cas_popup.css +242 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_cm.css +112 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_default_cm.css +40 -0
- munchboka_edutools/static/css/code_mirror_themes/github_dark_high_contrast_cm.css +141 -0
- munchboka_edutools/static/css/code_mirror_themes/github_light_cm.css +120 -0
- munchboka_edutools/static/css/code_mirror_themes/github_light_default_cm.css +108 -0
- munchboka_edutools/static/css/code_mirror_themes/one_dark_cm.css +121 -0
- munchboka_edutools/static/css/dialogue.css +92 -0
- munchboka_edutools/static/css/escapeRoom/escape-room.css +223 -0
- munchboka_edutools/static/css/figures.css +274 -0
- munchboka_edutools/static/css/general_style.css +74 -0
- munchboka_edutools/static/css/github-dark-high-contrast.css +141 -0
- munchboka_edutools/static/css/github-dark.css +112 -0
- munchboka_edutools/static/css/github-light.css +120 -0
- munchboka_edutools/static/css/interactive_code/style.css +575 -0
- munchboka_edutools/static/css/interactive_code.css +582 -0
- munchboka_edutools/static/css/jeopardy.css +476 -0
- munchboka_edutools/static/css/pairPuzzle/style.css +177 -0
- munchboka_edutools/static/css/parsons/parsonsPuzzle.css +331 -0
- munchboka_edutools/static/css/quiz.css +312 -0
- munchboka_edutools/static/css/timedQuiz.css +375 -0
- munchboka_edutools/static/icons/ggb/mode_evaluate.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_extremum.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_intersect.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_nsolve.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_numeric.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_point.svg +1 -0
- munchboka_edutools/static/icons/ggb/mode_solve.svg +1 -0
- munchboka_edutools/static/icons/misc/windows-logo.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/academic.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/book.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/chat_bubble.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/check.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/cmd_line.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/file.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/fire.svg +4 -0
- munchboka_edutools/static/icons/outline/dark_mode/key.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/magnifying.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/pencil_square.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/play.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/question.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/square_check.svg +1 -0
- munchboka_edutools/static/icons/outline/dark_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/summary.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/undo.svg +3 -0
- munchboka_edutools/static/icons/outline/dark_mode/unlock.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/academic.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/book.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/chat_bubble.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/check.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/cmd_line.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/file.svg +1 -0
- munchboka_edutools/static/icons/outline/light_mode/fire.svg +4 -0
- munchboka_edutools/static/icons/outline/light_mode/key.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/magnifying.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/pencil_square.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/play.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/question.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/square_check.svg +1 -0
- munchboka_edutools/static/icons/outline/light_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/summary.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/undo.svg +3 -0
- munchboka_edutools/static/icons/outline/light_mode/unlock.svg +3 -0
- munchboka_edutools/static/icons/polyicons/cubicdown.svg +3 -0
- munchboka_edutools/static/icons/polyicons/cubicup.svg +3 -0
- munchboka_edutools/static/icons/polyicons/frown.svg +3 -0
- munchboka_edutools/static/icons/polyicons/smile.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/academic.svg +5 -0
- munchboka_edutools/static/icons/solid/dark_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/book.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/brain.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/file.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/fire.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/key.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/pencil_square.svg +4 -0
- munchboka_edutools/static/icons/solid/dark_mode/play.svg +3 -0
- munchboka_edutools/static/icons/solid/dark_mode/python.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/scroll.svg +1 -0
- munchboka_edutools/static/icons/solid/dark_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/academic.svg +5 -0
- munchboka_edutools/static/icons/solid/light_mode/backward.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/book.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/brain.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/file.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/fire.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/key.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/pencil_square.svg +4 -0
- munchboka_edutools/static/icons/solid/light_mode/play.svg +3 -0
- munchboka_edutools/static/icons/solid/light_mode/python.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/scroll.svg +1 -0
- munchboka_edutools/static/icons/solid/light_mode/stop.svg +3 -0
- munchboka_edutools/static/icons/stickers/edit.svg +1 -0
- munchboka_edutools/static/icons/stickers/pencil_square.svg +3 -0
- munchboka_edutools/static/js/casThemeManager.js +99 -0
- munchboka_edutools/static/js/escapeRoom/escape-room.js +219 -0
- munchboka_edutools/static/js/geogebra-setup.js +6 -0
- munchboka_edutools/static/js/highlight-init.js +6 -0
- munchboka_edutools/static/js/interactiveCode/codeEditor.js +632 -0
- munchboka_edutools/static/js/interactiveCode/interactiveCodeSetup.js +348 -0
- munchboka_edutools/static/js/interactiveCode/pythonRunner.js +336 -0
- munchboka_edutools/static/js/interactiveCode/turtleCode.js +203 -0
- munchboka_edutools/static/js/interactiveCode/workerManager.js +353 -0
- munchboka_edutools/static/js/interactive_code/codeEditor.js +662 -0
- munchboka_edutools/static/js/interactive_code/interactiveCodeSetup.js +252 -0
- munchboka_edutools/static/js/interactive_code/pythonRunner.js +145 -0
- munchboka_edutools/static/js/interactive_code/turtleCode.js +56 -0
- munchboka_edutools/static/js/interactive_code/workerManager.js +204 -0
- munchboka_edutools/static/js/jeopardy.js +457 -0
- munchboka_edutools/static/js/pairPuzzle/draggableItem.js +64 -0
- munchboka_edutools/static/js/pairPuzzle/dropZone.js +119 -0
- munchboka_edutools/static/js/pairPuzzle/game.js +160 -0
- munchboka_edutools/static/js/parsons/parsonsPuzzle.js +641 -0
- munchboka_edutools/static/js/quiz.js +422 -0
- munchboka_edutools/static/js/skulpt/skulpt.js +35721 -0
- munchboka_edutools/static/js/timedQuiz/multipleChoiceQuestion.js +184 -0
- munchboka_edutools/static/js/timedQuiz/timedMultipleChoiceQuiz.js +244 -0
- munchboka_edutools/static/js/timedQuiz/utils.js +6 -0
- munchboka_edutools/static/js/utils.js +3 -0
- munchboka_edutools-0.1.0.dist-info/METADATA +107 -0
- munchboka_edutools-0.1.0.dist-info/RECORD +150 -0
- munchboka_edutools-0.1.0.dist-info/WHEEL +4 -0
- munchboka_edutools-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GeoGebra Directive for Munchboka Edutools
|
|
3
|
+
=========================================
|
|
4
|
+
|
|
5
|
+
This directive embeds interactive GeoGebra applets in the documentation.
|
|
6
|
+
It uses the GeoGebra API to create fully functional mathematics tools
|
|
7
|
+
directly in the browser.
|
|
8
|
+
|
|
9
|
+
Usage in MyST Markdown:
|
|
10
|
+
```{ggb} 720 600
|
|
11
|
+
:material_id: abcdef123
|
|
12
|
+
:toolbar: true
|
|
13
|
+
:menubar: true
|
|
14
|
+
:algebra: true
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with defaults (empty applet):
|
|
18
|
+
```{ggb} 800 600
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or with perspective:
|
|
22
|
+
```{ggb} 720 600
|
|
23
|
+
:material_id: xyz789
|
|
24
|
+
:perspective: graphing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Features:
|
|
28
|
+
- Embed existing GeoGebra materials by ID
|
|
29
|
+
- Configure toolbar, menubar, and algebra view visibility
|
|
30
|
+
- Set custom dimensions (width × height)
|
|
31
|
+
- Multiple perspective options (graphing, geometry, 3d, etc.)
|
|
32
|
+
- Automatic fullscreen and reset buttons
|
|
33
|
+
- Norwegian language interface
|
|
34
|
+
|
|
35
|
+
Arguments:
|
|
36
|
+
width (optional): Width in pixels (default: 720)
|
|
37
|
+
height (optional): Height in pixels (default: 600)
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
material_id (optional): GeoGebra material ID to load
|
|
41
|
+
toolbar (optional): Show toolbar ("true"/"false", default: "false")
|
|
42
|
+
menubar (optional): Show menubar ("true"/"false", default: "false")
|
|
43
|
+
algebra (optional): Show algebra view ("true"/"false", default: "false")
|
|
44
|
+
perspective (optional): Perspective to use (e.g., "graphing", "geometry", "3d")
|
|
45
|
+
|
|
46
|
+
Dependencies:
|
|
47
|
+
- GeoGebra API: Loaded via deployggb.js (already registered in __init__.py)
|
|
48
|
+
- geogebra-setup.js: Theme management and initialization
|
|
49
|
+
|
|
50
|
+
Author: René Aasen (ported from matematikk_r1)
|
|
51
|
+
Date: November 2025
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
from docutils import nodes
|
|
55
|
+
from sphinx.util.docutils import SphinxDirective
|
|
56
|
+
from docutils.parsers.rst import directives
|
|
57
|
+
import uuid
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class GGBDirective(SphinxDirective):
|
|
61
|
+
"""
|
|
62
|
+
Sphinx directive for embedding interactive GeoGebra applets.
|
|
63
|
+
|
|
64
|
+
This directive creates a container div and uses the GeoGebra API
|
|
65
|
+
(deployggb.js) to inject an interactive mathematics applet.
|
|
66
|
+
|
|
67
|
+
Arguments:
|
|
68
|
+
width (optional): Width in pixels (default: 720)
|
|
69
|
+
height (optional): Height in pixels (default: 600)
|
|
70
|
+
|
|
71
|
+
Options:
|
|
72
|
+
material_id: GeoGebra material ID (e.g., from geogebra.org/m/xyz)
|
|
73
|
+
toolbar: Show toolbar ("true"/"false")
|
|
74
|
+
menubar: Show menubar ("true"/"false")
|
|
75
|
+
algebra: Show algebra view ("true"/"false")
|
|
76
|
+
perspective: Perspective to use ("graphing", "geometry", "3d", etc.)
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
Embed a specific GeoGebra material:
|
|
80
|
+
```{ggb} 720 600
|
|
81
|
+
:material_id: abcdef123
|
|
82
|
+
:toolbar: true
|
|
83
|
+
:menubar: true
|
|
84
|
+
:algebra: true
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Create an empty applet:
|
|
88
|
+
```{ggb} 800 600
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use a specific perspective:
|
|
92
|
+
```{ggb} 720 600
|
|
93
|
+
:material_id: xyz789
|
|
94
|
+
:perspective: graphing
|
|
95
|
+
```
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
required_arguments = 0
|
|
99
|
+
optional_arguments = 2 # width and height
|
|
100
|
+
has_content = False
|
|
101
|
+
|
|
102
|
+
option_spec = {
|
|
103
|
+
"material_id": directives.unchanged,
|
|
104
|
+
"toolbar": directives.unchanged,
|
|
105
|
+
"menubar": directives.unchanged,
|
|
106
|
+
"algebra": directives.unchanged,
|
|
107
|
+
"perspective": directives.unchanged,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
def run(self):
|
|
111
|
+
"""
|
|
112
|
+
Generate the HTML for the GeoGebra applet.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
list: List of docutils nodes (raw HTML node)
|
|
116
|
+
"""
|
|
117
|
+
# Convert arguments to integers (with defaults if conversion fails)
|
|
118
|
+
try:
|
|
119
|
+
width = int(self.arguments[0])
|
|
120
|
+
except (IndexError, ValueError):
|
|
121
|
+
width = 720
|
|
122
|
+
try:
|
|
123
|
+
height = int(self.arguments[1])
|
|
124
|
+
except (IndexError, ValueError):
|
|
125
|
+
height = 600
|
|
126
|
+
|
|
127
|
+
# Get options
|
|
128
|
+
material_id = self.options.get("material_id", None)
|
|
129
|
+
toolbar = self.options.get("toolbar", "false")
|
|
130
|
+
menubar = self.options.get("menubar", "false")
|
|
131
|
+
algebra = self.options.get("algebra", "false")
|
|
132
|
+
perspective = self.options.get("perspective", None)
|
|
133
|
+
|
|
134
|
+
# Format perspective option
|
|
135
|
+
if perspective:
|
|
136
|
+
perspective_option = f"perspective: '{perspective}'"
|
|
137
|
+
else:
|
|
138
|
+
perspective_option = "'': ''"
|
|
139
|
+
|
|
140
|
+
# Format material_id option
|
|
141
|
+
if material_id:
|
|
142
|
+
material_id_option = f"material_id: '{material_id}'"
|
|
143
|
+
else:
|
|
144
|
+
# If no material_id is provided, enable all controls by default
|
|
145
|
+
# This creates an empty applet with full functionality
|
|
146
|
+
material_id_option = "'': ''"
|
|
147
|
+
toolbar = "true"
|
|
148
|
+
menubar = "true"
|
|
149
|
+
algebra = "true"
|
|
150
|
+
|
|
151
|
+
# Generate a unique container ID using a short UUID
|
|
152
|
+
container_id = f"ggb-cas-{uuid.uuid4().hex[:8]}"
|
|
153
|
+
|
|
154
|
+
# Create the raw HTML
|
|
155
|
+
# Note: GeoGebra API (deployggb.js) is already loaded via __init__.py
|
|
156
|
+
html = f"""
|
|
157
|
+
<div id="{container_id}" style="width: {width}px; height: {height}px;" class="ggb-window"></div>
|
|
158
|
+
<script>
|
|
159
|
+
document.addEventListener("DOMContentLoaded", function() {{
|
|
160
|
+
var options = {{
|
|
161
|
+
appName: 'classic',
|
|
162
|
+
width: {width},
|
|
163
|
+
height: {height},
|
|
164
|
+
showToolBar: {toolbar},
|
|
165
|
+
showAlgebraInput: {algebra},
|
|
166
|
+
showMenuBar: {menubar},
|
|
167
|
+
language: 'nb',
|
|
168
|
+
borderRadius: 8,
|
|
169
|
+
borderColor: '#000000',
|
|
170
|
+
showFullscreenButton: true,
|
|
171
|
+
showResetIcon: true,
|
|
172
|
+
scale: 1,
|
|
173
|
+
rounding: 2,
|
|
174
|
+
showKeyboardOnFocus: false,
|
|
175
|
+
preventFocus: true,
|
|
176
|
+
id: '{container_id}',
|
|
177
|
+
{material_id_option},
|
|
178
|
+
{perspective_option},
|
|
179
|
+
}};
|
|
180
|
+
|
|
181
|
+
var applet = new GGBApplet(options, true);
|
|
182
|
+
applet.inject('{container_id}');
|
|
183
|
+
}});
|
|
184
|
+
</script>
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
return [nodes.raw("", html, format="html")]
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def setup(app):
|
|
191
|
+
"""
|
|
192
|
+
Setup function to register the directive with Sphinx.
|
|
193
|
+
|
|
194
|
+
This function is called automatically by Sphinx when the extension is loaded.
|
|
195
|
+
It registers the 'ggb' directive for use in documentation.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
app: The Sphinx application instance
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
dict: Extension metadata including version and parallel processing flags
|
|
202
|
+
"""
|
|
203
|
+
app.add_directive("ggb", GGBDirective)
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
"version": "0.1",
|
|
207
|
+
"parallel_read_safe": True,
|
|
208
|
+
"parallel_write_safe": True,
|
|
209
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GeoGebra icon role for inline SVG icons.
|
|
3
|
+
|
|
4
|
+
This role allows you to insert GeoGebra tool icons inline in text.
|
|
5
|
+
The icons are SVG files that represent various GeoGebra tools and modes.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
This is the {ggb-icon}`mode_intersect` tool in GeoGebra.
|
|
9
|
+
|
|
10
|
+
Click the {ggb-icon}`mode_solve` icon to solve equations.
|
|
11
|
+
|
|
12
|
+
Available icons:
|
|
13
|
+
- mode_evaluate: Evaluate/compute icon
|
|
14
|
+
- mode_extremum: Find extremum (min/max) icon
|
|
15
|
+
- mode_intersect: Find intersection point icon
|
|
16
|
+
- mode_nsolve: Numeric solve icon
|
|
17
|
+
- mode_numeric: Numeric computation icon
|
|
18
|
+
- mode_point: Point tool icon
|
|
19
|
+
- mode_solve: Symbolic solve icon
|
|
20
|
+
|
|
21
|
+
The icons are rendered as inline images with appropriate alt text.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from docutils import nodes
|
|
25
|
+
from docutils.parsers.rst import roles
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ggb_icon_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
|
29
|
+
"""
|
|
30
|
+
Custom role for GeoGebra icons.
|
|
31
|
+
|
|
32
|
+
Usage: {ggb-icon}`mode_intersect`
|
|
33
|
+
|
|
34
|
+
This generates an image node that Sphinx processes as an inline SVG icon.
|
|
35
|
+
"""
|
|
36
|
+
# Clean up the icon name (remove any extra whitespace)
|
|
37
|
+
icon_name = text.strip()
|
|
38
|
+
|
|
39
|
+
# Build the image path relative to the source directory
|
|
40
|
+
# Note: The path uses munchboka subdirectory since static files are organized there
|
|
41
|
+
img_src = f"/_static/munchboka/icons/ggb/{icon_name}.svg"
|
|
42
|
+
|
|
43
|
+
# Create a proper image node that Sphinx can process
|
|
44
|
+
node = nodes.image(uri=img_src, alt=f"GeoGebra {icon_name} icon")
|
|
45
|
+
|
|
46
|
+
# Add the inline-image class for styling
|
|
47
|
+
node["classes"] = ["inline-image"]
|
|
48
|
+
|
|
49
|
+
return [node], []
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def setup(app):
|
|
53
|
+
"""Setup function to register the role with Sphinx."""
|
|
54
|
+
# Register the role with both hyphenated and unhyphenated names
|
|
55
|
+
roles.register_local_role("ggb-icon", ggb_icon_role)
|
|
56
|
+
roles.register_local_role("ggbicon", ggb_icon_role)
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
"version": "0.1.0",
|
|
60
|
+
"parallel_read_safe": True,
|
|
61
|
+
"parallel_write_safe": True,
|
|
62
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GeoGebra popup directive for creating interactive GeoGebra applets in dialog windows.
|
|
3
|
+
|
|
4
|
+
This directive creates a button that opens a GeoGebra Classic applet in a
|
|
5
|
+
draggable, resizable dialog window using jQuery UI.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
Basic usage with defaults (700x500 window):
|
|
9
|
+
```{ggb-popup}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Custom size and text:
|
|
13
|
+
```{ggb-popup} 800 600 "Open Calculator" "GeoGebra Calculator"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
With options:
|
|
17
|
+
```{ggb-popup} 900 700 "Open Geometry" "Geometry Window"
|
|
18
|
+
:perspective: G
|
|
19
|
+
:menubar: true
|
|
20
|
+
:layout: sidebar
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Arguments (all optional):
|
|
24
|
+
1. Width (default: 700) - Width of the GeoGebra applet in pixels
|
|
25
|
+
2. Height (default: 500) - Height of the GeoGebra applet in pixels
|
|
26
|
+
3. Button text (default: "Åpne Geogebra‑vindu") - Text shown on the button
|
|
27
|
+
4. Dialog title (default: "Geogebra‑vindu") - Title of the dialog window
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
- perspective: GeoGebra perspective/view (default: "AG")
|
|
31
|
+
Common values: "AG" (Algebra & Graphics), "G" (Geometry), "GS" (Graphing), "CAS"
|
|
32
|
+
- menubar: Show menu bar (default: "false") - "true" or "false"
|
|
33
|
+
- layout: Layout style (default: none) - Use "sidebar" to wrap in sidebar-cas div
|
|
34
|
+
|
|
35
|
+
Features:
|
|
36
|
+
- Draggable and resizable dialog window
|
|
37
|
+
- GeoGebra Classic applet with full features
|
|
38
|
+
- Responsive sizing when dialog is resized
|
|
39
|
+
- Centered on screen when opened
|
|
40
|
+
- jQuery UI styling
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from docutils import nodes
|
|
44
|
+
from sphinx.util.docutils import SphinxDirective
|
|
45
|
+
import uuid
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class GGBPopUpDirective(SphinxDirective):
|
|
49
|
+
"""
|
|
50
|
+
Directive for creating GeoGebra popup windows.
|
|
51
|
+
|
|
52
|
+
Creates a button that opens a GeoGebra Classic applet in a jQuery UI dialog.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
required_arguments = 0
|
|
56
|
+
optional_arguments = 4 # width, height, button text, dialog title
|
|
57
|
+
final_argument_whitespace = True
|
|
58
|
+
has_content = False
|
|
59
|
+
option_spec = {
|
|
60
|
+
"layout": lambda arg: arg, # e.g., "sidebar"
|
|
61
|
+
"menubar": lambda arg: arg, # e.g., "true" or "false"
|
|
62
|
+
"perspective": lambda arg: arg, # e.g., "GS"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def run(self):
|
|
66
|
+
"""Generate HTML for the GeoGebra popup."""
|
|
67
|
+
# 1 » Parse arguments
|
|
68
|
+
width = int(self.arguments[0]) if len(self.arguments) > 0 else 700
|
|
69
|
+
height = int(self.arguments[1]) if len(self.arguments) > 1 else 500
|
|
70
|
+
|
|
71
|
+
button_text = self.arguments[2] if len(self.arguments) > 2 else "Åpne Geogebra‑vindu"
|
|
72
|
+
dialog_title = self.arguments[3] if len(self.arguments) > 3 else "Geogebra‑vindu"
|
|
73
|
+
|
|
74
|
+
menubar = self.options.get("menubar", "false")
|
|
75
|
+
|
|
76
|
+
perspective = self.options.get("perspective", "AG").strip()
|
|
77
|
+
|
|
78
|
+
# 2 » Generate unique IDs
|
|
79
|
+
cid = f"ggb-geogebra-{uuid.uuid4().hex[:8]}"
|
|
80
|
+
dialog_id = f"dialog-{cid}"
|
|
81
|
+
button_id = f"button-{cid}"
|
|
82
|
+
|
|
83
|
+
# 3 » Handle layout option
|
|
84
|
+
layout = self.options.get("layout", "").strip().lower()
|
|
85
|
+
use_sidebar = layout == "sidebar"
|
|
86
|
+
|
|
87
|
+
wrapper_start = '<div class="sidebar-cas">' if use_sidebar else ""
|
|
88
|
+
wrapper_end = "</div>" if use_sidebar else ""
|
|
89
|
+
|
|
90
|
+
# 4 » Generate HTML content
|
|
91
|
+
html = f"""
|
|
92
|
+
{wrapper_start}
|
|
93
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
94
|
+
|
|
95
|
+
<button id="{button_id}" class="ggb-cas-button">{button_text}</button>
|
|
96
|
+
<div id="{dialog_id}" title="{dialog_title}" style="display:none;">
|
|
97
|
+
<div id="{cid}" class="ggb-window"></div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<style>
|
|
101
|
+
.ui-resizable-handle {{ min-width:16px;min-height:16px; }}
|
|
102
|
+
.ui-dialog-content{{padding:0!important;}}
|
|
103
|
+
.ggb-window {{width:100%!important;height:100%!important;box-sizing:border-box;}}
|
|
104
|
+
.ggb-cas-button {{margin-top: 1em; margin-bottom: 1em;}}
|
|
105
|
+
</style>
|
|
106
|
+
|
|
107
|
+
<script>
|
|
108
|
+
(function() {{
|
|
109
|
+
$(function() {{
|
|
110
|
+
let ggbReady = false;
|
|
111
|
+
|
|
112
|
+
function applySize() {{
|
|
113
|
+
if (!ggbReady) return;
|
|
114
|
+
const w = $("#{cid}").width(),
|
|
115
|
+
h = $("#{cid}").height();
|
|
116
|
+
window.ggbApplet.setSize(Math.round(w), Math.round(h));
|
|
117
|
+
}}
|
|
118
|
+
|
|
119
|
+
$("#{dialog_id}").dialog({{
|
|
120
|
+
autoOpen: false,
|
|
121
|
+
width: {width+40}, height: {height+80},
|
|
122
|
+
resizable: true, draggable: true,
|
|
123
|
+
position: {{ my: "center", at: "center", of: window }},
|
|
124
|
+
resize: () => window.requestAnimationFrame(applySize),
|
|
125
|
+
open: function() {{
|
|
126
|
+
if (!ggbReady) {{
|
|
127
|
+
new GGBApplet({{
|
|
128
|
+
appName: "classic", id: "{cid}",
|
|
129
|
+
width: {width}, height: {height},
|
|
130
|
+
perspective: "{perspective}", language: "nb",
|
|
131
|
+
showToolBar: true, showAlgebraInput: true,
|
|
132
|
+
borderRadius: 8, enableRightClick: true, showKeyboardOnFocus: false,
|
|
133
|
+
showMenuBar: {menubar},
|
|
134
|
+
appletOnLoad: () => {{ ggbReady = true; applySize(); }}
|
|
135
|
+
}}, true).inject("{cid}");
|
|
136
|
+
}} else {{
|
|
137
|
+
applySize();
|
|
138
|
+
}}
|
|
139
|
+
}}
|
|
140
|
+
}});
|
|
141
|
+
|
|
142
|
+
$("#{button_id}").button()
|
|
143
|
+
.on("click touchend pointerup", e => {{
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
$("#{dialog_id}").dialog("open");
|
|
146
|
+
}});
|
|
147
|
+
}});
|
|
148
|
+
}})();
|
|
149
|
+
</script>
|
|
150
|
+
{wrapper_end}
|
|
151
|
+
"""
|
|
152
|
+
return [nodes.raw("", html, format="html")]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def setup(app):
|
|
156
|
+
"""Register the ggb-popup directive with Sphinx."""
|
|
157
|
+
app.add_directive("ggb-popup", GGBPopUpDirective)
|
|
158
|
+
# Also register without hyphen for MyST compatibility
|
|
159
|
+
app.add_directive("ggbpopup", GGBPopUpDirective)
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
"version": "0.1.0",
|
|
163
|
+
"parallel_read_safe": True,
|
|
164
|
+
"parallel_write_safe": True,
|
|
165
|
+
}
|