SVG-Edit foreignObject tool refactored as an extension

Thanks to Alexis Deveria. (Though I did fix one small bug.)
My patch-file is now down to a mere 178 lines (a big
chunk of which is Revision 569).
Also, the font-size for foreignObjects defaults to 16pt,
which will be more useful in Instiki.
This commit is contained in:
Jacques Distler 2010-02-16 23:14:04 -06:00
parent 63f1d34d74
commit ce47d49e69
8 changed files with 562 additions and 298 deletions

View file

@ -165,7 +165,6 @@ function svg_edit_setup() {
var selectedElement = null;
var multiselected = false;
var editingsource = false;
var editingforeign = false;
var docprops = false;
var fillPaint = new $.jGraduate.Paint({solidColor: "FF0000"}); // solid red
@ -416,7 +415,74 @@ function svg_edit_setup() {
ext.callback();
}
}
if(ext.context_tools) {
$.each(ext.context_tools, function(i, tool) {
// Add select tool
var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):"";
var panel = $('#' + tool.panel);
if(!panel.length) {
panel = $('<div>', {id: tool.panel}).appendTo("#tools_top");
}
// TODO: Allow support for other types, or adding to existing tool
switch (tool.type) {
case 'tool_button':
var html = '<div class="tool_button">' + tool.id + '</div>';
var div = $(html).appendTo(panel);
if (tool.events) {
$.each(tool.events, function(evt, func) {
$(div).bind(evt, func);
});
}
break;
case 'select':
var html = '<label' + cont_id + '>'
+ '<select id="' + tool.id + '">';
$.each(tool.options, function(val, text) {
var sel = (val == tool.defval) ? " selected":"";
html += '<option value="'+val+'"' + sel + '>' + text + '</option>';
});
html += "</select></label>";
// Creates the tool, hides & adds it, returns the select element
var sel = $(html).appendTo(panel).find('select');
$.each(tool.events, function(evt, func) {
$(sel).bind(evt, func);
});
break;
case 'input':
var html = '<label' + cont_id + '>'
+ '<span id="' + tool.id + '_label">'
+ tool.label + ':</span>'
+ '<input id="' + tool.id + '" title="' + tool.title
+ '" size="' + (tool.size || "4") + '" value="' + (tool.defval || "") + '" type="text"/></label>'
// Creates the tool, hides & adds it, returns the select element
// Add to given tool.panel
var inp = $(html).appendTo(panel).find('input');
if(tool.spindata) {
inp.SpinButton(tool.spindata);
}
if(tool.events) {
$.each(tool.events, function(evt, func) {
inp.bind(evt, func);
});
}
break;
default:
break;
}
});
}
if(ext.buttons) {
var fallback_obj = {},
placement_obj = {},
@ -451,6 +517,10 @@ function svg_edit_setup() {
cls = 'tool_button';
parent = "#tools_left";
break;
case 'context':
cls = 'tool_button';
parent = "#" + btn.panel;
break;
}
var button = $('<div/>')
@ -516,21 +586,31 @@ function svg_edit_setup() {
if(!svgicons) {
button.append(icon);
}
// Add given events to button
$.each(btn.events, function(name, func) {
if(name == "click") {
if(btn.type == 'mode') {
button.bind(name, func);
if(btn.includeWith) {
button.bind(name, func);
} else {
button.bind(name, function() {
if(toolButtonClick(button)) {
func();
}
});
}
if(btn.key) {
$(document).bind('keydown', {combi: btn.key, disableInInput: true}, func);
if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']');
}
} else {
button.bind(name, func);
}
} else {
button.bind(name, func);
}
});
});
setupFlyouts(holders);
});
@ -542,7 +622,6 @@ function svg_edit_setup() {
fallback: fallback_obj,
placement: placement_obj,
callback: function(icons) {
// Bad hack to make the icon match the current size
// TODO: Write better hack!
var old = curPrefs.iconsize;
@ -555,72 +634,6 @@ function svg_edit_setup() {
});
}
if(ext.context_tools) {
$.each(ext.context_tools, function(i, tool) {
// Add select tool
var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):"";
var panel = $('#' + tool.panel);
if(!panel.length) {
panel = $('<div>', {id: tool.panel}).appendTo("#tools_top");
}
// TODO: Allow support for other types, or adding to existing tool
switch (tool.type) {
case 'tool_button':
var html = '<div class="tool_button">' + tool.id + '</div>';
var div = $(html).appendTo(panel);
if (tool.events) {
$.each(tool.events, function(evt, func) {
$(div).bind(evt, func);
});
}
break;
case 'select':
var html = '<label' + cont_id + '>'
+ '<select id="' + tool.id + '">';
$.each(tool.options, function(val, text) {
var sel = (val == tool.defval) ? " selected":"";
html += '<option value="'+val+'"' + sel + '>' + text + '</option>';
});
html += "</select></label>";
// Creates the tool, hides & adds it, returns the select element
var sel = $(html).appendTo(panel).find('select');
$.each(tool.events, function(evt, func) {
$(sel).bind(evt, func);
});
break;
case 'input':
var html = '<label' + cont_id + '">'
+ '<span id="' + tool.id + '_label">'
+ tool.label + ':</span>'
+ '<input id="' + tool.id + '" title="' + tool.title
+ '" size="' + (tool.size || "4") + '" value="' + (tool.defval || "") + '" type="text"/></label>'
// Creates the tool, hides & adds it, returns the select element
// Add to given tool.panel
var inp = $(html).appendTo(panel).find('input');
if(tool.spindata) {
inp.SpinButton(tool.spindata);
}
if(tool.events) {
$.each(tool.events, function(evt, func) {
$(sel).bind(evt, func);
});
}
break;
default:
break;
}
});
}
runCallback();
};
@ -652,8 +665,8 @@ function svg_edit_setup() {
// updates the toolbar (colors, opacity, etc) based on the selected element
var updateToolbar = function() {
if (selectedElement != null &&
selectedElement.tagName != "foreignObject" &&
selectedElement.tagName != "image" &&
selectedElement.tagName != "foreignObject" &&
selectedElement.tagName != "g")
{
// get opacity values
@ -734,7 +747,7 @@ function svg_edit_setup() {
var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false;
$('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,\
#ellipse_panel, #line_panel, #text_panel, #image_panel, #foreignObject_panel').hide();
#ellipse_panel, #line_panel, #text_panel, #image_panel').hide();
if (elem != null) {
var elname = elem.nodeName;
var angle = svgCanvas.getRotationAngle(elem);
@ -772,7 +785,7 @@ function svg_edit_setup() {
}
// Elements in this array cannot be converted to a path
var no_path = $.inArray(elname, ['image', 'text', 'path', 'g', 'use', 'foreignObject']) == -1;
var no_path = $.inArray(elname, ['image', 'text', 'path', 'g', 'use']) == -1;
$('#tool_topath').toggle(no_path);
$('#tool_reorient').toggle(elname == 'path');
$('#tool_reorient').toggleClass('disabled', angle == 0);
@ -800,7 +813,6 @@ function svg_edit_setup() {
circle: ['cx','cy','r'],
ellipse: ['cx','cy','rx','ry'],
line: ['x1','y1','x2','y2'],
foreignObject: [],
text: []
};
@ -837,12 +849,6 @@ function svg_edit_setup() {
$('#text').focus().select();
}
} // text
else if (el_name == 'foreignObject') {
$('#foreignObject_panel').css("display", "inline");
$('#foreign_font_size').val(elem.getAttribute("font-size"));
$('#foreign_width').val(elem.getAttribute("width"));
$('#foreign_height').val(elem.getAttribute("height"));
} //foreignObject
else if(el_name == 'image') {
var xlinkNS="http://www.w3.org/1999/xlink";
var href = elem.getAttributeNS(xlinkNS, "href");
@ -1331,11 +1337,6 @@ function svg_edit_setup() {
svgCanvas.setMode('text');
};
var clickForeign = function(){
toolButtonClick('#tool_foreign');
svgCanvas.setMode('foreign');
};
var clickPath = function(){
toolButtonClick('#tool_path');
svgCanvas.setMode('path');
@ -1540,21 +1541,10 @@ function svg_edit_setup() {
var str = svgCanvas.getSvgString();
$('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn();
properlySourceSizeTextArea('source');
properlySourceSizeTextArea();
$('#svg_source_textarea').focus();
};
var showForeignEditor = function(elt){
if (!elt || editingforeign) return;
editingforeign = true;
elt.removeAttribute('fill');
var str = svgCanvas.getForeignString(elt);
$('#svg_foreign_textarea').val(str);
$('#svg_foreign_editor').fadeIn();
properlySourceSizeTextArea('foreign');
$('#svg_foreign_textarea').focus();
};
$('#svg_docprops_container').draggable({cancel:'button,fieldset'});
var showDocProperties = function(){
@ -1590,40 +1580,18 @@ function svg_edit_setup() {
$('#svg_docprops').fadeIn();
};
var properlySourceSizeTextArea = function(str){
var properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS
var height = $('#svg_'+str+'_container').height() - 80;
$('#svg_'+str+'_textarea').css('height', height);
var height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
};
var saveForeignEditor = function(elt){
if (!editingforeign) return;
var saveChanges = function() {
svgCanvas.clearSelection();
hideSourceEditor('foreign');
zoomImage();
populateLayers();
setTitle(svgCanvas.getImageTitle());
}
if (!svgCanvas.setForeignString($('#svg_foreign_textarea').val(), elt)) {
$.confirm(uiStrings.QerrorsRevertToSource, function(ok) {
if(!ok) return false;
saveChanges();
});
} else {
saveChanges();
}
setSelectMode();
}
var saveSourceEditor = function(){
if (!editingsource) return;
var saveChanges = function() {
svgCanvas.clearSelection();
hideSourceEditor('source');
hideSourceEditor();
zoomImage();
populateLayers();
setTitle(svgCanvas.getImageTitle());
@ -1850,28 +1818,18 @@ function svg_edit_setup() {
setFlyoutPositions();
}
var cancelOverlays = function(elt) {
var cancelOverlays = function() {
$('#dialog_box').hide();
if (!editingsource && !editingforeign && !docprops) return;
if (!editingsource && !docprops) return;
if (editingsource) {
var oldString = svgCanvas.getSvgString();
if (oldString != $('#svg_source_textarea').val()) {
$.confirm(uiStrings.QignoreSourceChanges, function(ok) {
if(ok) hideSourceEditor('source');
if(ok) hideSourceEditor();
});
} else {
hideSourceEditor('source');
}
}
else if (editingforeign) {
var oldString = svgCanvas.getForeignString(elt);
if (oldString != $('#svg_foreign_textarea').val()) {
$.confirm(uiStrings.QignoreSourceChanges, function(ok) {
if(ok) hideSourceEditor('foreign');
});
} else {
hideSourceEditor('foreign');
hideSourceEditor();
}
}
else if (docprops) {
@ -1880,11 +1838,10 @@ function svg_edit_setup() {
};
var hideSourceEditor = function(str){
$('#svg_'+str+'_editor').hide();
var hideSourceEditor = function(){
$('#svg_source_editor').hide();
editingsource = false;
editingforeign = false;
$('#svg_'+str+'_textarea').blur();
$('#svg_source_textarea').blur();
};
var hideDocProperties = function(){
@ -1897,11 +1854,8 @@ function svg_edit_setup() {
// TODO: add canvas-centering code in here
$(window).resize(function(evt) {
if (editingsource) {
properlySourceSizeTextArea('source');
} else if(editingforeign) {
properlySourceSizeTextArea('foreign');
}
if (!editingsource) return;
properlySourceSizeTextArea();
});
$('#url_notice').click(function() {
@ -2037,7 +1991,7 @@ function svg_edit_setup() {
var bNoFill = (svgCanvas.getFillColor() == 'none');
var bNoStroke = (svgCanvas.getStrokeColor() == 'none');
var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ];
var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_foreign', '#tool_path', '#tool_edit_foreign'];
var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path'];
if (bNoStroke) {
for (index in buttonsNeedingStroke) {
var button = buttonsNeedingStroke[index];
@ -2500,19 +2454,13 @@ function svg_edit_setup() {
{sel:'#tool_text', fn: clickText, evt: 'click', key: 7},
{sel:'#tool_image', fn: clickImage, evt: 'mouseup', key: 8},
{sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: 9},
{sel:'#tool_foreign', fn: clickForeign, evt: 'mouseup'},
{sel:'#tool_edit_foreign', fn: function(){showForeignEditor(selectedElement)}, evt: 'mouseup'},
{sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey+'N', true]},
{sel:'#tool_save', fn: function() { if(editingsource){saveSourceEditor()}
else if(editingforeign){saveForeignEditor(selectedElement)}
else clickSave()}, evt: 'mouseup', key: [modKey+'S', true]},
{sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey+'S', true]},
{sel:'#tool_open', fn: clickOpen, evt: 'mouseup', key: [modKey+'O', true]},
{sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: ['U', true]},
{sel:'#tool_wireframe', fn: clickWireframe, evt: 'click', key: ['F', true]},
{sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true},
{sel:'#tool_foreign_cancel,#svg_source_overlay,#tool_docprops_cancel', fn: function(){cancelOverlays(selectedElement)}, evt: 'click', key: ['esc', false, false], hidekey: true},
{sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'},
{sel:'#tool_foreign_save', fn: function(){saveForeignEditor(selectedElement)}, evt: 'click'},
{sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'},
{sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup', key: [modKey+'I', true]},
{sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]},
@ -2812,7 +2760,7 @@ function svg_edit_setup() {
updateCanvas(true);
});
// var revnums = "svg-editor.js ($Rev: 1386 $) ";
// var revnums = "svg-editor.js ($Rev: 1395 $) ";
// revnums += svgCanvas.getVersion();
// $('#copyright')[0].setAttribute("title", revnums);
return svgCanvas;
@ -2850,8 +2798,6 @@ function svg_edit_setup() {
'text':'text.png',
'image':'image.png',
'zoom':'zoom.png',
'foreign':'foreign.png',
'edit_foreign':'edit_foreign.png',
'clone':'clone.png',
'delete':'delete.png',
@ -2905,8 +2851,6 @@ function svg_edit_setup() {
'#tool_text,#layer_rename':'text',
'#tool_image':'image',
'#tool_zoom':'zoom',
'#tool_foreign':'foreign',
'#tool_edit_foreign':'edit_foreign',
'#tool_clone,#tool_clone_multi,#tool_node_clone':'clone',
'#layer_delete,#tool_delete,#tool_delete_multi,#tool_node_delete':'delete',
@ -2931,8 +2875,8 @@ function svg_edit_setup() {
'#layer_down':'go_down',
'#layerlist td.layervis':'eye',
'#tool_source_save,#tool_foreign_save,#tool_docprops_save':'ok',
'#tool_source_cancel,#tool_foreign_cancel,#tool_docprops_cancel':'cancel',
'#tool_source_save,#tool_docprops_save':'ok',
'#tool_source_cancel,#tool_docprops_cancel':'cancel',
'.flyout_arrow_horiz':'arrow_right',
'.dropdown button, #main_button .dropdown':'arrow_down',
@ -2977,13 +2921,13 @@ function svg_edit_setup() {
// Load source if given
var loc = document.location.href;
if(loc.indexOf('source=data') != -1) {
var pre = 'source=data:image/svg+xml;base64,';
if(loc.indexOf('?source=') != -1) {
var pre = '?source=data:image/svg+xml;base64,';
var src = loc.substring(loc.indexOf(pre) + pre.length);
svgCanvas.setSvgString(Utils.decode64(src));
}
else if(loc.indexOf('url=') != -1) {
var pre = 'url=';
else if(loc.indexOf('?url=') != -1) {
var pre = '?url=';
var url = loc.substring(loc.indexOf(pre) + pre.length);
$.ajax({
'url': url,