Google Closure Library Editor with Equation Editor Dialog


Recently I have an application which needs a HTML editor with LaTex equation support. There are many WYSIWYG (WhatYou See Is What You Get) editors available on Internet, and finally I decide to use Google Closure Library built-in rich text editor (see [1]).

The default closure works perfectly, and there are also demos of equation editor dialog. But there are two problem:

  1. It is not trivial to embed the equation editor dialog into default rich text editor, and lack of documentation on this part. (actually it's trivial to embed assumed that you are familiar with the code structure of closure library, but I am not in the beginning.)
  2. The preview feature of math equation in equation editor dialog is broken. We have to find some way to fix this.

To fix the issue #1, I read some material online (References [2] ~ [7]) and trace the online source code and api. To fix the issue #2, I read the references [9] ~ [11], and I decide to use the solution provided by [11]. The following is my patch for the closure library (under closure/goog/, revision 2021):

patch.diff | repository | view raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Index: ui/equation/imagerenderer.js
===================================================================
--- ui/equation/imagerenderer.js (revision 2021)
+++ ui/equation/imagerenderer.js (working copy)
@@ -104,7 +104,7 @@
   if (!equation) {
     return '';
   }
-
+/*
   var url = goog.ui.equation.ImageRenderer.SERVER_NAME_ +
       '/chart?cht=tx' +
       '&chf=bg,s,' +
@@ -113,6 +113,10 @@
       goog.ui.equation.ImageRenderer.FOREGROUND_COLOR +
       '&chl=' +
       encodeURIComponent(equation);
+*/
+  var url = 'http://latex.codecogs.com/gif.latex?' +
+      encodeURIComponent(equation);
+
   return url;
 };
 
@@ -123,7 +127,8 @@
  * @return {string?} The equation string, null if imageUrl cannot be parsed.
  */
 goog.ui.equation.ImageRenderer.getEquationFromImageUrl = function(imageUrl) {
-  return goog.uri.utils.getParamValue(imageUrl, 'chl');
+//  return goog.uri.utils.getParamValue(imageUrl, 'chl');
+  return decodeURIComponent(goog.uri.utils.getQueryData(imageUrl));
 };
 
 
Index: ui/editor/defaulttoolbar.js
===================================================================
--- ui/editor/defaulttoolbar.js (revision 2021)
+++ ui/editor/defaulttoolbar.js (working copy)
@@ -797,6 +797,10 @@
 goog.ui.editor.DefaultToolbar.MSG_IMAGE_TITLE = goog.getMsg('Insert image');
 
 
+/** @desc Insert image button tooltip. */
+goog.ui.editor.DefaultToolbar.MSG_EQUATION_TITLE = goog.getMsg('Insert equation');
+
+
 /** @desc Strike through button tooltip. */
 goog.ui.editor.DefaultToolbar.MSG_STRIKE_THROUGH_TITLE =
     goog.getMsg('Strikethrough');
@@ -1000,6 +1004,11 @@
   classes: goog.getCssName('tr-icon') + ' ' + goog.getCssName('tr-image'),
   factory: goog.ui.editor.ToolbarFactory.makeButton
 }, {
+  command: goog.editor.Command.EQUATION,
+  tooltip: goog.ui.editor.DefaultToolbar.MSG_EQUATION_TITLE,
+  classes: goog.getCssName('tr-icon') + ' ' + goog.getCssName('tr-equation'),
+  factory: goog.ui.editor.ToolbarFactory.makeButton
+}, {
   command: goog.editor.Command.STRIKE_THROUGH,
   tooltip: goog.ui.editor.DefaultToolbar.MSG_STRIKE_THROUGH_TITLE,
   classes: goog.getCssName('tr-icon') + ' ' +
Index: demos/editor/editor.html
===================================================================
--- demos/editor/editor.html (revision 2021)
+++ demos/editor/editor.html (working copy)
@@ -27,6 +27,8 @@
     goog.require('goog.editor.plugins.UndoRedo');
     goog.require('goog.ui.editor.DefaultToolbar');
     goog.require('goog.ui.editor.ToolbarController');
+    goog.require('goog.editor.plugins.EquationEditorPlugin');
+    goog.require('goog.editor.plugins.equation.EquationBubble');
   </script>
 
   <link rel="stylesheet" href="../css/demo.css">
@@ -49,6 +51,8 @@
   <link rel="stylesheet" href="../../css/editor/linkdialog.css" />
   <link rel="stylesheet" href="../../css/editortoolbar.css" />
 
+  <link rel="stylesheet" href="../../css/dialog.css" />
+  <link rel="stylesheet" href="../../css/editor/equationeditor.css" />
   <style>
     #editMe {
       width: 600px;
@@ -96,6 +100,10 @@
   myField.registerPlugin(
       new goog.editor.plugins.LinkDialogPlugin());
   myField.registerPlugin(new goog.editor.plugins.LinkBubble());
+  myField.registerPlugin(
+      new goog.editor.plugins.EquationEditorPlugin());
+  myField.registerPlugin(
+      new goog.editor.plugins.equation.EquationBubble());
 
   // Specify the buttons to add to the toolbar, using built in default buttons.
   var buttons = [
@@ -116,6 +124,7 @@
     goog.editor.Command.JUSTIFY_LEFT,
     goog.editor.Command.JUSTIFY_CENTER,
     goog.editor.Command.JUSTIFY_RIGHT,
+    goog.editor.Command.EQUATION,
     goog.editor.Command.SUBSCRIPT,
     goog.editor.Command.SUPERSCRIPT,
     goog.editor.Command.STRIKE_THROUGH,
Index: editor/plugins/equationeditorbubble.js
===================================================================
--- editor/plugins/equationeditorbubble.js (revision 2021)
+++ editor/plugins/equationeditorbubble.js (working copy)
@@ -94,14 +94,15 @@
     function(bubbleContainer) {
   goog.dom.appendChild(bubbleContainer,
       bubbleContainer.ownerDocument.createTextNode(
-      MSG_EE_BUBBLE_EQUATION + goog.string.Unicode.NBSP));
+      MSG_EE_BUBBLE_EQUATION + ' $' +
+      (this.getTargetElement().getAttribute('alt') || '') +
+      '$ ' + goog.string.Unicode.NBSP));
 
   this.createLink(goog.editor.plugins.equation.EquationBubble.EDIT_ID_,
       MSG_EE_BUBBLE_EDIT, this.editEquation_, bubbleContainer);
 
   goog.dom.appendChild(bubbleContainer,
       bubbleContainer.ownerDocument.createTextNode(
-      MSG_EE_BUBBLE_EQUATION +
       goog.editor.plugins.AbstractBubblePlugin.DASH_NBSP_STRING));
 
   this.createLink(goog.editor.plugins.equation.EquationBubble.REMOVE_ID_,
Index: editor/plugins/equationeditorplugin.js
===================================================================
--- editor/plugins/equationeditorplugin.js (revision 2021)
+++ editor/plugins/equationeditorplugin.js (working copy)
@@ -137,11 +137,13 @@
 goog.editor.plugins.EquationEditorPlugin.prototype.enable =
     function(fieldObject) {
   goog.base(this, 'enable', fieldObject);
+/*
   if (this.isEnabled(fieldObject)) {
     this.dblClickKey_ = goog.events.listen(fieldObject.getElement(),
         goog.events.EventType.DBLCLICK,
         goog.bind(this.handleDoubleClick_, this), false, this);
   }
+*/
 };
 
 
@@ -149,9 +151,11 @@
 goog.editor.plugins.EquationEditorPlugin.prototype.disable =
     function(fieldObject) {
   goog.base(this, 'disable', fieldObject);
+/*
   if (!this.isEnabled(fieldObject)) {
     goog.events.unlistenByKey(this.dblClickKey_);
   }
+*/
 };
 
 
Index: editor/command.js
===================================================================
--- editor/command.js (revision 2021)
+++ editor/command.js (working copy)
@@ -58,6 +58,7 @@
   DIR_LTR: 'ltr', // should be exactly 'ltr' as it becomes dir attribute value
   DIR_RTL: 'rtl', // same here
   IMAGE: 'image',
+  EQUATION: 'equation',
   EDIT_HTML: 'editHtml',
   UPDATE_LINK_BUBBLE: 'updateLinkBubble',
 

As you can see, it's not so difficult to customize the library, but it takes time to be familiar with the code structure. I also patch default editor demo to make it include equation editor dialog for reference. I hope this post will help those who need a rich text editor with math equation.


References:

[1]Introducing the Closure Library Editor - Closure Tools Blog
[2]Google Search: google closure editor plugin
[3]Write a Google Closure Editor Plugin
[4]yinhm/google-closure-editor-image · GitHub
[5]The Road to HTML 5: contentEditable
[6]Rich HTML editing in the browser: part 1 (backup)
[7]Rich HTML editing in the browser: part 2 (backup)
[8]Updated richtext editor to include HTML source editing
[9]jqMath - Put Math on the Web
[10]javascript - Embeddable WYSIWYG equation editor - Stack Overflow
[11](1, 2) LaTeX Equations in HTML | CodeCogs Equation Editor