Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mathics_django/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
from mathics.settings import DATA_DIR

# Needed for Firefox security. Allow these mime types.
# When we migrate to MathJax v4, we won't need this.
mimetypes.add_type("font/woff2", ".woff2", True)
mimetypes.add_type("application/javascript", ".js", True)
mimetypes.add_type("text/javascript", ".js", True)

# Check if daphne is installed without importing
daphne_spec = importlib.util.find_spec("daphne")
Expand Down
62 changes: 42 additions & 20 deletions mathics_django/web/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@
from mathics.core.systemsymbols import (
SymbolAborted,
SymbolFailed,
SymbolInterpretationBox,
SymbolOutputForm,
SymbolStandardForm,
SymbolTeXForm,
)
from mathics.format.box import format_element

FORM_TO_FORMAT = {
# Maps a Form to a kind of rendering process
FORM_TO_RENDER = {
"System`FullForm": "text",
"System`InputForm": "text",
# "System`MathMLForm": "text",
# "System`MathMLForm": "mathml",
"System`OutputForm": "text",
# "System`TeXForm": "text",
"System`TeXForm": "tex",
"System`String": "text",
}

Expand All @@ -30,7 +33,7 @@ def safe_html_string(value):
return value # mark_safe(escape_html(value))


def format_output(evaluation, expr, format=None):
def format_output(evaluation, expr, render=None):
"""
Handle unformatted output using the *specific* capabilities \
of mathics-django.
Expand All @@ -40,15 +43,15 @@ def format_output(evaluation, expr, format=None):
specific capabilities.
"""

if format is None:
format = evaluation.format
if render is None:
render = evaluation.format

if format == "unformatted":
if render == "unformatted":
evaluation.exc_result = None
return expr

if isinstance(format, dict):
return dict((k, evaluation.format_output(expr, f)) for k, f in format.items())
if isinstance(render, dict):
return dict((k, evaluation.format_output(expr, f)) for k, f in render.items())

if expr is SymbolAborted:
return "$Aborted"
Expand All @@ -60,31 +63,50 @@ def format_output(evaluation, expr, format=None):
# MathML, we want
# plain-ol' text so we can cut and paste that.
expr_type = expr.get_head_name()
if expr_type in FORM_TO_FORMAT:
if expr_type in FORM_TO_RENDER:
# For these forms, we strip off the outer "Form" part
format = FORM_TO_FORMAT[expr_type]
render = FORM_TO_RENDER[expr_type]

# This part was derived from and the same as evaluation.py format_output.

if format == "text":
if render == "text":
boxed = format_element(expr, evaluation, SymbolOutputForm)
result = boxed.boxes_to_text()

return safe_html_string(result)
elif format == "xml":
boxes = format_element(expr, evaluation, SymbolStandardForm)
elif render == "xml":
boxed = format_element(expr, evaluation, SymbolStandardForm)
if (
hasattr(boxed, "head")
and boxed.head is SymbolInterpretationBox
and (box_value := boxed.elements[0].value).startswith('"<math ')
):
# FIXME: [1:-1] is to strip quotes.
# We should probably address a long-standing mistake where strings
# have quotes in them.
return box_value[1:-1]

# THINK ABOUT: This probably no longer happens
result = (
'<math display="block">'
f"{boxes.boxes_to_mathml(evaluation=evaluation)}"
f"{boxed.to_mathml(evaluation=evaluation)}"
"</math>"
)
return safe_html_string(result)
elif format == "tex":
boxes = format_element(expr, evaluation, SymbolStandardForm)
if isinstance(boxes, String):
result = boxes.boxes_to_text()
elif render == "tex":
boxed = format_element(expr, evaluation, SymbolTeXForm)
if hasattr(boxed, "head") and boxed.head is SymbolInterpretationBox:
# FIXME: [1:-1] is to strip quotes.
# We should probably address a long-standing mistake where strings
# have quotes in them.
box_str_sans_quotes = boxed.elements[0].value[1:-1]
return f"$${box_str_sans_quotes}$$"

# THINK ABOUT: This probably no longer happens
if isinstance(boxed, String):
result = boxed.to_text()
else:
result = boxes.boxes_to_tex(evaluation=evaluation)
result = boxed.to_tex(evaluation=evaluation)
return safe_html_string(result)

raise ValueError
57 changes: 34 additions & 23 deletions mathics_django/web/media/js/mathics.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function getLetterWidth(element) {

document.body.appendChild(letter);

const width = letter.getWidth();
const width = letter.getBoundingClientRect().width;

document.body.removeChild(letter);

Expand Down Expand Up @@ -52,7 +52,7 @@ function inputChange() {
}

function isEmpty(textarea) {
return textarea.value.strip() == '' && !textarea.submitted;
return textarea.value.trim() == '' && !textarea.submitted;
}

function prepareText(text) {
Expand Down Expand Up @@ -88,7 +88,7 @@ function getDimensions(math, callback) {
}

function createMathNode(nodeName) {
if (['svg', 'g', 'rect', 'circle', 'polyline', 'polygon', 'path', 'ellipse', 'foreignObject'].include(nodeName)) {
if (['svg', 'g', 'rect', 'circle', 'polyline', 'polygon', 'path', 'ellipse', 'foreignObject'].includes(nodeName)) {
return document.createElementNS("http://www.w3.org/2000/svg", nodeName);
}

Expand Down Expand Up @@ -319,8 +319,9 @@ function afterProcessResult(list, command) {
list.querySelectorAll('.mspace').forEach((mspace) => {
if (mspace) {
const id = mspace.getAttribute('id').substr(objectsPrefix.length);

mspace.appendChild(objects[id]);
if (objects[id]) {
mspace.appendChild(objects[id]);
}
}
});
});
Expand All @@ -341,22 +342,24 @@ function afterProcessResult(list, command) {

if (command === 'Typeset') {
// recalculate positions of insets based on ox/oy properties
const foreignObject = math.parentNode.parentNode.parentNode,
dimensions = math.getDimensions();
const foreignObject = math.parentNode.parentNode.parentNode;
if (foreignObject && math.getDimensions) {
const dimensions = math.getDimensions();

const ox = parseFloat(foreignObject.getAttribute('ox')),
oy = parseFloat(foreignObject.getAttribute('oy')),
width = dimensions.width + 4,
height = dimensions.height + 4;
const ox = parseFloat(foreignObject.getAttribute('ox')) || 0,
oy = parseFloat(foreignObject.getAttribute('oy')) || 0,
width = dimensions.width + 4,
height = dimensions.height + 4;

let x = parseFloat(foreignObject.getAttribute('x').substr()),
y = parseFloat(foreignObject.getAttribute('y'));
let x = parseFloat(foreignObject.getAttribute('x')) || 0,
y = parseFloat(foreignObject.getAttribute('y')) || 0;

x = x - width / 2.0 - ox * width / 2.0;
y = y - height / 2.0 + oy * height / 2.0;
x = x - width / 2.0 - ox * width / 2.0;
y = y - height / 2.0 + oy * height / 2.0;

foreignObject.setAttribute('x', x + 'px');
foreignObject.setAttribute('y', y + 'px');
foreignObject.setAttribute('x', x + 'px');
foreignObject.setAttribute('y', y + 'px');
}
}
});
});
Expand Down Expand Up @@ -479,7 +482,12 @@ function submitQuery(element, onfinish, query) {
}

if (welcome) {
document.getElementById('welcomeContainer')?.fade({ duration: 0.2 });
const welcomeContainer = document.getElementById('welcomeContainer');
if (welcomeContainer) {
welcomeContainer.style.transition = 'opacity 0.2s ease-out';
welcomeContainer.style.opacity = '0';
welcomeContainer.style.pointerEvents = 'none';
}

if (document.getElementById('hideStartupMsg')?.checked) {
localStorage.setItem('hideMathicsStartupMsg', 'true');
Expand Down Expand Up @@ -561,7 +569,7 @@ function keyDown(event) {
if (event.key === 'Enter' && (event.shiftKey || event.location === 3)) {
event.stop();

if (textArea.value.strip()) {
if (textArea.value.trim()) {
submitQuery(textArea);
}
} else if (event.key === 'ArrowUp') {
Expand Down Expand Up @@ -617,7 +625,7 @@ function deleteClick() {

function moveMouseDown() {
movedItem = this.li;
movedItem.addClassName('moving');
movedItem.classList.add('moving');
}

function moveMouseUp() {
Expand Down Expand Up @@ -730,7 +738,7 @@ function createQuery(beforeElement, noFocus, updatingAll) {
moveHandle.addEventListener('mousedown', moveMouseDown);
document.addEventListener('mouseup', moveMouseUp);
submitButton.addEventListener('mousedown', () => {
if (textarea.value.strip()) {
if (textarea.value.trim()) {
submitQuery(textarea);
} else {
textarea.focus();
Expand Down Expand Up @@ -876,7 +884,10 @@ function domLoaded() {
MathJax.Hub.Configured();

if (localStorage.getItem('hideMathicsStartupMsg') === 'true') {
document.getElementById('welcome').style.display = 'none';
const welcome = document.getElementById('welcome');
if (welcome) {
welcome.style.display = 'none';
}
}

const queriesContainer = document.getElementById('queriesContainer');
Expand Down Expand Up @@ -913,7 +924,7 @@ window.addEventListener('resize', function () {

timeout = window.setTimeout(function () {
document.querySelectorAll('#queries ul').forEach((ul) => {
afterProcessResult(ul, 'Rerender');
afterProcessResult(ul);
});

timeout = -1; // reset the timeout
Expand Down
3 changes: 2 additions & 1 deletion mathics_django/web/templates/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ <h1>Connection Information</h1>

<p>Copyright (C) 2021-2026 The Mathics<i>3</i> Team<p><br>

This program comes with ABSOLUTELY NO WARRANTY;
<p>
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under <a href="doc/license/gnu-general-public-license/">certain conditions</a>.
</p>
Expand Down
1 change: 1 addition & 0 deletions mathics_django/web/templates/welcome.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<p>Copyright (C) 2021-2026 The Mathics<i>3</i> Team</p><br>

<p>
This program comes with ABSOLUTELY NO WARRANTY;
This is free software, and you are welcome to redistribute it
under <a href="doc/license/gnu-general-public-license/">certain conditions</a>.
Expand Down