Closed Bug 1077291 Opened 10 years ago Closed 10 years ago

Add some UI to easily insert mathematical symbols into the LaTeX input box

Categories

(SeaMonkey :: Composer, defect)

defect
Not set
normal

Tracking

(seamonkey2.34 fixed)

RESOLVED FIXED
seamonkey2.34
Tracking Status
seamonkey2.34 --- fixed

People

(Reporter: fredw, Assigned: fredw)

References

Details

Attachments

(1 file, 6 obsolete files)

One of the difficulty for people to enter math expressions is to remember all the LaTeX commands to insert mathematical symbols. Since TeXZilla supports Unicode input, we could just organize all or part of the following math Unicode characters

https://github.com/fred-wang/TeXZilla/wiki/TeXZilla-Commands#identifiers
https://github.com/fred-wang/TeXZilla/wiki/TeXZilla-Commands#operators

into some categories ; and create the corresponding buttons to insert them.
Summary: Add some UI to easily insert mathematical symbols in the LaTeX input box → Add some UI to easily insert mathematical symbols into the LaTeX input box
Attached patch Patch V1 (obsolete) — Splinter Review
OK, I just wrote a very basic patch as a proof-of-concept.

This does not handle surrogate pairs and does not implement a way to switch between several categories.
Attached image screenshot_insertMath.png (obsolete) —
Attached patch Patch V2 (obsolete) — Splinter Review
This organizes symbols with tabpanels and handles surrogate pairs.

However for some reason I can not click on a button with the mouse and I have to use the keyboard instead. (example https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/tabbox#Examples works, though).
Attachment #8499401 - Attachment is obsolete: true
Attachment #8507499 - Flags: feedback?(neil)
Comment on attachment 8507499 [details] [diff] [review]
Patch V2

>+  var selectionStart = gDialog.input.selectionStart;
>+  gDialog.input.value =
>+    gDialog.input.value.substring(0, selectionStart) + aChar +
>+    gDialog.input.value.substring(gDialog.input.selectionEnd);
>+  gDialog.input.selectionStart = selectionStart + aChar.length;
>+  gDialog.input.selectionEnd = gDialog.input.selectionStart;
I think you can use
gDialog.input.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor).insertText(aChar);

>+  gDialog.input.focus();
>+  updateMath();
[Possibly if you focus the input first it will also trigger the input handler for you.]

>+  for (var i = 0; i < aSymbolPanelList.length; i++) {
>+
>+    // Create a <rows> element with the symbols of the i-th panel.
>+    var symbols = aSymbolPanelList[i];
If you don't use i again you can write for (var symbols of aSymbolPanelList)

>+    var rows = document.createElementNS(XULNS, "rows");
Don't need this because you create it again immediately anyway.

>+    var row, j, k, columnCount = 13;
>+    var tabLabel = "", tabLabelLength = 3;
Two of these should be const.

>+    for (j = 0, k = 0; j < symbols.length; j++, k++) {
I think you can use for (var symbol of symbols) which also handles surrogates. (You'd still have to count the columns yourself though.)

>+      button.setAttribute("class", "checkbox-spacer");
This isn't what this class is designed for sorry. Maybe what you really need is <toolbarbutton class="tabbable">.

>+      button.setAttribute("oncommand", "insertSymbol('" + symbol + "')");
One event listener to rule them all: <tabpanels oncommand="insertSymbol(event.target.label);"/>

>+      columns.appendChild(document.createElementNS(XULNS, "column"));
Add flex="1" to all the columns so that the buttons will space out evenly on each tab. (Needs "tabpanel" fix below.)

>+    // Create the <grid> element with the <rows> and <columns> children.
>+    var grid = document.createElementNS(XULNS, "grid");
>+    grid.appendChild(rows);
>+    grid.appendChild(columns);
Appending the columns last puts them above the rows in the z-order. Put the rows last to fix this and make the buttons clickable.

>+    // Create a new <tab> element with the label determined above.
>+    var tab = document.createElementNS(XULNS, "tab");
>+    tab.setAttribute("label", tabLabel);
>+    tabbox.tabs.appendChild(tab);
(This messes up the tabbox's idea of the initially selected tab.)

>+    // Create a new <tabpanel> containing the <grid>.
>+    var tabpanel = document.createElementNS(XULNS, "tabpanel");
>+    tabpanel.appendChild(grid);
>+    tabbox.tabpanels.appendChild(tabpanel);
No such thing as a tabpanel. Just append the grid directly.
Attachment #8507499 - Flags: feedback?(neil)
Attached patch Patch V3 (obsolete) — Splinter Review
> >+    var rows = document.createElementNS(XULNS, "rows");
> Don't need this because you create it again immediately anyway.

I didn't understand that one.

> (This messes up the tabbox's idea of the initially selected tab.)

I removed the attribute. Not sure how to force the tab to be selected. But anyway that does not change the panel initially displayed.
Attachment #8499403 - Attachment is obsolete: true
Attachment #8507499 - Attachment is obsolete: true
Attachment #8509042 - Flags: feedback?
Attachment #8509042 - Attachment description: texzilla-unicode-input.patch → Patch V3
Attachment #8509042 - Flags: feedback? → feedback?(neil)
Comment on attachment 8509042 [details] [diff] [review]
Patch V3

>+    for (var symbol of symbols) {
>+      var row;
Nit: declaring row looks odd here, since you retain its value between loop iterations. Might be more readable to declare it just before instead.

>+    // Create a <columns> element with the desired number of columns.
>+    var columns = document.createElementNS(XULNS, "columns");
>+    for (i = 0; i < columnCount; i++) {
>+      var column = document.createElementNS(XULNS, "column");
>+      column.setAttribute("flex", "1");
This almost does what I want but the various symbols are slightly different widths so that the columns don't quite distribute evenly. I'd appreciate it if you could fix this by setting the width to 1 too. (The flex then calculates the column width by flexing this width rather than the actual character widths.)

>+    // Append the new tab panel.
>+    tabbox.tabpanels.appendChild(grid);
>+  }
It would be helpful if you set the tabbox's selectedIndex to 0 when you finished, so that the tab looks selected.

>+    <tabpanels oncommand="insertSymbol(event.target.label)"/>
Nit: event handlers are JS statements so should end with a semicolon.

The only other problem I have with this is that there is nothing to label the tabbox. This might not be a problem if you move it above the options. The example also looks a bit lost there, I don't know whether it would be possible to make it placeholder text instead.
Attachment #8509042 - Flags: feedback?(neil) → feedback+
Attached patch Patch V4 (obsolete) — Splinter Review
Attachment #8509042 - Attachment is obsolete: true
(In reply to neil@parkwaycc.co.uk from comment #6)
> >+    // Create a <columns> element with the desired number of columns.
> >+    var columns = document.createElementNS(XULNS, "columns");
> >+    for (i = 0; i < columnCount; i++) {
> >+      var column = document.createElementNS(XULNS, "column");
> >+      column.setAttribute("flex", "1");
> This almost does what I want but the various symbols are slightly different
> widths so that the columns don't quite distribute evenly. I'd appreciate it
> if you could fix this by setting the width to 1 too. (The flex then
> calculates the column width by flexing this width rather than the actual
> character widths.)

The problem with this is that the label of the largest buttons become "...", unless we increase the window width.

> 
> >+    // Append the new tab panel.
> >+    tabbox.tabpanels.appendChild(grid);
> >+  }
> It would be helpful if you set the tabbox's selectedIndex to 0 when you
> finished, so that the tab looks selected.

OK, for some reason tabbox.setAttribute("selectedIndex", "0") does not work but tabbox.selectedIndex = 0; does.

> The only other problem I have with this is that there is nothing to label
> the tabbox. This might not be a problem if you move it above the options.
> The example also looks a bit lost there, I don't know whether it would be
> possible to make it placeholder text instead.

I tried to do something. Let me know if that looks better.
Flags: needinfo?(neil)
(In reply to Frédéric Wang from comment #8)
> (In reply to comment #6)
> > >+    // Create a <columns> element with the desired number of columns.
> > >+    var columns = document.createElementNS(XULNS, "columns");
> > >+    for (i = 0; i < columnCount; i++) {
> > >+      var column = document.createElementNS(XULNS, "column");
> > >+      column.setAttribute("flex", "1");
> > This almost does what I want but the various symbols are slightly different
> > widths so that the columns don't quite distribute evenly. I'd appreciate it
> > if you could fix this by setting the width to 1 too. (The flex then
> > calculates the column width by flexing this width rather than the actual
> > character widths.)
> 
> The problem with this is that the label of the largest buttons become "...",
> unless we increase the window width.

Ah, must depend on your OS's fonts I guess. Thanks for trying.

> for some reason tabbox.setAttribute("selectedIndex", "0") does not work
> but tabbox.selectedIndex = 0; does.
Yes, it sets up some other attributes to make everything look right.

> > The only other problem I have with this is that there is nothing to label
> > the tabbox. This might not be a problem if you move it above the options.
> > The example also looks a bit lost there, I don't know whether it would be
> > possible to make it placeholder text instead.
> 
> I tried to do something. Let me know if that looks better.
Cool! Just one code nit:
>+    var input = gDialog.input.value;
>+    if (!input) {
>+      input = gDialog.input.placeholder;
var input = gDialog.input.value || gDialog.input.placeholder;
Flags: needinfo?(neil)
(In reply to neil@parkwaycc.co.uk from comment #9)
> Cool! Just one code nit:
> >+    var input = gDialog.input.value;
> >+    if (!input) {
> >+      input = gDialog.input.placeholder;
> var input = gDialog.input.value || gDialog.input.placeholder;

argh! I initially did that but I thought you won't be happy to use boolean operators for strings. I'll put that back.
Attached patch Patch V5 (obsolete) — Splinter Review
Attachment #8510861 - Attachment is obsolete: true
Attachment #8511259 - Flags: review?(neil)
Comment on attachment 8511259 [details] [diff] [review]
Patch V5

Sorry for the delay.
Attachment #8511259 - Flags: review?(neil) → review+
Just adding r=neil to the commit message.
Attachment #8511259 - Attachment is obsolete: true
Keywords: checkin-needed
Blocks: 1098150
Can someone please commit this patch?
Flags: needinfo?(philip.chee)
(In reply to Frédéric Wang (:fredw) from comment #14)
> Can someone please commit this patch?
The tree is closed due to multiple bustages. I'll check it in once the Thunderbird tree re-opens.
Pushed to comm-central:
http://hg.mozilla.org/comm-central/rev/d04571dd1bf4
Status: NEW → RESOLVED
Closed: 10 years ago
Keywords: checkin-needed
Resolution: --- → FIXED
Target Milestone: --- → seamonkey2.34
Flags: needinfo?(philip.chee)
Thanks Philip!
Blocks: 1113572
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: