/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Insert MathML dialog */ /* import-globals-from ../editorUtilities.js */ /* import-globals-from EdDialogCommon.js */ document.addEventListener("dialogaccept", onAccept); document.addEventListener("dialogcancel", onCancel); function Startup() { var editor = GetCurrentEditor(); if (!editor) { window.close(); return; } // Create dialog object for easy access gDialog.accept = document.querySelector("dialog").getButton("accept"); gDialog.mode = document.getElementById("optionMode"); gDialog.direction = document.getElementById("optionDirection"); gDialog.input = document.getElementById("input"); gDialog.output = document.getElementById("output"); gDialog.tabbox = document.getElementById("tabboxInsertLaTeXCommand"); // Set initial focus gDialog.input.focus(); // Load TeXZilla // TeXZilla.js contains non-ASCII characters and explicitly sets // window.TeXZilla, so we have to specify the charset parameter but don't // need to worry about the targetObj parameter. /* globals TeXZilla */ Services.scriptloader.loadSubScript( "chrome://messenger/content/messengercompose/TeXZilla.js", {}, "UTF-8" ); // Verify if the selection is on a and initialize the dialog. gDialog.oldMath = editor.getElementOrParentByTagName("math", null); if (gDialog.oldMath) { // When these attributes are absent or invalid, they default to "inline" and "ltr" respectively. gDialog.mode.selectedIndex = gDialog.oldMath.getAttribute("display") == "block" ? 1 : 0; gDialog.direction.selectedIndex = gDialog.oldMath.getAttribute("dir") == "rtl" ? 1 : 0; gDialog.input.value = TeXZilla.getTeXSource(gDialog.oldMath); } // Create the tabbox with LaTeX commands. createCommandPanel({ "√⅗²": [ "{⋯}^{⋯}", "{⋯}_{⋯}", "{⋯}_{⋯}^{⋯}", "\\underset{⋯}{⋯}", "\\overset{⋯}{⋯}", "\\underoverset{⋯}{⋯}{⋯}", "\\left(⋯\\right)", "\\left[⋯\\right]", "\\frac{⋯}{⋯}", "\\binom{⋯}{⋯}", "\\sqrt{⋯}", "\\sqrt[⋯]{⋯}", "\\cos\\left({⋯}\\right)", "\\sin\\left({⋯}\\right)", "\\tan\\left({⋯}\\right)", "\\exp\\left({⋯}\\right)", "\\ln\\left({⋯}\\right)", "\\underbrace{⋯}", "\\underline{⋯}", "\\overbrace{⋯}", "\\widevec{⋯}", "\\widetilde{⋯}", "\\widehat{⋯}", "\\widecheck{⋯}", "\\widebar{⋯}", "\\dot{⋯}", "\\ddot{⋯}", "\\boxed{⋯}", "\\slash{⋯}", ], "(▦)": [ "\\begin{matrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{matrix}", "\\begin{pmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{pmatrix}", "\\begin{bmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{bmatrix}", "\\begin{Bmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{Bmatrix}", "\\begin{vmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{vmatrix}", "\\begin{Vmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{Vmatrix}", "\\begin{cases} ⋯ \\\\ ⋯ \\end{cases}", "\\begin{aligned} ⋯ &= ⋯ \\\\ ⋯ &= ⋯ \\end{aligned}", ], }); createSymbolPanels([ "∏∐∑∫∬∭⨌∮⊎⊕⊖⊗⊘⊙⋀⋁⋂⋃⌈⌉⌊⌋⎰⎱⟨⟩⟪⟫∥⫼⨀⨁⨂⨄⨅⨆ðıȷℏℑℓ℘ℜℵℶ", "∀∃∄∅∉∊∋∌⊂⊃⊄⊅⊆⊇⊈⊈⊉⊊⊊⊋⊋⊏⊐⊑⊒⊓⊔⊥⋐⋑⋔⫅⫆⫋⫋⫌⫌…⋮⋯⋰⋱♭♮♯∂∇", "±×÷†‡•∓∔∗∘∝∠∡∢∧∨∴∵∼∽≁≃≅≇≈≈≊≍≎≏≐≑≒≓≖≗≜≡≢≬⊚⊛⊞⊡⊢⊣⊤⊥", "⊨⊩⊪⊫⊬⊭⊯⊲⊲⊳⊴⊵⊸⊻⋄⋅⋇⋈⋉⋊⋋⋌⋍⋎⋏⋒⋓⌅⌆⌣△▴▵▸▹▽▾▿◂◃◊○★♠♡♢♣⧫", "≦≧≨≩≩≪≫≮≯≰≱≲≳≶≷≺≻≼≽≾≿⊀⊁⋖⋗⋘⋙⋚⋛⋞⋟⋦⋧⋨⋩⩽⩾⪅⪆⪇⪈⪉⪊⪋⪌⪕⪯⪰⪷⪸⪹⪺", "←↑→↓↔↕↖↗↘↙↜↝↞↠↢↣↦↩↪↫↬↭↭↰↱↼↽↾↿⇀⇁⇂⇃⇄⇆⇇⇈⇉⇊⇋⇌⇐⇑⇒⇓⇕⇖⇗⇘⇙⟺", "αβγδϵ϶εζηθϑικϰλμνξℴπϖρϱσςτυϕφχψωΓΔΘΛΞΠΣϒΦΨΩϝ℧", "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ", "𝒶𝒷𝒸𝒹ℯ𝒻ℊ𝒽𝒾𝒿𝓀𝓁𝓂𝓃ℴ𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏𝒜ℬ𝒞𝒟ℰℱ𝒢ℋℐ𝒥𝒦ℒℳ𝒩𝒪𝒫𝒬ℛ𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵", "𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ", ]); gDialog.tabbox.selectedIndex = 0; updateMath(); SetWindowLocation(); } function insertLaTeXCommand(aButton) { gDialog.input.focus(); // For a single math symbol, just use the insertText command. if (aButton.label) { gDialog.input.editor.insertText(aButton.label); return; } // Otherwise, it's a LaTeX command with at least one argument... var latex = TeXZilla.getTeXSource(aButton.firstElementChild); var selectionStart = gDialog.input.selectionStart; var selectionEnd = gDialog.input.selectionEnd; // If the selection is not empty, we replace the first argument of the LaTeX // command with the current selection. var selection = gDialog.input.value.substring(selectionStart, selectionEnd); if (selection != "") { latex = latex.replace("⋯", selection); } // Try and move to the next position. var latexNewStart = latex.indexOf("⋯"), latexNewEnd; if (latexNewStart == -1) { // This is a unary function and the selection was used as an argument above. // We select the expression again so that one can choose to apply further // command to it or just move the caret after that text. latexNewStart = 0; latexNewEnd = latex.length; } else { // Otherwise, select the dots representing the next argument. latexNewEnd = latexNewStart + 1; } // Update the input text and selection. gDialog.input.editor.insertText(latex); gDialog.input.setSelectionRange( selectionStart + latexNewStart, selectionStart + latexNewEnd ); updateMath(); } function createCommandPanel(aCommandPanelList) { const columnCount = 10; for (var label in aCommandPanelList) { var commands = aCommandPanelList[label]; // Create the element with the . var table = document.createElementNS( "http://www.w3.org/1999/xhtml", "table" ); var i = 0, row; for (var command of commands) { if (i % columnCount == 0) { // Create a new row. row = document.createElementNS("http://www.w3.org/1999/xhtml", "tr"); table.appendChild(row); } // Create a new button to insert the symbol. var button = document.createXULElement("toolbarbutton"); var td = document.createElementNS("http://www.w3.org/1999/xhtml", "td"); button.setAttribute("class", "tabbable"); button.appendChild(TeXZilla.toMathML(command)); td.append(button); row.appendChild(td); i++; } // Create a new element. var tab = document.createXULElement("tab"); tab.setAttribute("label", label); gDialog.tabbox.tabs.appendChild(tab); // Append the new tab panel. gDialog.tabbox.tabpanels.appendChild(table); } } function createSymbolPanels(aSymbolPanelList) { const columnCount = 13, tabLabelLength = 3; for (var symbols of aSymbolPanelList) { // Create the
element with the . var table = document.createElementNS( "http://www.w3.org/1999/xhtml", "table" ); var i = 0, tabLabel = "", row; for (var symbol of symbols) { if (i % columnCount == 0) { // Create a new row. row = document.createElementNS("http://www.w3.org/1999/xhtml", "tr"); table.appendChild(row); } // Build the tab label from the first symbols of this tab. if (i < tabLabelLength) { tabLabel += symbol; } // Create a new button to insert the symbol. var button = document.createXULElement("toolbarbutton"); var td = document.createElementNS("http://www.w3.org/1999/xhtml", "td"); button.setAttribute("label", symbol); button.setAttribute("class", "tabbable"); td.append(button); row.appendChild(td); i++; } // Create a new element with the label determined above. var tab = document.createXULElement("tab"); tab.setAttribute("label", tabLabel); gDialog.tabbox.tabs.appendChild(tab); // Append the new tab panel. gDialog.tabbox.tabpanels.appendChild(table); } } function onAccept(event) { if (gDialog.output.firstElementChild) { var editor = GetCurrentEditor(); editor.beginTransaction(); try { var newMath = editor.document.importNode( gDialog.output.firstElementChild, true ); if (gDialog.oldMath) { // Replace the old element with the new one. editor.selectElement(gDialog.oldMath); editor.insertElementAtSelection(newMath, true); } else { // Insert the new element. editor.insertElementAtSelection(newMath, false); } } catch (e) {} editor.endTransaction(); } else { dump("Null value -- not inserting in MathML Source dialog\n"); event.preventDefault(); } SaveWindowLocation(); } function updateMath() { // Remove the preview, if any. if (gDialog.output.firstElementChild) { gDialog.output.firstElementChild.remove(); } // Try to convert the LaTeX source into MathML using TeXZilla. // We use the placeholder text if no input is provided. try { var input = gDialog.input.value || gDialog.input.placeholder; var newMath = TeXZilla.toMathML( input, gDialog.mode.selectedIndex, gDialog.direction.selectedIndex, true ); gDialog.output.appendChild(document.importNode(newMath, true)); gDialog.output.style.opacity = gDialog.input.value ? 1 : 0.5; } catch (e) {} // Disable the accept button if parsing fails or when the placeholder is used. gDialog.accept.disabled = !gDialog.input.value || !gDialog.output.firstElementChild; } function updateMode() { if (gDialog.output.firstElementChild) { gDialog.output.firstElementChild.setAttribute( "display", gDialog.mode.selectedIndex ? "block" : "inline" ); } } function updateDirection() { if (gDialog.output.firstElementChild) { gDialog.output.firstElementChild.setAttribute( "dir", gDialog.direction.selectedIndex ? "rtl" : "ltr" ); } }