improve the mathquill equation editor for tinyMCE, fixes: #11663

now looks like: http://cl.ly/image/3Q2R0l0n3e15

cleaned up styling so it used real dialog buttons.

refactored code to lazy-load math quill css, js
and font only when first needed.

Change-Id: I7cf0894222d7fb7d6fc2ddb09935b2c849bbd4ac
Reviewed-on: https://gerrit.instructure.com/14562
Reviewed-by: Jon Jensen <jon@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
This commit is contained in:
Ryan Shaw 2012-10-18 17:31:12 -06:00
parent e3a869b71e
commit 28c43b29a6
8 changed files with 147 additions and 126 deletions

View File

@ -0,0 +1,80 @@
define [
'i18n!editor'
'jquery'
'underscore'
'Backbone'
'jst/tinymce/EquationEditorView'
'jqueryui/dialog'
'mathquill'
], (I18n, $, _, Backbone, template) ->
# like $.text() / Sizzle.getText(elems), except it also gets alt attributes from images
getEquationText = (elems) ->
_.map elems, (elem) ->
# Get the text from text nodes and CDATA nodes
if elem.nodeType in [3,4]
elem.nodeValue
# Get alt attributes from IMG nodes
else if elem.nodeName is 'IMG' && elem.className is 'equation_image'
elem.alt
# Traverse everything else, except comment nodes
else if elem.nodeType isnt 8
getEquationText( elem.childNodes )
.join('')
class EquationEditorView extends Backbone.View
template: template
# all instances share same element
el: $(document.createElement('span')).appendTo('body')[0]
initialize: (@editor) ->
# calling this just makes sure to get the css loaded
@template()
@$editor = $("##{@editor.id}")
@prevSelection = @editor.selection.getBookmark()
nodes = $('<span>').html @editor.selection.getContent()
equation = getEquationText(nodes).replace(/^\s+|\s+$/g, '')
@$el.dialog
minWidth: 670
minHeight: 290
resizable: true
title: I18n.t('equation_editor_title', 'Use the toolbars or type/paste in LaTeX format to add an equation')
buttons: [
class: 'btn-primary'
text: I18n.t('button.insert_equation', 'Insert Equation')
click: @onSubmit
]
@$el
.mathquill('revert')
.addClass('mathquill-editor')
.mathquill('editor')
.mathquill('write', equation)
.focus()
restoreCaret: ->
@editor.selection.moveToBookmark(@prevSelection)
onSubmit: (event) =>
event.preventDefault()
text = @$el.mathquill('latex')
url = "/equation_images/#{ encodeURIComponent escape text }"
$img = $(document.createElement('img')).attr
src: url
alt: text
title: text
class: 'equation_image'
$div = $(document.createElement('div')).append($img)
@restoreCaret()
@$editor.editorBox 'insert_code', $div.html()
@$el.dialog('close')

View File

@ -0,0 +1,45 @@
//mathquill.scss is just the stock mathquill.css file that comes with the
//javascript library. we had to rename it to be an scss file because
//sass can only import sass/scss files.
@import 'mathquill.scss';
/*
* instructure tweaks of stock mathquill styles
*/
@font-face {
font-family: Symbola;
src: url(/font/Symbola.eot?v1);
src: local("Symbola Regular"),
local("Symbola"),
url(/font/Symbola.ttf?v1) format("truetype"),
url(/font/Symbola.otf?v1) format("opentype"),
url(/font/Symbola.svg?v1#webfont7MzkO3xs) format("svg");
}
.mathquill-editor {
font-size: 1.5em;
// the editable area gets an active blue glow so it looks wierd if there is white space between
// it and the buttonpane
margin-bottom: -5px;
}
//undo the padding added by .ui-dialog
.mathquill-toolbar {
margin-top: -.5em !important;
margin-left: -1em !important;
margin-right: -1em !important;
}
.mathquill-toolbar-panes {
background: #ccc url(/images/tinybg.png) repeat-x top left;
}
.mathquill-tab-pane li {
background: #ccc url(/images/tinybutton.png) repeat-x top left;
}
.mathquill-tab-pane li a:hover {
text-decoration: none;
}
.mathquill-editable .textarea textarea {
z-index: inherit; /* so that jquery modal dialogs don't cancel its events */
}

View File

@ -501,24 +501,3 @@
.mathquill-toolbar * {
cursor: default !important;
}
/*
* instructure tweaks
*/
.mathquill-toolbar-panes {
background: #ccc url(/images/tinybg.png) repeat-x top left;
}
.mathquill-tab-pane li {
background: #ccc url(/images/tinybutton.png) repeat-x top left;
}
.mathquill-tab-pane li a:hover {
text-decoration: none;
}
.mathquill-editable .textarea textarea {
z-index: inherit; /* so that jquery modal dialogs don't cancel its events */
}
/* the @font-face for symbola is in instructure_equation/editor_plugin.js */

View File

@ -0,0 +1 @@
{{! intentionally blank, but needs to be here to load app/stylesheets/jst/tinymce/EquationEditorView.scss}}

View File

@ -171,7 +171,6 @@ stylesheets:
- public/javascripts/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css
- public/stylesheets/compiled/tiny_like_ck_with_external_tools.css
- public/javascripts/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css
- public/stylesheets/static/mathquill.css
messages:
- public/stylesheets/compiled/messages.css
<%= plugin_assets.anchors_yml %>

View File

@ -18,123 +18,38 @@
define([
'compiled/editor/stocktiny',
'jquery',
'jqueryui/dialog',
'mathquill'
], function(tinymce, $) {
// the loading of this @font-face is done here because tinyMCE was blocking rendering untill all of the css
// was loaded. Remember to update the ?v1 querystring parameter if we ever update the font.
$('<style>' +
'@font-face { '+
'font-family: Symbola; src: url(/font/Symbola.eot?v1); src: local("Symbola Regular"), local("Symbola"),' +
'url(/font/Symbola.ttf?v1) format("truetype"),' +
'url(/font/Symbola.otf?v1) format("opentype"),' +
'url(/font/Symbola.svg?v1#webfont7MzkO3xs) format("svg");' +
'}' +
'</style>').appendTo("head");
$("<span class='mathquill-embedded-latex' style='position: absolute; z-index: -1; top: 0; left: 0; width: 0; height: 0; overflow: hidden;'>a</span>").appendTo("body").mathquill();
// like $.text() / Sizzle.getText(elems), except it also gets alt attributes
// from images
function getEquationText(elems) {
var ret = "", elem;
for ( var i = 0; elems[i]; i++ ) {
elem = elems[i];
// Get the text from text nodes and CDATA nodes
if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
ret += elem.nodeValue;
// Get alt attributes from IMG nodes
} else if ( elem.nodeName == 'IMG' && elem.className == 'equation_image' ) {
ret += $(elem).attr('alt');
// Traverse everything else, except comment nodes
} else if ( elem.nodeType !== 8 ) {
ret += getEquationText( elem.childNodes );
}
}
return ret;
}
], function(tinymce) {
tinymce.create('tinymce.plugins.InstructureEquation', {
init : function(ed, url) {
ed.addCommand('instructureEquation', function() {
var nodes = $('<span>' + ed.selection.getContent() + '</span>');
var equation = getEquationText(nodes).replace(/^\s+|\s+$/g, '');
var $editor = $("#" + ed.id);
var $box = $("#instructure_equation_prompt");
if($box.length == 0) {
var $box = $(document.createElement('div'));
$box.append("Use the equation editor below (or type/paste in your equation in LaTeX format). " +
"<form id='instructure_equation_prompt_form' style='margin-top: 5px;'>" +
"<span class='mathquill-editor' style='width: auto; font-size: 1.5em'></span>" +
"<div class='actions' style='padding-top: 10px'><button type='submit' class='button' style='float: right'>Insert Equation</button></div>" +
"</form>");
$box.find("#instructure_equation_prompt_form").submit(function(event) {
var $editor = $box.data('editor');
event.preventDefault();
event.stopPropagation();
var text = $(this).find(".mathquill-editor").mathquill('latex');
var url = "/equation_images/" + encodeURIComponent(escape(text));
var $div = $(document.createElement('div'));
var $img = $(document.createElement('img'));
$img.attr('src', url).attr('alt', text).attr('title', text).attr('class', 'equation_image');
$div.append($img);
$box.data('restore_caret')();
$editor.editorBox('insert_code', $div.html());
$box.dialog('close');
});
$box.attr('id', 'instructure_equation_prompt');
$("body").append($box);
}
var prevSelection = ed.selection.getBookmark();
$box.data('restore_caret', function() {
ed.selection.moveToBookmark(prevSelection);
require(['compiled/views/tinymce/EquationEditorView'], function(EquationEditorView){
new EquationEditorView(ed);
});
$box.data('editor', $editor);
$box.dialog({
width: 690,
minWidth: 690,
minHeight: 300,
resizable: true,
height: "auto",
title: "Embed Math Equation"
});
// needs to be visible for some computed styles to work when we write
// the equation
$box.find(".mathquill-editor").mathquill('revert').
addClass('mathquill-editor').mathquill('editor').
mathquill('write', equation).focus();
});
ed.addButton('instructure_equation', {
title: 'Insert Math Equation',
cmd: 'instructureEquation',
image: url + '/img/button.gif'
});
ed.onNodeChange.add(function(ed, cm, e) {
if(e.nodeName == 'IMG' && e.className == 'equation_image') {
cm.setActive('instructure_equation', true);
// Since equations are inserted as <img>es, we need to prevent the default
// 'image' button from activating too. Runs async to make sure this happens
// AFTER 'image' does it's thing
setTimeout(function(){ cm.setActive('image', false) }, 1);
} else {
cm.setActive('instructure_equation', false);
}
});
},
getInfo : function() {
return {
longname : 'InstructureEquation',
author : 'Brian Whitmer',
authorurl : 'http://www.instructure.com',
infourl : 'http://www.instructure.com',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('instructure_equation', tinymce.plugins.InstructureEquation);
});

View File

@ -28,11 +28,11 @@ describe "equation editor" do
equation_editor = keep_trying_until do
question.find_element(:css, '.mce_instructure_equation').click
sleep 1
equation_editor = fj("#instructure_equation_prompt:visible")
equation_editor = fj(".mathquill-editor:visible")
equation_editor.should_not be_nil
equation_editor
end
equation_editor.find_element(:css, 'button').click
f('.ui-dialog-buttonset .btn-primary').click
question.find_element(:css, '.toggle_question_content_views_link').click
question.find_element(:css, 'textarea.question_content').attribute(:value).should include('<img class="equation_image" title="" src="/equation_images/" alt="" />')
save_question_and_wait

View File

@ -229,16 +229,18 @@ describe "Wiki pages and Tiny WYSIWYG editor features" do
f('#wiki_page_body_instructure_equation').click
wait_for_animations
f('#instructure_equation_prompt').should be_displayed
f('.mathquill-editor').should be_displayed
misc_tab = f('.mathquill-tab-bar > li:last-child a')
driver.action.move_to(misc_tab).perform
f('#Misc_tab li:nth-child(35) a').click
basic_tab = f('.mathquill-tab-bar > li:first-child a')
driver.action.move_to(basic_tab).perform
f('#Basic_tab li:nth-child(27) a').click
submit_form('#instructure_equation_prompt_form')
in_frame "wiki_page_body_ifr" do
f('#tinymce img').should be_displayed
f('.ui-dialog-buttonset .btn-primary').click
keep_trying_until do
in_frame "wiki_page_body_ifr" do
f('#tinymce img.equation_image').should be_displayed
end
end
submit_form('#new_wiki_page')
@ -256,7 +258,7 @@ describe "Wiki pages and Tiny WYSIWYG editor features" do
f('#wiki_page_body_instructure_equation').click
wait_for_animations
f('#instructure_equation_prompt').should be_displayed
f('.mathquill-editor').should be_displayed
textarea = f('.mathquill-editor .textarea textarea')
3.times do
textarea.send_keys(:backspace)
@ -285,7 +287,7 @@ describe "Wiki pages and Tiny WYSIWYG editor features" do
textarea.send_keys :arrow_right
textarea.send_keys :arrow_right
textarea.send_keys "\\text that. is. so. cool."
submit_form('#instructure_equation_prompt_form')
f('.ui-dialog-buttonset .btn-primary').click
wait_for_ajax_requests
in_frame "wiki_page_body_ifr" do
keep_trying_until { f('.equation_image').attribute('title').should == equation_text }