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
62 changes: 62 additions & 0 deletions src/commands/math/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,68 @@ LatexCmds.superscript =
}
};

// Ion notation: a superscript-only command carrying an editable charge
// block followed by a fixed sign — `\ion[+]{2}` renders as the "2+" of a
// 2+ cation. `\positiveion` / `\negativeion` are sign-bound shorthands.
// Restored for @openwebwork/mathquill; the chemistry answer-entry toolbars
// (chemQuillChemistry.pl) drive these commands.
class Ion extends SupSub {
sign: '+' | '-';

constructor(sign?: string) {
super();
this.sign = sign === '-' ? '-' : '+';
this.supsub = 'sup';
this.htmlTemplate =
'<span class="mq-supsub mq-non-leaf mq-sup-only">' +
'<span class="mq-sup">' +
'<span>&0</span>' +
`<span class="mq-ion">${this.sign}</span>` +
'</span></span>';
}

latex() {
return `\\ion[${this.sign}]{${this.sup?.latex() || '1'}}`;
}

text() {
return `^(${this.sign}${this.sup?.text() || '1'})`;
}

parser() {
return latexMathParser.optBlock
.then((optBlock: MathBlock) => {
return latexMathParser.block.map((block: MathBlock) => {
const ion = new Ion(optBlock.text() === '-' ? '-' : '+');
ion.blocks = [block];
block.adopt(ion);
return ion;
});
})
.or(super.parser());
}

finalizeTree() {
this.upInto = this.sup = this.ends.right;
if (this.sup) this.sup.downOutOf = insLeftOfMeUnlessAtEnd;
super.finalizeTree();
}
}

LatexCmds.ion = Ion;

LatexCmds.positiveion = class extends Ion {
constructor() {
super('+');
}
};

LatexCmds.negativeion = class extends Ion {
constructor() {
super('-');
}
};

class SummationNotation extends UpperLowerLimitCommand {
constructor(ch: string, html: string, ariaLabel?: string) {
super(
Expand Down
14 changes: 14 additions & 0 deletions test/latex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ suite('latex', function () {
assertParsesLatex('x ^2', 'x^2');
});

test('ion charges', function () {
// \ion[sign]{charge} — superscript-only with a fixed sign after the block.
assertParsesLatex('\\ion[+]{2}');
assertParsesLatex('\\ion[-]{3}');
// Missing optional sign defaults to '+'.
assertParsesLatex('\\ion{2}', '\\ion[+]{2}');
// Empty charge block defaults to 1 (e.g. Na+).
assertParsesLatex('\\ion[+]{}', '\\ion[+]{1}');
// \positiveion / \negativeion are sign-bound shorthands; both
// canonicalize to \ion[sign]{...}.
assertParsesLatex('\\positiveion{2}', '\\ion[+]{2}');
assertParsesLatex('\\negativeion{3}', '\\ion[-]{3}');
});

test('inner groups', function () {
assertParsesLatex('a{bc}d', 'abcd');
assertParsesLatex('{bc}d', 'bcd');
Expand Down
Loading