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:
parent
e3a869b71e
commit
28c43b29a6
|
@ -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')
|
|
@ -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 */
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1 @@
|
|||
{{! intentionally blank, but needs to be here to load app/stylesheets/jst/tinymce/EquationEditorView.scss}}
|
|
@ -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 %>
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
Loading…
Reference in New Issue