instiki/public/svg-edit/editor/extensions/ext-itex.js
Jacques Distler 5a5ff87286 Fix Bug in itex Extension
Firefox was too lenient, in allowing
you to append nodes from another document to
the svg canvas. Use adoptNode(), to do things
right. (Google Chrome is more strict about this.)
2010-03-05 16:19:12 -06:00

307 lines
8.2 KiB
JavaScript

/*
* ext-itex.js
*
* Licensed under the Apache License, Version 2
*
* Copyright(c) 2010 Jacques Distler
* Copyright(c) 2010 Alexis Deveria
*
*/
$(function() {
svgCanvas.addExtension("itex", function(S) {
var svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson,
selElems,
svgns = "http://www.w3.org/2000/svg",
xlinkns = "http://www.w3.org/1999/xlink",
xmlns = "http://www.w3.org/XML/1998/namespace",
xmlnsns = "http://www.w3.org/2000/xmlns/",
se_ns = "http://svg-edit.googlecode.com",
htmlns = "http://www.w3.org/1999/xhtml",
mathns = "http://www.w3.org/1998/Math/MathML",
ajaxEndpoint = "../../itex",
editingitex = false,
svgdoc = S.svgroot.parentNode.ownerDocument,
started,
newFO;
var properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS
var height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
};
function showPanel(on) {
var fc_rules = $('#fc_rules');
if(!fc_rules.length) {
fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
}
fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
$('#itex_panel').toggle(on);
}
function toggleSourceButtons(on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#itex_save, #itex_cancel').toggle(on);
}
// Function: setItexString(string, url)
// This function sets the content of of the currently-selected foreignObject element,
// based on the itex contained in string.
//
// Parameters:
// string - The itex text.
// url - the url of the itex server to do the conversion
//
// Returns:
// This function returns false if the set was unsuccessful, true otherwise.
function setItexString(tex) {
var elt = selElems[0];
try {
var math = svgdoc.createElementNS(mathns, 'math');
math.setAttributeNS(xmlnsns, 'xmlns', mathns);
math.setAttribute('display', 'inline');
var semantics = document.createElementNS(mathns, 'semantics');
var annotation = document.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = tex;
var mrow = document.createElementNS(mathns, 'mrow');
semantics.appendChild(mrow);
semantics.appendChild(annotation);
math.appendChild(semantics);
// make an AJAX request to the server, to get the MathML
$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){
var children = data.documentElement.childNodes;
while (children.length > 0) {
mrow.appendChild(svgdoc.adoptNode(children[0], true));
}
S.sanitizeSvg(math);
S.call("changed", [elt]);
});
elt.replaceChild(math, elt.firstChild);
S.call("changed", [elt]);
svgCanvas.clearSelection();
} catch(e) {
console.log(e);
return false;
}
return true;
};
function showItexEditor() {
var elt = selElems[0];
var annotation = jQuery('math > semantics > annotation', elt);
if (!annotation || editingitex) return;
editingitex = true;
toggleSourceButtons(true);
// elt.removeAttribute('fill');
var str = annotation.text();
$('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn();
properlySourceSizeTextArea();
$('#svg_source_textarea').focus();
}
function setAttr(attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call("changed", selElems);
}
return {
name: "itex",
svgicons: "extensions/itex-icons.xml",
buttons: [{
id: "tool_itex",
type: "mode",
title: "itex Tool",
events: {
'click': function() {
svgCanvas.setMode('itex')
}
}
},{
id: "edit_itex",
type: "context",
panel: "itex_panel",
title: "Edit TeX Content",
events: {
'click': function() {
showItexEditor();
}
}
}],
context_tools: [{
type: "input",
panel: "itex_panel",
title: "Change enclosing foreignObject's width",
id: "itex_width",
label: "w",
size: 3,
events: {
change: function() {
setAttr('width', this.value);
}
}
},{
type: "input",
panel: "itex_panel",
title: "Change enclosing foreignObject's height",
id: "itex_height",
label: "h",
events: {
change: function() {
setAttr('height', this.value);
}
}
}, {
type: "input",
panel: "itex_panel",
title: "Change font size",
id: "itex_font_size",
label: "font-size",
size: 2,
defval: 16,
events: {
change: function() {
setAttr('font-size', this.value);
}
}
}
],
callback: function() {
$('#itex_panel').hide();
var endChanges = function() {
$('#svg_source_editor').hide();
editingitex = false;
$('#svg_source_textarea').blur();
toggleSourceButtons(false);
}
// TODO: Needs to be done after orig icon loads
setTimeout(function() {
// Create source save/cancel buttons
var save = $('#tool_source_save').clone()
.hide().attr('id', 'itex_save').unbind()
.appendTo("#tool_source_back").click(function() {
if (!editingitex) return;
if (!setItexString($('#svg_source_textarea').val())) {
$.confirm("Errors found. Revert to original?", function(ok) {
if(!ok) return false;
endChanges();
});
} else {
endChanges();
}
// setSelectMode();
});
var cancel = $('#tool_source_cancel').clone()
.hide().attr('id', 'itex_cancel').unbind()
.appendTo("#tool_source_back").click(function() {
endChanges();
});
}, 3000);
},
mouseDown: function(opts) {
var e = opts.event;
if(svgCanvas.getMode() == "itex") {
started = true;
newFO = S.addSvgElementFromJson({
"element": "foreignObject",
"attr": {
"x": opts.start_x,
"y": opts.start_y,
"id": S.getNextId(),
"font-size": 16, //cur_text.font_size,
"width": "48",
"height": "20",
"style": "pointer-events:inherit"
}
});
var m = svgdoc.createElementNS(mathns, 'math');
m.setAttributeNS(xmlnsns, 'xmlns', mathns);
m.setAttribute('display', 'inline');
var semantics = svgdoc.createElementNS(mathns, 'semantics');
var mrow = svgdoc.createElementNS(mathns, 'mrow');
var mi = svgdoc.createElementNS(mathns, 'mi');
mi.setAttribute('mathvariant', 'normal');
mi.textContent = "\u03A6";
var mo = svgdoc.createElementNS(mathns, 'mo');
mo.textContent = "\u222A";
var mi2 = svgdoc.createElementNS(mathns, 'mi');
mi2.textContent = "\u2133";
var annotation = svgdoc.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = "\\Phi \\union \\mathcal{M}";
mrow.appendChild(mi);
mrow.appendChild(mo);
mrow.appendChild(mi2);
semantics.appendChild(mrow);
semantics.appendChild(annotation);
m.appendChild(semantics);
newFO.appendChild(m);
return {
started: true
}
}
},
mouseUp: function(opts) {
var e = opts.event;
if(svgCanvas.getMode() == "itex" && started) {
var attrs = $(newFO).attr(["width", "height"]);
keep = (attrs.width != 0 || attrs.height != 0);
svgCanvas.addToSelection([newFO], true);
return {
keep: keep,
element: newFO
}
}
},
selectedChanged: function(opts) {
// Use this to update the current selected elements
selElems = opts.elems;
var i = selElems.length;
while(i--) {
var elem = selElems[i];
if(elem && elem.tagName == "foreignObject") {
if(opts.selectedElement && !opts.multiselected &&
elem.firstElementChild.namespaceURI == mathns ) {
$('#itex_font_size').val(elem.getAttribute("font-size"));
$('#itex_width').val(elem.getAttribute("width"));
$('#itex_height').val(elem.getAttribute("height"));
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
}
},
elementChanged: function(opts) {
var elem = opts.elems[0];
}
};
});
});