Convert all tabs to spaces in extensions for issue #37

This commit is contained in:
codedread
2018-05-17 21:54:31 -07:00
parent e38fbc75c7
commit 646a927ef6
22 changed files with 4064 additions and 4064 deletions

View File

@@ -10,283 +10,283 @@
*/ */
svgEditor.addExtension('Arrows', function (S) { svgEditor.addExtension('Arrows', function (S) {
var // svgcontent = S.svgcontent, var // svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson, addElem = S.addSvgElementFromJson,
nonce = S.nonce, nonce = S.nonce,
randomizeIds = S.randomize_ids, randomizeIds = S.randomize_ids,
selElems, pathdata, selElems, pathdata,
langList = { langList = {
'en': [ 'en': [
{'id': 'arrow_none', 'textContent': 'No arrow'} {'id': 'arrow_none', 'textContent': 'No arrow'}
], ],
'fr': [ 'fr': [
{'id': 'arrow_none', 'textContent': 'Sans flèche'} {'id': 'arrow_none', 'textContent': 'Sans flèche'}
] ]
}, },
arrowprefix, arrowprefix,
prefix = 'se_arrow_'; prefix = 'se_arrow_';
function setArrowNonce (window, n) { function setArrowNonce (window, n) {
randomizeIds = true; randomizeIds = true;
arrowprefix = prefix + n + '_'; arrowprefix = prefix + n + '_';
pathdata.fw.id = arrowprefix + 'fw'; pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk'; pathdata.bk.id = arrowprefix + 'bk';
} }
function unsetArrowNonce (window) { function unsetArrowNonce (window) {
randomizeIds = false; randomizeIds = false;
arrowprefix = prefix; arrowprefix = prefix;
pathdata.fw.id = arrowprefix + 'fw'; pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk'; pathdata.bk.id = arrowprefix + 'bk';
} }
svgCanvas.bind('setnonce', setArrowNonce); svgCanvas.bind('setnonce', setArrowNonce);
svgCanvas.bind('unsetnonce', unsetArrowNonce); svgCanvas.bind('unsetnonce', unsetArrowNonce);
if (randomizeIds) { if (randomizeIds) {
arrowprefix = prefix + nonce + '_'; arrowprefix = prefix + nonce + '_';
} else { } else {
arrowprefix = prefix; arrowprefix = prefix;
} }
pathdata = { pathdata = {
fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'}, fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'},
bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'} bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
}; };
function getLinked (elem, attr) { function getLinked (elem, attr) {
var str = elem.getAttribute(attr); var str = elem.getAttribute(attr);
if (!str) { return null; } if (!str) { return null; }
var m = str.match(/\(#(.*)\)/); var m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) { if (!m || m.length !== 2) {
return null; return null;
} }
return S.getElem(m[1]); return S.getElem(m[1]);
} }
function showPanel (on) { function showPanel (on) {
$('#arrow_panel').toggle(on); $('#arrow_panel').toggle(on);
if (on) { if (on) {
var el = selElems[0]; var el = selElems[0];
var end = el.getAttribute('marker-end'); var end = el.getAttribute('marker-end');
var start = el.getAttribute('marker-start'); var start = el.getAttribute('marker-start');
var mid = el.getAttribute('marker-mid'); var mid = el.getAttribute('marker-mid');
var val; var val;
if (end && start) { if (end && start) {
val = 'both'; val = 'both';
} else if (end) { } else if (end) {
val = 'end'; val = 'end';
} else if (start) { } else if (start) {
val = 'start'; val = 'start';
} else if (mid) { } else if (mid) {
val = 'mid'; val = 'mid';
if (mid.indexOf('bk') !== -1) { if (mid.indexOf('bk') !== -1) {
val = 'mid_bk'; val = 'mid_bk';
} }
} }
if (!start && !mid && !end) { if (!start && !mid && !end) {
val = 'none'; val = 'none';
} }
$('#arrow_list').val(val); $('#arrow_list').val(val);
} }
} }
function resetMarker () { function resetMarker () {
var el = selElems[0]; var el = selElems[0];
el.removeAttribute('marker-start'); el.removeAttribute('marker-start');
el.removeAttribute('marker-mid'); el.removeAttribute('marker-mid');
el.removeAttribute('marker-end'); el.removeAttribute('marker-end');
} }
function addMarker (dir, type, id) { function addMarker (dir, type, id) {
// TODO: Make marker (or use?) per arrow type, since refX can be different // TODO: Make marker (or use?) per arrow type, since refX can be different
id = id || arrowprefix + dir; id = id || arrowprefix + dir;
var marker = S.getElem(id); var marker = S.getElem(id);
var data = pathdata[dir]; var data = pathdata[dir];
if (type === 'mid') { if (type === 'mid') {
data.refx = 5; data.refx = 5;
} }
if (!marker) { if (!marker) {
marker = addElem({ marker = addElem({
'element': 'marker', 'element': 'marker',
'attr': { 'attr': {
'viewBox': '0 0 10 10', 'viewBox': '0 0 10 10',
'id': id, 'id': id,
'refY': 5, 'refY': 5,
'markerUnits': 'strokeWidth', 'markerUnits': 'strokeWidth',
'markerWidth': 5, 'markerWidth': 5,
'markerHeight': 5, 'markerHeight': 5,
'orient': 'auto', 'orient': 'auto',
'style': 'pointer-events:none' // Currently needed for Opera 'style': 'pointer-events:none' // Currently needed for Opera
} }
}); });
var arrow = addElem({ var arrow = addElem({
'element': 'path', 'element': 'path',
'attr': { 'attr': {
'd': data.d, 'd': data.d,
'fill': '#000000' 'fill': '#000000'
} }
}); });
marker.appendChild(arrow); marker.appendChild(arrow);
S.findDefs().appendChild(marker); S.findDefs().appendChild(marker);
} }
marker.setAttribute('refX', data.refx); marker.setAttribute('refX', data.refx);
return marker; return marker;
} }
function setArrow () { function setArrow () {
var type = this.value; var type = this.value;
resetMarker(); resetMarker();
if (type === 'none') { if (type === 'none') {
return; return;
} }
// Set marker on element // Set marker on element
var dir = 'fw'; var dir = 'fw';
if (type === 'mid_bk') { if (type === 'mid_bk') {
type = 'mid'; type = 'mid';
dir = 'bk'; dir = 'bk';
} else if (type === 'both') { } else if (type === 'both') {
addMarker('bk', type); addMarker('bk', type);
svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')');
type = 'end'; type = 'end';
dir = 'fw'; dir = 'fw';
} else if (type === 'start') { } else if (type === 'start') {
dir = 'bk'; dir = 'bk';
} }
addMarker(dir, type); addMarker(dir, type);
svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')');
S.call('changed', selElems); S.call('changed', selElems);
} }
function colorChanged (elem) { function colorChanged (elem) {
var color = elem.getAttribute('stroke'); var color = elem.getAttribute('stroke');
var mtypes = ['start', 'mid', 'end']; var mtypes = ['start', 'mid', 'end'];
var defs = S.findDefs(); var defs = S.findDefs();
$.each(mtypes, function (i, type) { $.each(mtypes, function (i, type) {
var marker = getLinked(elem, 'marker-' + type); var marker = getLinked(elem, 'marker-' + type);
if (!marker) { return; } if (!marker) { return; }
var curColor = $(marker).children().attr('fill'); var curColor = $(marker).children().attr('fill');
var curD = $(marker).children().attr('d'); var curD = $(marker).children().attr('d');
var newMarker = null; var newMarker = null;
if (curColor === color) { return; } if (curColor === color) { return; }
var allMarkers = $(defs).find('marker'); var allMarkers = $(defs).find('marker');
// Different color, check if already made // Different color, check if already made
allMarkers.each(function () { allMarkers.each(function () {
var attrs = $(this).children().attr(['fill', 'd']); var attrs = $(this).children().attr(['fill', 'd']);
if (attrs.fill === color && attrs.d === curD) { if (attrs.fill === color && attrs.d === curD) {
// Found another marker with this color and this path // Found another marker with this color and this path
newMarker = this; newMarker = this;
} }
}); });
if (!newMarker) { if (!newMarker) {
// Create a new marker with this color // Create a new marker with this color
var lastId = marker.id; var lastId = marker.id;
var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk'; var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk';
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length); newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
$(newMarker).children().attr('fill', color); $(newMarker).children().attr('fill', color);
} }
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')'); $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
// Check if last marker can be removed // Check if last marker can be removed
var remove = true; var remove = true;
$(S.svgcontent).find('line, polyline, path, polygon').each(function () { $(S.svgcontent).find('line, polyline, path, polygon').each(function () {
var elem = this; var elem = this;
$.each(mtypes, function (j, mtype) { $.each(mtypes, function (j, mtype) {
if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
remove = false; remove = false;
return remove; return remove;
} }
}); });
if (!remove) { return false; } if (!remove) { return false; }
}); });
// Not found, so can safely remove // Not found, so can safely remove
if (remove) { if (remove) {
$(marker).remove(); $(marker).remove();
} }
}); });
} }
return { return {
name: 'Arrows', name: 'Arrows',
context_tools: [{ context_tools: [{
type: 'select', type: 'select',
panel: 'arrow_panel', panel: 'arrow_panel',
title: 'Select arrow type', title: 'Select arrow type',
id: 'arrow_list', id: 'arrow_list',
options: { options: {
none: 'No arrow', none: 'No arrow',
end: '---->', end: '---->',
start: '<----', start: '<----',
both: '<--->', both: '<--->',
mid: '-->--', mid: '-->--',
mid_bk: '--<--' mid_bk: '--<--'
}, },
defval: 'none', defval: 'none',
events: { events: {
change: setArrow change: setArrow
} }
}], }],
callback: function () { callback: function () {
$('#arrow_panel').hide(); $('#arrow_panel').hide();
// Set ID so it can be translated in locale file // Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow'; $('#arrow_list option')[0].id = 'connector_no_arrow';
}, },
addLangData: function (lang) { addLangData: function (lang) {
return { return {
data: langList[lang] data: langList[lang]
}; };
}, },
selectedChanged: function (opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
var markerElems = ['line', 'path', 'polyline', 'polygon']; var markerElems = ['line', 'path', 'polyline', 'polygon'];
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && $.inArray(elem.tagName, markerElems) !== -1) { if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
} }
} else { } else {
showPanel(false); showPanel(false);
} }
} }
}, },
elementChanged: function (opts) { elementChanged: function (opts) {
var elem = opts.elems[0]; var elem = opts.elems[0];
if (elem && ( if (elem && (
elem.getAttribute('marker-start') || elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') || elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end') elem.getAttribute('marker-end')
)) { )) {
// var start = elem.getAttribute('marker-start'); // var start = elem.getAttribute('marker-start');
// var mid = elem.getAttribute('marker-mid'); // var mid = elem.getAttribute('marker-mid');
// var end = elem.getAttribute('marker-end'); // var end = elem.getAttribute('marker-end');
// Has marker, so see if it should match color // Has marker, so see if it should match color
colorChanged(elem); colorChanged(elem);
} }
} }
}; };
}); });

View File

@@ -12,81 +12,81 @@
// This extension adds a simple button to the contextual panel for paths // This extension adds a simple button to the contextual panel for paths
// The button toggles whether the path is open or closed // The button toggles whether the path is open or closed
svgEditor.addExtension('ClosePath', function () { svgEditor.addExtension('ClosePath', function () {
'use strict'; 'use strict';
var selElems, var selElems,
updateButton = function (path) { updateButton = function (path) {
var seglist = path.pathSegList, var seglist = path.pathSegList,
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
showbutton = closed ? '#tool_openpath' : '#tool_closepath', showbutton = closed ? '#tool_openpath' : '#tool_closepath',
hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
$(hidebutton).hide(); $(hidebutton).hide();
$(showbutton).show(); $(showbutton).show();
}, },
showPanel = function (on) { showPanel = function (on) {
$('#closepath_panel').toggle(on); $('#closepath_panel').toggle(on);
if (on) { if (on) {
var path = selElems[0]; var path = selElems[0];
if (path) { updateButton(path); } if (path) { updateButton(path); }
} }
}, },
toggleClosed = function () { toggleClosed = function () {
var path = selElems[0]; var path = selElems[0];
if (path) { if (path) {
var seglist = path.pathSegList, var seglist = path.pathSegList,
last = seglist.numberOfItems - 1; last = seglist.numberOfItems - 1;
// is closed // is closed
if (seglist.getItem(last).pathSegType === 1) { if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last); seglist.removeItem(last);
} else { } else {
seglist.appendItem(path.createSVGPathSegClosePath()); seglist.appendItem(path.createSVGPathSegClosePath());
} }
updateButton(path); updateButton(path);
} }
}; };
return { return {
name: 'ClosePath', name: 'ClosePath',
svgicons: svgEditor.curConfig.extPath + 'closepath_icons.svg', svgicons: svgEditor.curConfig.extPath + 'closepath_icons.svg',
buttons: [{ buttons: [{
id: 'tool_openpath', id: 'tool_openpath',
type: 'context', type: 'context',
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Open path', title: 'Open path',
events: { events: {
click: function () { click: function () {
toggleClosed(); toggleClosed();
} }
} }
}, },
{ {
id: 'tool_closepath', id: 'tool_closepath',
type: 'context', type: 'context',
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Close path', title: 'Close path',
events: { events: {
click: function () { click: function () {
toggleClosed(); toggleClosed();
} }
} }
}], }],
callback: function () { callback: function () {
$('#closepath_panel').hide(); $('#closepath_panel').hide();
}, },
selectedChanged: function (opts) { selectedChanged: function (opts) {
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && elem.tagName === 'path') { if (elem && elem.tagName === 'path') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
} }
} else { } else {
showPanel(false); showPanel(false);
} }
} }
} }
}; };
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -16,96 +16,96 @@
// 4) svgcanvas.js // 4) svgcanvas.js
svgEditor.addExtension('eyedropper', function (S) { svgEditor.addExtension('eyedropper', function (S) {
'use strict'; 'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
svgCanvas = svgEditor.canvas, svgCanvas = svgEditor.canvas,
ChangeElementCommand = svgedit.history.ChangeElementCommand, ChangeElementCommand = svgedit.history.ChangeElementCommand,
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
currentStyle = { currentStyle = {
fillPaint: 'red', fillOpacity: 1.0, fillPaint: 'red', fillOpacity: 1.0,
strokePaint: 'black', strokeOpacity: 1.0, strokePaint: 'black', strokeOpacity: 1.0,
strokeWidth: 5, strokeDashArray: null, strokeWidth: 5, strokeDashArray: null,
opacity: 1.0, opacity: 1.0,
strokeLinecap: 'butt', strokeLinecap: 'butt',
strokeLinejoin: 'miter' strokeLinejoin: 'miter'
}; };
function getStyle (opts) { function getStyle (opts) {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool // if we are in eyedropper mode, we don't want to disable the eye-dropper tool
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode === 'eyedropper') { return; } if (mode === 'eyedropper') { return; }
var elem = null; var elem = null;
var tool = $('#tool_eyedropper'); var tool = $('#tool_eyedropper');
// enable-eye-dropper if one element is selected // enable-eye-dropper if one element is selected
if (!opts.multiselected && opts.elems[0] && if (!opts.multiselected && opts.elems[0] &&
$.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1 $.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1
) { ) {
elem = opts.elems[0]; elem = opts.elems[0];
tool.removeClass('disabled'); tool.removeClass('disabled');
// grab the current style // grab the current style
currentStyle.fillPaint = elem.getAttribute('fill') || 'black'; currentStyle.fillPaint = elem.getAttribute('fill') || 'black';
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0; currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0;
currentStyle.strokePaint = elem.getAttribute('stroke'); currentStyle.strokePaint = elem.getAttribute('stroke');
currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0; currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0;
currentStyle.strokeWidth = elem.getAttribute('stroke-width'); currentStyle.strokeWidth = elem.getAttribute('stroke-width');
currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray'); currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray');
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap'); currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap');
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin'); currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin');
currentStyle.opacity = elem.getAttribute('opacity') || 1.0; currentStyle.opacity = elem.getAttribute('opacity') || 1.0;
// disable eye-dropper tool // disable eye-dropper tool
} else { } else {
tool.addClass('disabled'); tool.addClass('disabled');
} }
} }
return { return {
name: 'eyedropper', name: 'eyedropper',
svgicons: svgEditor.curConfig.extPath + 'eyedropper-icon.xml', svgicons: svgEditor.curConfig.extPath + 'eyedropper-icon.xml',
buttons: [{ buttons: [{
id: 'tool_eyedropper', id: 'tool_eyedropper',
type: 'mode', type: 'mode',
title: 'Eye Dropper Tool', title: 'Eye Dropper Tool',
key: 'I', key: 'I',
events: { events: {
click: function () { click: function () {
svgCanvas.setMode('eyedropper'); svgCanvas.setMode('eyedropper');
} }
} }
}], }],
// if we have selected an element, grab its paint and enable the eye dropper button // if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle, selectedChanged: getStyle,
elementChanged: getStyle, elementChanged: getStyle,
mouseDown: function (opts) { mouseDown: function (opts) {
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode === 'eyedropper') { if (mode === 'eyedropper') {
var e = opts.event; var e = opts.event;
var target = e.target; var target = e.target;
if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) { if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) {
var changes = {}; var changes = {};
var change = function (elem, attrname, newvalue) { var change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname); changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue); elem.setAttribute(attrname, newvalue);
}; };
if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); } if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); }
if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); } if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); }
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); } if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); }
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); } if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); }
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); } if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); }
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); } if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); }
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); } if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); }
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); } if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); }
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); } if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); }
addToHistory(new ChangeElementCommand(target, changes)); addToHistory(new ChangeElementCommand(target, changes));
} }
} }
} }
}; };
}); });

View File

@@ -11,254 +11,254 @@
*/ */
svgEditor.addExtension('foreignObject', function (S) { svgEditor.addExtension('foreignObject', function (S) {
var NS = svgedit.NS, var NS = svgedit.NS,
Utils = svgedit.utilities, Utils = svgedit.utilities,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson, // addElem = S.addSvgElementFromJson,
selElems, selElems,
editingforeign = false, editingforeign = false,
svgdoc = S.svgroot.parentNode.ownerDocument, svgdoc = S.svgroot.parentNode.ownerDocument,
started, started,
newFO; newFO;
var properlySourceSizeTextArea = function () { var properlySourceSizeTextArea = function () {
// TODO: remove magic numbers here and get values from CSS // TODO: remove magic numbers here and get values from CSS
var height = $('#svg_source_container').height() - 80; var height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height); $('#svg_source_textarea').css('height', height);
}; };
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); var fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#foreignObject_panel').toggle(on); $('#foreignObject_panel').toggle(on);
} }
function toggleSourceButtons (on) { function toggleSourceButtons (on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on); $('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#foreign_save, #foreign_cancel').toggle(on); $('#foreign_save, #foreign_cancel').toggle(on);
} }
// Function: setForeignString(xmlString, elt) // Function: setForeignString(xmlString, elt)
// This function sets the content of element elt to the input XML. // This function sets the content of element elt to the input XML.
// //
// Parameters: // Parameters:
// xmlString - The XML text. // xmlString - The XML text.
// elt - the parent element to append to // elt - the parent element to append to
// //
// Returns: // Returns:
// This function returns false if the set was unsuccessful, true otherwise. // This function returns false if the set was unsuccessful, true otherwise.
function setForeignString (xmlString) { function setForeignString (xmlString) {
var elt = selElems[0]; var elt = selElems[0];
try { try {
// convert string into XML document // convert string into XML document
var newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>'); var newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
// run it through our sanitizer to remove anything we do not support // run it through our sanitizer to remove anything we do not support
S.sanitizeSvg(newDoc.documentElement); S.sanitizeSvg(newDoc.documentElement);
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
S.call('changed', [elt]); S.call('changed', [elt]);
svgCanvas.clearSelection(); svgCanvas.clearSelection();
} catch (e) { } catch (e) {
console.log(e); console.log(e);
return false; return false;
} }
return true; return true;
} }
function showForeignEditor () { function showForeignEditor () {
var elt = selElems[0]; var elt = selElems[0];
if (!elt || editingforeign) { return; } if (!elt || editingforeign) { return; }
editingforeign = true; editingforeign = true;
toggleSourceButtons(true); toggleSourceButtons(true);
elt.removeAttribute('fill'); elt.removeAttribute('fill');
var str = S.svgToString(elt, 0); var str = S.svgToString(elt, 0);
$('#svg_source_textarea').val(str); $('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn(); $('#svg_source_editor').fadeIn();
properlySourceSizeTextArea(); properlySourceSizeTextArea();
$('#svg_source_textarea').focus(); $('#svg_source_textarea').focus();
} }
function setAttr (attr, val) { function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems); S.call('changed', selElems);
} }
return { return {
name: 'foreignObject', name: 'foreignObject',
svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml', svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml',
buttons: [{ buttons: [{
id: 'tool_foreign', id: 'tool_foreign',
type: 'mode', type: 'mode',
title: 'Foreign Object Tool', title: 'Foreign Object Tool',
events: { events: {
'click': function () { 'click': function () {
svgCanvas.setMode('foreign'); svgCanvas.setMode('foreign');
} }
} }
}, { }, {
id: 'edit_foreign', id: 'edit_foreign',
type: 'context', type: 'context',
panel: 'foreignObject_panel', panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content', title: 'Edit ForeignObject Content',
events: { events: {
'click': function () { 'click': function () {
showForeignEditor(); showForeignEditor();
} }
} }
}], }],
context_tools: [{ context_tools: [{
type: 'input', type: 'input',
panel: 'foreignObject_panel', panel: 'foreignObject_panel',
title: "Change foreignObject's width", title: "Change foreignObject's width",
id: 'foreign_width', id: 'foreign_width',
label: 'w', label: 'w',
size: 3, size: 3,
events: { events: {
change: function () { change: function () {
setAttr('width', this.value); setAttr('width', this.value);
} }
} }
}, { }, {
type: 'input', type: 'input',
panel: 'foreignObject_panel', panel: 'foreignObject_panel',
title: "Change foreignObject's height", title: "Change foreignObject's height",
id: 'foreign_height', id: 'foreign_height',
label: 'h', label: 'h',
events: { events: {
change: function () { change: function () {
setAttr('height', this.value); setAttr('height', this.value);
} }
} }
}, { }, {
type: 'input', type: 'input',
panel: 'foreignObject_panel', panel: 'foreignObject_panel',
title: "Change foreignObject's font size", title: "Change foreignObject's font size",
id: 'foreign_font_size', id: 'foreign_font_size',
label: 'font-size', label: 'font-size',
size: 2, size: 2,
defval: 16, defval: 16,
events: { events: {
change: function () { change: function () {
setAttr('font-size', this.value); setAttr('font-size', this.value);
} }
} }
} }
], ],
callback: function () { callback: function () {
$('#foreignObject_panel').hide(); $('#foreignObject_panel').hide();
var endChanges = function () { var endChanges = function () {
$('#svg_source_editor').hide(); $('#svg_source_editor').hide();
editingforeign = false; editingforeign = false;
$('#svg_source_textarea').blur(); $('#svg_source_textarea').blur();
toggleSourceButtons(false); toggleSourceButtons(false);
}; };
// TODO: Needs to be done after orig icon loads // TODO: Needs to be done after orig icon loads
setTimeout(function () { setTimeout(function () {
// Create source save/cancel buttons // Create source save/cancel buttons
/* var save = */ $('#tool_source_save').clone() /* var save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind() .hide().attr('id', 'foreign_save').unbind()
.appendTo('#tool_source_back').click(function () { .appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; } if (!editingforeign) { return; }
if (!setForeignString($('#svg_source_textarea').val())) { if (!setForeignString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) { $.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) { return false; } if (!ok) { return false; }
endChanges(); endChanges();
}); });
} else { } else {
endChanges(); endChanges();
} }
// setSelectMode(); // setSelectMode();
}); });
/* var cancel = */ $('#tool_source_cancel').clone() /* var cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind() .hide().attr('id', 'foreign_cancel').unbind()
.appendTo('#tool_source_back').click(function () { .appendTo('#tool_source_back').click(function () {
endChanges(); endChanges();
}); });
}, 3000); }, 3000);
}, },
mouseDown: function (opts) { mouseDown: function (opts) {
// var e = opts.event; // var e = opts.event;
if (svgCanvas.getMode() === 'foreign') { if (svgCanvas.getMode() === 'foreign') {
started = true; started = true;
newFO = S.addSvgElementFromJson({ newFO = S.addSvgElementFromJson({
'element': 'foreignObject', 'element': 'foreignObject',
'attr': { 'attr': {
'x': opts.start_x, 'x': opts.start_x,
'y': opts.start_y, 'y': opts.start_y,
'id': S.getNextId(), 'id': S.getNextId(),
'font-size': 16, // cur_text.font_size, 'font-size': 16, // cur_text.font_size,
'width': '48', 'width': '48',
'height': '20', 'height': '20',
'style': 'pointer-events:inherit' 'style': 'pointer-events:inherit'
} }
}); });
var m = svgdoc.createElementNS(NS.MATH, 'math'); var m = svgdoc.createElementNS(NS.MATH, 'math');
m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
m.setAttribute('display', 'inline'); m.setAttribute('display', 'inline');
var mi = svgdoc.createElementNS(NS.MATH, 'mi'); var mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal'); mi.setAttribute('mathvariant', 'normal');
mi.textContent = '\u03A6'; mi.textContent = '\u03A6';
var mo = svgdoc.createElementNS(NS.MATH, 'mo'); var mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = '\u222A'; mo.textContent = '\u222A';
var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = '\u2133'; mi2.textContent = '\u2133';
m.appendChild(mi); m.appendChild(mi);
m.appendChild(mo); m.appendChild(mo);
m.appendChild(mi2); m.appendChild(mi2);
newFO.appendChild(m); newFO.appendChild(m);
return { return {
started: true started: true
}; };
} }
}, },
mouseUp: function (opts) { mouseUp: function (opts) {
// var e = opts.event; // var e = opts.event;
if (svgCanvas.getMode() === 'foreign' && started) { if (svgCanvas.getMode() === 'foreign' && started) {
var attrs = $(newFO).attr(['width', 'height']); var attrs = $(newFO).attr(['width', 'height']);
var keep = (attrs.width !== '0' || attrs.height !== '0'); var keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true); svgCanvas.addToSelection([newFO], true);
return { return {
keep: keep, keep: keep,
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && elem.tagName === 'foreignObject') { if (elem && elem.tagName === 'foreignObject') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute('font-size')); $('#foreign_font_size').val(elem.getAttribute('font-size'));
$('#foreign_width').val(elem.getAttribute('width')); $('#foreign_width').val(elem.getAttribute('width'));
$('#foreign_height').val(elem.getAttribute('height')); $('#foreign_height').val(elem.getAttribute('height'));
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
} }
} else { } else {
showPanel(false); showPanel(false);
} }
} }
}, },
elementChanged: function (opts) { elementChanged: function (opts) {
// var elem = opts.elems[0]; // var elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -15,149 +15,149 @@
// 2) everything else // 2) everything else
svgEditor.addExtension('view_grid', function () { svgEditor.addExtension('view_grid', function () {
'use strict'; 'use strict';
var NS = svgedit.NS, var NS = svgedit.NS,
svgdoc = document.getElementById('svgcanvas').ownerDocument, svgdoc = document.getElementById('svgcanvas').ownerDocument,
showGrid = svgEditor.curConfig.showGrid || false, showGrid = svgEditor.curConfig.showGrid || false,
assignAttributes = svgCanvas.assignAttributes, assignAttributes = svgCanvas.assignAttributes,
hcanvas = document.createElement('canvas'), hcanvas = document.createElement('canvas'),
canvBG = $('#canvasBackground'), canvBG = $('#canvasBackground'),
units = svgedit.units.getTypeMap(), units = svgedit.units.getTypeMap(),
intervals = [0.01, 0.1, 1, 10, 100, 1000]; intervals = [0.01, 0.1, 1, 10, 100, 1000];
$(hcanvas).hide().appendTo('body'); $(hcanvas).hide().appendTo('body');
var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
assignAttributes(canvasGrid, { assignAttributes(canvasGrid, {
'id': 'canvasGrid', 'id': 'canvasGrid',
'width': '100%', 'width': '100%',
'height': '100%', 'height': '100%',
'x': 0, 'x': 0,
'y': 0, 'y': 0,
'overflow': 'visible', 'overflow': 'visible',
'display': 'none' 'display': 'none'
}); });
canvBG.append(canvasGrid); canvBG.append(canvasGrid);
// grid-pattern // grid-pattern
var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
assignAttributes(gridPattern, { assignAttributes(gridPattern, {
'id': 'gridpattern', 'id': 'gridpattern',
'patternUnits': 'userSpaceOnUse', 'patternUnits': 'userSpaceOnUse',
'x': 0, // -(value.strokeWidth / 2), // position for strokewidth 'x': 0, // -(value.strokeWidth / 2), // position for strokewidth
'y': 0, // -(value.strokeWidth / 2), // position for strokewidth 'y': 0, // -(value.strokeWidth / 2), // position for strokewidth
'width': 100, 'width': 100,
'height': 100 'height': 100
}); });
var gridimg = svgdoc.createElementNS(NS.SVG, 'image'); var gridimg = svgdoc.createElementNS(NS.SVG, 'image');
assignAttributes(gridimg, { assignAttributes(gridimg, {
'x': 0, 'x': 0,
'y': 0, 'y': 0,
'width': 100, 'width': 100,
'height': 100 'height': 100
}); });
gridPattern.appendChild(gridimg); gridPattern.appendChild(gridimg);
$('#svgroot defs').append(gridPattern); $('#svgroot defs').append(gridPattern);
// grid-box // grid-box
var gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); var gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
assignAttributes(gridBox, { assignAttributes(gridBox, {
'width': '100%', 'width': '100%',
'height': '100%', 'height': '100%',
'x': 0, 'x': 0,
'y': 0, 'y': 0,
'stroke-width': 0, 'stroke-width': 0,
'stroke': 'none', 'stroke': 'none',
'fill': 'url(#gridpattern)', 'fill': 'url(#gridpattern)',
'style': 'pointer-events: none; display:visible;' 'style': 'pointer-events: none; display:visible;'
}); });
$('#canvasGrid').append(gridBox); $('#canvasGrid').append(gridBox);
function updateGrid (zoom) { function updateGrid (zoom) {
var i; var i;
// TODO: Try this with <line> elements, then compare performance difference // TODO: Try this with <line> elements, then compare performance difference
var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
var uMulti = unit * zoom; var uMulti = unit * zoom;
// Calculate the main number interval // Calculate the main number interval
var rawM = 100 / uMulti; var rawM = 100 / uMulti;
var multi = 1; var multi = 1;
for (i = 0; i < intervals.length; i++) { for (i = 0; i < intervals.length; i++) {
var num = intervals[i]; var num = intervals[i];
multi = num; multi = num;
if (rawM <= num) { if (rawM <= num) {
break; break;
} }
} }
var bigInt = multi * uMulti; var bigInt = multi * uMulti;
// Set the canvas size to the width of the container // Set the canvas size to the width of the container
hcanvas.width = bigInt; hcanvas.width = bigInt;
hcanvas.height = bigInt; hcanvas.height = bigInt;
var ctx = hcanvas.getContext('2d'); var ctx = hcanvas.getContext('2d');
var curD = 0.5; var curD = 0.5;
var part = bigInt / 10; var part = bigInt / 10;
ctx.globalAlpha = 0.2; ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor; ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (i = 1; i < 10; i++) { for (i = 1; i < 10; i++) {
var subD = Math.round(part * i) + 0.5; var subD = Math.round(part * i) + 0.5;
// var lineNum = (i % 2)?12:10; // var lineNum = (i % 2)?12:10;
var lineNum = 0; var lineNum = 0;
ctx.moveTo(subD, bigInt); ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum); ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD); ctx.moveTo(bigInt, subD);
ctx.lineTo(lineNum, subD); ctx.lineTo(lineNum, subD);
} }
ctx.stroke(); ctx.stroke();
ctx.beginPath(); ctx.beginPath();
ctx.globalAlpha = 0.5; ctx.globalAlpha = 0.5;
ctx.moveTo(curD, bigInt); ctx.moveTo(curD, bigInt);
ctx.lineTo(curD, 0); ctx.lineTo(curD, 0);
ctx.moveTo(bigInt, curD); ctx.moveTo(bigInt, curD);
ctx.lineTo(0, curD); ctx.lineTo(0, curD);
ctx.stroke(); ctx.stroke();
var datauri = hcanvas.toDataURL('image/png'); var datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', bigInt); gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt); gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt); gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', bigInt); gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri); svgCanvas.setHref(gridimg, datauri);
} }
function gridUpdate () { function gridUpdate () {
if (showGrid) { if (showGrid) {
updateGrid(svgCanvas.getZoom()); updateGrid(svgCanvas.getZoom());
} }
$('#canvasGrid').toggle(showGrid); $('#canvasGrid').toggle(showGrid);
$('#view_grid').toggleClass('push_button_pressed tool_button'); $('#view_grid').toggleClass('push_button_pressed tool_button');
} }
return { return {
name: 'view_grid', name: 'view_grid',
svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml', svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
zoomChanged: function (zoom) { zoomChanged: function (zoom) {
if (showGrid) { updateGrid(zoom); } if (showGrid) { updateGrid(zoom); }
}, },
callback: function () { callback: function () {
if (showGrid) { if (showGrid) {
gridUpdate(); gridUpdate();
} }
}, },
buttons: [{ buttons: [{
id: 'view_grid', id: 'view_grid',
type: 'context', type: 'context',
panel: 'editor_panel', panel: 'editor_panel',
title: 'Show/Hide Grid', title: 'Show/Hide Grid',
events: { events: {
click: function () { click: function () {
svgEditor.curConfig.showGrid = showGrid = !showGrid; svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate(); gridUpdate();
} }
} }
}] }]
}; };
}); });

View File

@@ -10,70 +10,70 @@
*/ */
/* /*
This is a very basic SVG-Edit extension. It adds a "Hello World" button in This is a very basic SVG-Edit extension. It adds a "Hello World" button in
the left panel. Clicking on the button, and then the canvas will show the the left panel. Clicking on the button, and then the canvas will show the
user the point on the canvas that was clicked on. user the point on the canvas that was clicked on.
*/ */
svgEditor.addExtension('Hello World', function () { svgEditor.addExtension('Hello World', function () {
'use strict'; 'use strict';
return { return {
name: 'Hello World', name: 'Hello World',
// For more notes on how to make an icon file, see the source of // For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml // the helloworld-icon.xml
svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml', svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml',
// Multiple buttons can be added in this array // Multiple buttons can be added in this array
buttons: [{ buttons: [{
// Must match the icon ID in helloworld-icon.xml // Must match the icon ID in helloworld-icon.xml
id: 'hello_world', id: 'hello_world',
// This indicates that the button will be added to the "mode" // This indicates that the button will be added to the "mode"
// button panel on the left side // button panel on the left side
type: 'mode', type: 'mode',
// Tooltip text // Tooltip text
title: "Say 'Hello World'", title: "Say 'Hello World'",
// Events // Events
events: { events: {
'click': function () { 'click': function () {
// The action taken when the button is clicked on. // The action taken when the button is clicked on.
// For "mode" buttons, any other button will // For "mode" buttons, any other button will
// automatically be de-pressed. // automatically be de-pressed.
svgCanvas.setMode('hello_world'); svgCanvas.setMode('hello_world');
} }
} }
}], }],
// This is triggered when the main mouse button is pressed down // This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels) // on the editor canvas (not the tool panels)
mouseDown: function () { mouseDown: function () {
// Check the mode on mousedown // Check the mode on mousedown
if (svgCanvas.getMode() === 'hello_world') { if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with // The returned object must include "started" with
// a value of true in order for mouseUp to be triggered // a value of true in order for mouseUp to be triggered
return {started: true}; return {started: true};
} }
}, },
// This is triggered from anywhere, but "started" must have been set // This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info // to true (see above). Note that "opts" is an object with event info
mouseUp: function (opts) { mouseUp: function (opts) {
// Check the mode on mouseup // Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') { if (svgCanvas.getMode() === 'hello_world') {
var zoom = svgCanvas.getZoom(); var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value // Get the actual coordinate by dividing by the zoom value
var x = opts.mouse_x / zoom; var x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom; var y = opts.mouse_y / zoom;
var text = 'Hello World!\n\nYou clicked here: ' + var text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y; x + ', ' + y;
// Show the text using the custom alert function // Show the text using the custom alert function
$.alert(text); $.alert(text);
} }
} }
}; };
}); });

View File

@@ -10,447 +10,447 @@
*/ */
svgEditor.addExtension('imagelib', function () { svgEditor.addExtension('imagelib', function () {
'use strict'; 'use strict';
var uiStrings = svgEditor.uiStrings; var uiStrings = svgEditor.uiStrings;
$.extend(uiStrings, { $.extend(uiStrings, {
imagelib: { imagelib: {
select_lib: 'Select an image library', select_lib: 'Select an image library',
show_list: 'Show library list', show_list: 'Show library list',
import_single: 'Import single', import_single: 'Import single',
import_multi: 'Import multiple', import_multi: 'Import multiple',
open: 'Open as new document' open: 'Open as new document'
} }
}); });
var imgLibs = [ var imgLibs = [
{ {
name: 'Demo library (local)', name: 'Demo library (local)',
url: svgEditor.curConfig.extPath + 'imagelib/index.html', url: svgEditor.curConfig.extPath + 'imagelib/index.html',
description: 'Demonstration library for SVG-edit on this server' description: 'Demonstration library for SVG-edit on this server'
}, },
{ {
name: 'IAN Symbol Libraries', name: 'IAN Symbol Libraries',
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php', url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
description: 'Free library of illustrations' description: 'Free library of illustrations'
}, },
{ {
name: 'Openclipart', name: 'Openclipart',
url: 'https://openclipart.org/svgedit', url: 'https://openclipart.org/svgedit',
description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.' description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.'
} }
]; ];
function closeBrowser () { function closeBrowser () {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
} }
function importImage (url) { function importImage (url) {
var newImage = svgCanvas.addSvgElementFromJson({ var newImage = svgCanvas.addSvgElementFromJson({
'element': 'image', 'element': 'image',
'attr': { 'attr': {
'x': 0, 'x': 0,
'y': 0, 'y': 0,
'width': 0, 'width': 0,
'height': 0, 'height': 0,
'id': svgCanvas.getNextId(), 'id': svgCanvas.getNextId(),
'style': 'pointer-events:inherit' 'style': 'pointer-events:inherit'
} }
}); });
svgCanvas.clearSelection(); svgCanvas.clearSelection();
svgCanvas.addToSelection([newImage]); svgCanvas.addToSelection([newImage]);
svgCanvas.setImageURL(url); svgCanvas.setImageURL(url);
} }
var mode = 's'; var mode = 's';
var multiArr = []; var multiArr = [];
var transferStopped = false; var transferStopped = false;
var pending = {}; var pending = {};
var preview, submit; var preview, submit;
window.addEventListener('message', function (evt) { window.addEventListener('message', function (evt) {
// Receive postMessage data // Receive postMessage data
var response = evt.data; var response = evt.data;
if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here
// Do nothing // Do nothing
return; return;
} }
try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed) try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed)
var res = JSON.parse(response); var res = JSON.parse(response);
if (res.namespace) { // Part of embedAPI communications if (res.namespace) { // Part of embedAPI communications
return; return;
} }
} catch (e) {} } catch (e) {}
var char1 = response.charAt(0); var char1 = response.charAt(0);
var id; var id;
var svgStr; var svgStr;
var imgStr; var imgStr;
if (char1 !== '{' && transferStopped) { if (char1 !== '{' && transferStopped) {
transferStopped = false; transferStopped = false;
return; return;
} }
if (char1 === '|') { if (char1 === '|') {
var secondpos = response.indexOf('|', 1); var secondpos = response.indexOf('|', 1);
id = response.substr(1, secondpos - 1); id = response.substr(1, secondpos - 1);
response = response.substr(secondpos + 1); response = response.substr(secondpos + 1);
char1 = response.charAt(0); char1 = response.charAt(0);
} }
// Hide possible transfer dialog box // Hide possible transfer dialog box
$('#dialog_box').hide(); $('#dialog_box').hide();
var entry, curMeta; var entry, curMeta;
switch (char1) { switch (char1) {
case '{': case '{':
// Metadata // Metadata
transferStopped = false; transferStopped = false;
curMeta = JSON.parse(response); curMeta = JSON.parse(response);
pending[curMeta.id] = curMeta; pending[curMeta.id] = curMeta;
var name = (curMeta.name || 'file'); var name = (curMeta.name || 'file');
var message = uiStrings.notification.retrieving.replace('%s', name); var message = uiStrings.notification.retrieving.replace('%s', name);
if (mode !== 'm') { if (mode !== 'm') {
$.process_cancel(message, function () { $.process_cancel(message, function () {
transferStopped = true; transferStopped = true;
// Should a message be sent back to the frame? // Should a message be sent back to the frame?
$('#dialog_box').hide(); $('#dialog_box').hide();
}); });
} else { } else {
entry = $('<div>' + message + '</div>').data('id', curMeta.id); entry = $('<div>' + message + '</div>').data('id', curMeta.id);
preview.append(entry); preview.append(entry);
curMeta.entry = entry; curMeta.entry = entry;
} }
return; return;
case '<': case '<':
svgStr = true; svgStr = true;
break; break;
case 'd': case 'd':
if (response.indexOf('data:image/svg+xml') === 0) { if (response.indexOf('data:image/svg+xml') === 0) {
var pre = 'data:image/svg+xml;base64,'; var pre = 'data:image/svg+xml;base64,';
var src = response.substring(pre.length); var src = response.substring(pre.length);
response = svgedit.utilities.decode64(src); response = svgedit.utilities.decode64(src);
svgStr = true; svgStr = true;
break; break;
} else if (response.indexOf('data:image/') === 0) { } else if (response.indexOf('data:image/') === 0) {
imgStr = true; imgStr = true;
break; break;
} }
// Else fall through // Else fall through
default: default:
// TODO: See if there's a way to base64 encode the binary data stream // TODO: See if there's a way to base64 encode the binary data stream
// var str = 'data:;base64,' + svgedit.utilities.encode64(response, true); // var str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data // Assume it's raw image data
// importImage(str); // importImage(str);
// Don't give warning as postMessage may have been used by something else // Don't give warning as postMessage may have been used by something else
if (mode !== 'm') { if (mode !== 'm') {
closeBrowser(); closeBrowser();
} else { } else {
pending[id].entry.remove(); pending[id].entry.remove();
} }
// $.alert('Unexpected data was returned: ' + response, function() { // $.alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') { // if (mode !== 'm') {
// closeBrowser(); // closeBrowser();
// } else { // } else {
// pending[id].entry.remove(); // pending[id].entry.remove();
// } // }
// }); // });
return; return;
} }
switch (mode) { switch (mode) {
case 's': case 's':
// Import one // Import one
if (svgStr) { if (svgStr) {
svgCanvas.importSvgString(response); svgCanvas.importSvgString(response);
} else if (imgStr) { } else if (imgStr) {
importImage(response); importImage(response);
} }
closeBrowser(); closeBrowser();
break; break;
case 'm': case 'm':
// Import multiple // Import multiple
multiArr.push([(svgStr ? 'svg' : 'img'), response]); multiArr.push([(svgStr ? 'svg' : 'img'), response]);
var title; var title;
curMeta = pending[id]; curMeta = pending[id];
if (svgStr) { if (svgStr) {
if (curMeta && curMeta.name) { if (curMeta && curMeta.name) {
title = curMeta.name; title = curMeta.name;
} else { } else {
// Try to find a title // Try to find a title
var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement; var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')'; title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
} }
if (curMeta) { if (curMeta) {
preview.children().each(function () { preview.children().each(function () {
if ($(this).data('id') === id) { if ($(this).data('id') === id) {
if (curMeta.preview_url) { if (curMeta.preview_url) {
$(this).html('<img src="' + curMeta.preview_url + '">' + title); $(this).html('<img src="' + curMeta.preview_url + '">' + title);
} else { } else {
$(this).text(title); $(this).text(title);
} }
submit.removeAttr('disabled'); submit.removeAttr('disabled');
} }
}); });
} else { } else {
preview.append('<div>' + title + '</div>'); preview.append('<div>' + title + '</div>');
submit.removeAttr('disabled'); submit.removeAttr('disabled');
} }
} else { } else {
if (curMeta && curMeta.preview_url) { if (curMeta && curMeta.preview_url) {
title = curMeta.name || ''; title = curMeta.name || '';
} }
if (curMeta && curMeta.preview_url) { if (curMeta && curMeta.preview_url) {
entry = '<img src="' + curMeta.preview_url + '">' + title; entry = '<img src="' + curMeta.preview_url + '">' + title;
} else { } else {
entry = '<img src="' + response + '">'; entry = '<img src="' + response + '">';
} }
if (curMeta) { if (curMeta) {
preview.children().each(function () { preview.children().each(function () {
if ($(this).data('id') === id) { if ($(this).data('id') === id) {
$(this).html(entry); $(this).html(entry);
submit.removeAttr('disabled'); submit.removeAttr('disabled');
} }
}); });
} else { } else {
preview.append($('<div>').append(entry)); preview.append($('<div>').append(entry));
submit.removeAttr('disabled'); submit.removeAttr('disabled');
} }
} }
break; break;
case 'o': case 'o':
// Open // Open
if (!svgStr) { break; } if (!svgStr) { break; }
svgEditor.openPrep(function (ok) { svgEditor.openPrep(function (ok) {
if (!ok) { return; } if (!ok) { return; }
svgCanvas.clear(); svgCanvas.clear();
svgCanvas.setSvgString(response); svgCanvas.setSvgString(response);
// updateCanvas(); // updateCanvas();
}); });
closeBrowser(); closeBrowser();
break; break;
} }
}, true); }, true);
function toggleMulti (show) { function toggleMulti (show) {
$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)}); $('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
if (!preview) { if (!preview) {
preview = $('<div id=imglib_preview>').css({ preview = $('<div id=imglib_preview>').css({
position: 'absolute', position: 'absolute',
top: 45, top: 45,
right: 10, right: 10,
width: 180, width: 180,
bottom: 45, bottom: 45,
background: '#fff', background: '#fff',
overflow: 'auto' overflow: 'auto'
}).insertAfter('#lib_framewrap'); }).insertAfter('#lib_framewrap');
submit = $('<button disabled>Import selected</button>') submit = $('<button disabled>Import selected</button>')
.appendTo('#imgbrowse') .appendTo('#imgbrowse')
.on('click touchend', function () { .on('click touchend', function () {
$.each(multiArr, function (i) { $.each(multiArr, function (i) {
var type = this[0]; var type = this[0];
var data = this[1]; var data = this[1];
if (type === 'svg') { if (type === 'svg') {
svgCanvas.importSvgString(data); svgCanvas.importSvgString(data);
} else { } else {
importImage(data); importImage(data);
} }
svgCanvas.moveSelectedElements(i * 20, i * 20, false); svgCanvas.moveSelectedElements(i * 20, i * 20, false);
}); });
preview.empty(); preview.empty();
multiArr = []; multiArr = [];
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
}).css({ }).css({
position: 'absolute', position: 'absolute',
bottom: 10, bottom: 10,
right: -10 right: -10
}); });
} }
preview.toggle(show); preview.toggle(show);
submit.toggle(show); submit.toggle(show);
} }
function showBrowser () { function showBrowser () {
var browser = $('#imgbrowse'); var browser = $('#imgbrowse');
if (!browser.length) { if (!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' + $('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
'</div></div>').insertAfter('#svg_docprops'); '</div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse'); browser = $('#imgbrowse');
var allLibs = uiStrings.imagelib.select_lib; var allLibs = uiStrings.imagelib.select_lib;
var libOpts = $('<ul id=imglib_opts>').appendTo(browser); var libOpts = $('<ul id=imglib_opts>').appendTo(browser);
var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>'); var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
var header = $('<h1>').prependTo(browser).text(allLibs).css({ var header = $('<h1>').prependTo(browser).text(allLibs).css({
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
width: '100%' width: '100%'
}); });
var cancel = $('<button>' + uiStrings.common.cancel + '</button>') var cancel = $('<button>' + uiStrings.common.cancel + '</button>')
.appendTo(browser) .appendTo(browser)
.on('click touchend', function () { .on('click touchend', function () {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
}).css({ }).css({
position: 'absolute', position: 'absolute',
top: 5, top: 5,
right: -10 right: -10
}); });
var leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser); var leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>') var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
.appendTo(leftBlock) .appendTo(leftBlock)
.on('click touchend', function () { .on('click touchend', function () {
frame.attr('src', 'about:blank').hide(); frame.attr('src', 'about:blank').hide();
libOpts.show(); libOpts.show();
header.text(allLibs); header.text(allLibs);
back.hide(); back.hide();
}).css({ }).css({
'margin-right': 5 'margin-right': 5
}).hide(); }).hide();
/* var type = */ $('<select><option value=s>' + /* var type = */ $('<select><option value=s>' +
uiStrings.imagelib.import_single + '</option><option value=m>' + uiStrings.imagelib.import_single + '</option><option value=m>' +
uiStrings.imagelib.import_multi + '</option><option value=o>' + uiStrings.imagelib.import_multi + '</option><option value=o>' +
uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () { uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () {
mode = $(this).val(); mode = $(this).val();
switch (mode) { switch (mode) {
case 's': case 's':
case 'o': case 'o':
toggleMulti(false); toggleMulti(false);
break; break;
case 'm': case 'm':
// Import multiple // Import multiple
toggleMulti(true); toggleMulti(true);
break; break;
} }
}).css({ }).css({
'margin-top': 10 'margin-top': 10
}); });
cancel.prepend($.getSvgIcon('cancel', true)); cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true)); back.prepend($.getSvgIcon('tool_imagelib', true));
$.each(imgLibs, function (i, opts) { $.each(imgLibs, function (i, opts) {
$('<li>') $('<li>')
.appendTo(libOpts) .appendTo(libOpts)
.text(opts.name) .text(opts.name)
.on('click touchend', function () { .on('click touchend', function () {
frame.attr('src', opts.url).show(); frame.attr('src', opts.url).show();
header.text(opts.name); header.text(opts.name);
libOpts.hide(); libOpts.hide();
back.show(); back.show();
}).append('<span>' + opts.description + '</span>'); }).append('<span>' + opts.description + '</span>');
}); });
} else { } else {
$('#imgbrowse_holder').show(); $('#imgbrowse_holder').show();
} }
} }
return { return {
svgicons: svgEditor.curConfig.extPath + 'ext-imagelib.xml', svgicons: svgEditor.curConfig.extPath + 'ext-imagelib.xml',
buttons: [{ buttons: [{
id: 'tool_imagelib', id: 'tool_imagelib',
type: 'app_menu', // _flyout type: 'app_menu', // _flyout
position: 4, position: 4,
title: 'Image library', title: 'Image library',
events: { events: {
'mouseup': showBrowser 'mouseup': showBrowser
} }
}], }],
callback: function () { callback: function () {
$('<style>').text( $('<style>').text(
'#imgbrowse_holder {' + '#imgbrowse_holder {' +
'position: absolute;' + 'position: absolute;' +
'top: 0;' + 'top: 0;' +
'left: 0;' + 'left: 0;' +
'width: 100%;' + 'width: 100%;' +
'height: 100%;' + 'height: 100%;' +
'background-color: rgba(0, 0, 0, .5);' + 'background-color: rgba(0, 0, 0, .5);' +
'z-index: 5;' + 'z-index: 5;' +
'}' + '}' +
'#imgbrowse {' + '#imgbrowse {' +
'position: absolute;' + 'position: absolute;' +
'top: 25px;' + 'top: 25px;' +
'left: 25px;' + 'left: 25px;' +
'right: 25px;' + 'right: 25px;' +
'bottom: 25px;' + 'bottom: 25px;' +
'min-width: 300px;' + 'min-width: 300px;' +
'min-height: 200px;' + 'min-height: 200px;' +
'background: #B0B0B0;' + 'background: #B0B0B0;' +
'border: 1px outset #777;' + 'border: 1px outset #777;' +
'}' + '}' +
'#imgbrowse h1 {' + '#imgbrowse h1 {' +
'font-size: 20px;' + 'font-size: 20px;' +
'margin: .4em;' + 'margin: .4em;' +
'text-align: center;' + 'text-align: center;' +
'}' + '}' +
'#lib_framewrap,' + '#lib_framewrap,' +
'#imgbrowse > ul {' + '#imgbrowse > ul {' +
'position: absolute;' + 'position: absolute;' +
'top: 45px;' + 'top: 45px;' +
'left: 10px;' + 'left: 10px;' +
'right: 10px;' + 'right: 10px;' +
'bottom: 10px;' + 'bottom: 10px;' +
'background: white;' + 'background: white;' +
'margin: 0;' + 'margin: 0;' +
'padding: 0;' + 'padding: 0;' +
'}' + '}' +
'#imgbrowse > ul {' + '#imgbrowse > ul {' +
'overflow: auto;' + 'overflow: auto;' +
'}' + '}' +
'#imgbrowse > div {' + '#imgbrowse > div {' +
'border: 1px solid #666;' + 'border: 1px solid #666;' +
'}' + '}' +
'#imglib_preview > div {' + '#imglib_preview > div {' +
'padding: 5px;' + 'padding: 5px;' +
'font-size: 12px;' + 'font-size: 12px;' +
'}' + '}' +
'#imglib_preview img {' + '#imglib_preview img {' +
'display: block;' + 'display: block;' +
'margin: 0 auto;' + 'margin: 0 auto;' +
'max-height: 100px;' + 'max-height: 100px;' +
'}' + '}' +
'#imgbrowse li {' + '#imgbrowse li {' +
'list-style: none;' + 'list-style: none;' +
'padding: .5em;' + 'padding: .5em;' +
'background: #E8E8E8;' + 'background: #E8E8E8;' +
'border-bottom: 1px solid #B0B0B0;' + 'border-bottom: 1px solid #B0B0B0;' +
'line-height: 1.2em;' + 'line-height: 1.2em;' +
'font-style: sans-serif;' + 'font-style: sans-serif;' +
'}' + '}' +
'#imgbrowse li > span {' + '#imgbrowse li > span {' +
'color: #666;' + 'color: #666;' +
'font-size: 15px;' + 'font-size: 15px;' +
'display: block;' + 'display: block;' +
'}' + '}' +
'#imgbrowse li:hover {' + '#imgbrowse li:hover {' +
'background: #FFC;' + 'background: #FFC;' +
'cursor: pointer;' + 'cursor: pointer;' +
'}' + '}' +
'#imgbrowse iframe {' + '#imgbrowse iframe {' +
'width: 100%;' + 'width: 100%;' +
'height: 100%;' + 'height: 100%;' +
'border: 0;' + 'border: 0;' +
'}' '}'
).appendTo('head'); ).appendTo('head');
} }
}; };
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -10,255 +10,255 @@
*/ */
svgEditor.addExtension('mathjax', function () { svgEditor.addExtension('mathjax', function () {
'use strict'; 'use strict';
// Configuration of the MathJax extention. // Configuration of the MathJax extention.
// This will be added to the head tag before MathJax is loaded. // This will be added to the head tag before MathJax is loaded.
var /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\ var /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\
MathJax.Hub.Config({\ MathJax.Hub.Config({\
extensions: ["tex2jax.js"],\ extensions: ["tex2jax.js"],\
jax: ["input/TeX","output/SVG"],\ jax: ["input/TeX","output/SVG"],\
showProcessingMessages: true,\ showProcessingMessages: true,\
showMathMenu: false,\ showMathMenu: false,\
showMathMenuMSIE: false,\ showMathMenuMSIE: false,\
errorSettings: {\ errorSettings: {\
message: ["[Math Processing Error]"],\ message: ["[Math Processing Error]"],\
style: {color: "#CC0000", "font-style":"italic"}\ style: {color: "#CC0000", "font-style":"italic"}\
},\ },\
elements: [],\ elements: [],\
tex2jax: {\ tex2jax: {\
ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\ ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
},\ },\
TeX: {\ TeX: {\
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\ extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
},\ },\
"SVG": {\ "SVG": {\
}\ }\
});\ });\
</script>', */ </script>', */
// mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js', // mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js', mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js',
math, math,
locationX, locationX,
locationY, locationY,
mathjaxLoaded = false, mathjaxLoaded = false,
uiStrings = svgEditor.uiStrings; uiStrings = svgEditor.uiStrings;
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback. // TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
$.extend(uiStrings, { $.extend(uiStrings, {
mathjax: { mathjax: {
embed_svg: 'Save as mathematics', embed_svg: 'Save as mathematics',
embed_mathml: 'Save as figure', embed_mathml: 'Save as figure',
svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ', svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ',
mathml_save_warning: 'Advised. The math will be saved as a figure.', mathml_save_warning: 'Advised. The math will be saved as a figure.',
title: 'Mathematics code editor' title: 'Mathematics code editor'
} }
}); });
function saveMath () { function saveMath () {
var code = $('#mathjax_code_textarea').val(); var code = $('#mathjax_code_textarea').val();
// displaystyle to force MathJax NOT to use the inline style. Because it is // displaystyle to force MathJax NOT to use the inline style. Because it is
// less fancy! // less fancy!
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']); MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
/* /*
* The MathJax library doesn't want to bloat your webpage so it creates * The MathJax library doesn't want to bloat your webpage so it creates
* every symbol (glymph) you need only once. These are saved in a <svg> on * every symbol (glymph) you need only once. These are saved in a <svg> on
* the top of your html document, just under the body tag. Each glymph has * the top of your html document, just under the body tag. Each glymph has
* its unique id and is saved as a <path> in the <defs> tag of the <svg> * its unique id and is saved as a <path> in the <defs> tag of the <svg>
* *
* Then when the symbols are needed in the rest of your html document they * Then when the symbols are needed in the rest of your html document they
* are refferd to by a <use> tag. * are refferd to by a <use> tag.
* Because of bug 1076 we can't just grab the defs tag on the top and add it * Because of bug 1076 we can't just grab the defs tag on the top and add it
* to your formula's <svg> and copy the lot. So we have to replace each * to your formula's <svg> and copy the lot. So we have to replace each
* <use> tag by it's <path>. * <use> tag by it's <path>.
*/ */
MathJax.Hub.queue.Push( MathJax.Hub.queue.Push(
function () { function () {
var mathjaxMath = $('.MathJax_SVG'); var mathjaxMath = $('.MathJax_SVG');
var svg = $(mathjaxMath.html()); var svg = $(mathjaxMath.html());
svg.find('use').each(function () { svg.find('use').each(function () {
var x, y, id, transform; var x, y, id, transform;
// TODO: find a less pragmatic and more elegant solution to this. // TODO: find a less pragmatic and more elegant solution to this.
if ($(this).attr('href')) { if ($(this).attr('href')) {
id = $(this).attr('href').slice(1); // Works in Chrome. id = $(this).attr('href').slice(1); // Works in Chrome.
} else { } else {
id = $(this).attr('xlink:href').slice(1); // Works in Firefox. id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
} }
var glymph = $('#' + id).clone().removeAttr('id'); var glymph = $('#' + id).clone().removeAttr('id');
x = $(this).attr('x'); x = $(this).attr('x');
y = $(this).attr('y'); y = $(this).attr('y');
transform = $(this).attr('transform'); transform = $(this).attr('transform');
if (transform && (x || y)) { if (transform && (x || y)) {
glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')'); glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
} else if (transform) { } else if (transform) {
glymph.attr('transform', transform); glymph.attr('transform', transform);
} else if (x || y) { } else if (x || y) {
glymph.attr('transform', 'translate(' + x + ',' + y + ')'); glymph.attr('transform', 'translate(' + x + ',' + y + ')');
} }
$(this).replaceWith(glymph); $(this).replaceWith(glymph);
}); });
// Remove the style tag because it interferes with SVG-Edit. // Remove the style tag because it interferes with SVG-Edit.
svg.removeAttr('style'); svg.removeAttr('style');
svg.attr('xmlns', 'http://www.w3.org/2000/svg'); svg.attr('xmlns', 'http://www.w3.org/2000/svg');
svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true); svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true);
svgCanvas.ungroupSelectedElement(); svgCanvas.ungroupSelectedElement();
// TODO: To undo the adding of the Formula you now have to undo twice. // TODO: To undo the adding of the Formula you now have to undo twice.
// This should only be once! // This should only be once!
svgCanvas.moveSelectedElements(locationX, locationY, true); svgCanvas.moveSelectedElements(locationX, locationY, true);
} }
); );
} }
return { return {
name: 'MathJax', name: 'MathJax',
svgicons: svgEditor.curConfig.extPath + 'mathjax-icons.xml', svgicons: svgEditor.curConfig.extPath + 'mathjax-icons.xml',
buttons: [{ buttons: [{
id: 'tool_mathjax', id: 'tool_mathjax',
type: 'mode', type: 'mode',
title: 'Add Mathematics', title: 'Add Mathematics',
events: { events: {
click: function () { click: function () {
// Only load Mathjax when needed, we don't want to strain Svg-Edit any more. // Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
// From this point on it is very probable that it will be needed, so load it. // From this point on it is very probable that it will be needed, so load it.
if (mathjaxLoaded === false) { if (mathjaxLoaded === false) {
$('<div id="mathjax">' + $('<div id="mathjax">' +
'<!-- Here is where MathJax creates the math -->' + '<!-- Here is where MathJax creates the math -->' +
'<div id="mathjax_creator" class="tex2jax_process" style="display:none">' + '<div id="mathjax_creator" class="tex2jax_process" style="display:none">' +
'$${}$$' + '$${}$$' +
'</div>' + '</div>' +
'<div id="mathjax_overlay"></div>' + '<div id="mathjax_overlay"></div>' +
'<div id="mathjax_container">' + '<div id="mathjax_container">' +
'<div id="tool_mathjax_back" class="toolbar_button">' + '<div id="tool_mathjax_back" class="toolbar_button">' +
'<button id="tool_mathjax_save">OK</button>' + '<button id="tool_mathjax_save">OK</button>' +
'<button id="tool_mathjax_cancel">Cancel</button>' + '<button id="tool_mathjax_cancel">Cancel</button>' +
'</div>' + '</div>' +
'<fieldset>' + '<fieldset>' +
'<legend id="mathjax_legend">Mathematics Editor</legend>' + '<legend id="mathjax_legend">Mathematics Editor</legend>' +
'<label>' + '<label>' +
'<span id="mathjax_explication">Please type your mathematics in ' + '<span id="mathjax_explication">Please type your mathematics in ' +
'<a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>' + '<a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>' +
'<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>' + '<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>' +
'</fieldset>' + '</fieldset>' +
'</div>' + '</div>' +
'</div>' '</div>'
).insertAfter('#svg_prefs').hide(); ).insertAfter('#svg_prefs').hide();
// Make the MathEditor draggable. // Make the MathEditor draggable.
$('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'}); $('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
// Add functionality and picture to cancel button. // Add functionality and picture to cancel button.
$('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true)) $('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
.on('click touched', function () { .on('click touched', function () {
$('#mathjax').hide(); $('#mathjax').hide();
}); });
// Add functionality and picture to the save button. // Add functionality and picture to the save button.
$('#tool_mathjax_save').prepend($.getSvgIcon('ok', true)) $('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
.on('click touched', function () { .on('click touched', function () {
saveMath(); saveMath();
$('#mathjax').hide(); $('#mathjax').hide();
}); });
// MathJax preprocessing has to ignore most of the page. // MathJax preprocessing has to ignore most of the page.
$('body').addClass('tex2jax_ignore'); $('body').addClass('tex2jax_ignore');
// Now get (and run) the MathJax Library. // Now get (and run) the MathJax Library.
$.getScript(mathjaxSrcSecure) $.getScript(mathjaxSrcSecure)
.done(function (script, textStatus) { .done(function (script, textStatus) {
// When MathJax is loaded get the div where the math will be rendered. // When MathJax is loaded get the div where the math will be rendered.
MathJax.Hub.queue.Push(function () { MathJax.Hub.queue.Push(function () {
math = MathJax.Hub.getAllJax('#mathjax_creator')[0]; math = MathJax.Hub.getAllJax('#mathjax_creator')[0];
console.log(math); console.log(math);
mathjaxLoaded = true; mathjaxLoaded = true;
console.log('MathJax Loaded'); console.log('MathJax Loaded');
}); });
}) })
// If it fails. // If it fails.
.fail(function () { .fail(function () {
console.log('Failed loadeing MathJax.'); console.log('Failed loadeing MathJax.');
$.alert('Failed loading MathJax. You will not be able to change the mathematics.'); $.alert('Failed loading MathJax. You will not be able to change the mathematics.');
}); });
} }
// Set the mode. // Set the mode.
svgCanvas.setMode('mathjax'); svgCanvas.setMode('mathjax');
} }
} }
}], }],
mouseDown: function () { mouseDown: function () {
if (svgCanvas.getMode() === 'mathjax') { if (svgCanvas.getMode() === 'mathjax') {
return {started: true}; return {started: true};
} }
}, },
mouseUp: function (opts) { mouseUp: function (opts) {
if (svgCanvas.getMode() === 'mathjax') { if (svgCanvas.getMode() === 'mathjax') {
// Get the coordinates from your mouse. // Get the coordinates from your mouse.
var zoom = svgCanvas.getZoom(); var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value // Get the actual coordinate by dividing by the zoom value
locationX = opts.mouse_x / zoom; locationX = opts.mouse_x / zoom;
locationY = opts.mouse_y / zoom; locationY = opts.mouse_y / zoom;
$('#mathjax').show(); $('#mathjax').show();
return {started: false}; // Otherwise the last selected object dissapears. return {started: false}; // Otherwise the last selected object dissapears.
} }
}, },
callback: function () { callback: function () {
$('<style>').text( $('<style>').text(
'#mathjax fieldset{' + '#mathjax fieldset{' +
'padding: 5px;' + 'padding: 5px;' +
'margin: 5px;' + 'margin: 5px;' +
'border: 1px solid #DDD;' + 'border: 1px solid #DDD;' +
'}' + '}' +
'#mathjax label{' + '#mathjax label{' +
'display: block;' + 'display: block;' +
'margin: .5em;' + 'margin: .5em;' +
'}' + '}' +
'#mathjax legend {' + '#mathjax legend {' +
'max-width:195px;' + 'max-width:195px;' +
'}' + '}' +
'#mathjax_overlay {' + '#mathjax_overlay {' +
'position: absolute;' + 'position: absolute;' +
'top: 0;' + 'top: 0;' +
'left: 0;' + 'left: 0;' +
'right: 0;' + 'right: 0;' +
'bottom: 0;' + 'bottom: 0;' +
'background-color: black;' + 'background-color: black;' +
'opacity: 0.6;' + 'opacity: 0.6;' +
'z-index: 20000;' + 'z-index: 20000;' +
'}' + '}' +
'#mathjax_container {' + '#mathjax_container {' +
'position: absolute;' + 'position: absolute;' +
'top: 50px;' + 'top: 50px;' +
'padding: 10px;' + 'padding: 10px;' +
'background-color: #B0B0B0;' + 'background-color: #B0B0B0;' +
'border: 1px outset #777;' + 'border: 1px outset #777;' +
'opacity: 1.0;' + 'opacity: 1.0;' +
'font-family: Verdana, Helvetica, sans-serif;' + 'font-family: Verdana, Helvetica, sans-serif;' +
'font-size: .8em;' + 'font-size: .8em;' +
'z-index: 20001;' + 'z-index: 20001;' +
'}' + '}' +
'#tool_mathjax_back {' + '#tool_mathjax_back {' +
'margin-left: 1em;' + 'margin-left: 1em;' +
'overflow: auto;' + 'overflow: auto;' +
'}' + '}' +
'#mathjax_legend{' + '#mathjax_legend{' +
'font-weight: bold;' + 'font-weight: bold;' +
'font-size:1.1em;' + 'font-size:1.1em;' +
'}' + '}' +
'#mathjax_code_textarea {\\n' + '#mathjax_code_textarea {\\n' +
'margin: 5px .7em;' + 'margin: 5px .7em;' +
'overflow: hidden;' + 'overflow: hidden;' +
'width: 416px;' + 'width: 416px;' +
'display: block;' + 'display: block;' +
'height: 100px;' + 'height: 100px;' +
'}' '}'
).appendTo('head'); ).appendTo('head');
// Add the MathJax configuration. // Add the MathJax configuration.
// $(mathjaxConfiguration).appendTo('head'); // $(mathjaxConfiguration).appendTo('head');
} }
}; };
}); });

View File

@@ -11,142 +11,142 @@
var overviewWindowGlobals = {}; var overviewWindowGlobals = {};
svgEditor.addExtension('overview_window', function () { svgEditor.addExtension('overview_window', function () {
'use strict'; 'use strict';
// Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and // Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and
// https://code.google.com/p/chromium/issues/detail?id=565120. // https://code.google.com/p/chromium/issues/detail?id=565120.
if (svgedit.browser.isChrome()) { if (svgedit.browser.isChrome()) {
var verIndex = navigator.userAgent.indexOf('Chrome/') + 7; var verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10); var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10);
if (chromeVersion < 49) { if (chromeVersion < 49) {
return; return;
} }
} }
// Define and insert the base html element. // Define and insert the base html element.
var propsWindowHtml = var propsWindowHtml =
'<div id="overview_window_content_pane" style="width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;">' + '<div id="overview_window_content_pane" style="width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;">' +
'<div id="overview_window_content" style="position:relative; left:12px; top:0px;">' + '<div id="overview_window_content" style="position:relative; left:12px; top:0px;">' +
'<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' + '<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' +
'<svg id="overviewMiniView" width="150" height="100" x="0" y="0" viewBox="0 0 4800 3600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' + '<svg id="overviewMiniView" width="150" height="100" x="0" y="0" viewBox="0 0 4800 3600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
'<use x="0" y="0" xlink:href="#svgroot"> </use>' + '<use x="0" y="0" xlink:href="#svgroot"> </use>' +
'</svg>' + '</svg>' +
'<div id="overview_window_view_box" style="min-width:50px; min-height:50px; position:absolute; top:30px; left:30px; z-index:5; background-color:rgba(255,0,102,0.3);">' + '<div id="overview_window_view_box" style="min-width:50px; min-height:50px; position:absolute; top:30px; left:30px; z-index:5; background-color:rgba(255,0,102,0.3);">' +
'</div>' + '</div>' +
'</div>' + '</div>' +
'</div>' + '</div>' +
'</div>'; '</div>';
$('#sidepanels').append(propsWindowHtml); $('#sidepanels').append(propsWindowHtml);
// Define dynamic animation of the view box. // Define dynamic animation of the view box.
var updateViewBox = function () { var updateViewBox = function () {
var portHeight = parseFloat($('#workarea').css('height')); var portHeight = parseFloat($('#workarea').css('height'));
var portWidth = parseFloat($('#workarea').css('width')); var portWidth = parseFloat($('#workarea').css('width'));
var portX = $('#workarea').scrollLeft(); var portX = $('#workarea').scrollLeft();
var portY = $('#workarea').scrollTop(); var portY = $('#workarea').scrollTop();
var windowWidth = parseFloat($('#svgcanvas').css('width')); var windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height')); var windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width'); var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = portX / windowWidth * overviewWidth; var viewBoxX = portX / windowWidth * overviewWidth;
var viewBoxY = portY / windowHeight * overviewHeight; var viewBoxY = portY / windowHeight * overviewHeight;
var viewBoxWidth = portWidth / windowWidth * overviewWidth; var viewBoxWidth = portWidth / windowWidth * overviewWidth;
var viewBoxHeight = portHeight / windowHeight * overviewHeight; var viewBoxHeight = portHeight / windowHeight * overviewHeight;
$('#overview_window_view_box').css('min-width', viewBoxWidth + 'px'); $('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
$('#overview_window_view_box').css('min-height', viewBoxHeight + 'px'); $('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
$('#overview_window_view_box').css('top', viewBoxY + 'px'); $('#overview_window_view_box').css('top', viewBoxY + 'px');
$('#overview_window_view_box').css('left', viewBoxX + 'px'); $('#overview_window_view_box').css('left', viewBoxX + 'px');
}; };
$('#workarea').scroll(function () { $('#workarea').scroll(function () {
if (!(overviewWindowGlobals.viewBoxDragging)) { if (!(overviewWindowGlobals.viewBoxDragging)) {
updateViewBox(); updateViewBox();
} }
}); });
$('#workarea').resize(updateViewBox); $('#workarea').resize(updateViewBox);
updateViewBox(); updateViewBox();
// Compensate for changes in zoom and canvas size. // Compensate for changes in zoom and canvas size.
var updateViewDimensions = function () { var updateViewDimensions = function () {
var viewWidth = $('#svgroot').attr('width'); var viewWidth = $('#svgroot').attr('width');
var viewHeight = $('#svgroot').attr('height'); var viewHeight = $('#svgroot').attr('height');
var viewX = 640; var viewX = 640;
var viewY = 480; var viewY = 480;
if (svgedit.browser.isIE()) { if (svgedit.browser.isIE()) {
// This has only been tested with Firefox 10 and IE 9 (without chrome frame). // This has only been tested with Firefox 10 and IE 9 (without chrome frame).
// I am not sure if if is Firefox or IE that is being non compliant here. // I am not sure if if is Firefox or IE that is being non compliant here.
// Either way the one that is noncompliant may become more compliant later. // Either way the one that is noncompliant may become more compliant later.
// TAG:HACK // TAG:HACK
// TAG:VERSION_DEPENDENT // TAG:VERSION_DEPENDENT
// TAG:BROWSER_SNIFFING // TAG:BROWSER_SNIFFING
viewX = 0; viewX = 0;
viewY = 0; viewY = 0;
} }
var svgWidthOld = $('#overviewMiniView').attr('width'); var svgWidthOld = $('#overviewMiniView').attr('width');
var svgHeightNew = viewHeight / viewWidth * svgWidthOld; var svgHeightNew = viewHeight / viewWidth * svgWidthOld;
$('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight); $('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
$('#overviewMiniView').attr('height', svgHeightNew); $('#overviewMiniView').attr('height', svgHeightNew);
updateViewBox(); updateViewBox();
}; };
updateViewDimensions(); updateViewDimensions();
// Set up the overview window as a controller for the view port. // Set up the overview window as a controller for the view port.
overviewWindowGlobals.viewBoxDragging = false; overviewWindowGlobals.viewBoxDragging = false;
var updateViewPortFromViewBox = function () { var updateViewPortFromViewBox = function () {
var windowWidth = parseFloat($('#svgcanvas').css('width')); var windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height')); var windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width'); var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = parseFloat($('#overview_window_view_box').css('left')); var viewBoxX = parseFloat($('#overview_window_view_box').css('left'));
var viewBoxY = parseFloat($('#overview_window_view_box').css('top')); var viewBoxY = parseFloat($('#overview_window_view_box').css('top'));
var portX = viewBoxX / overviewWidth * windowWidth; var portX = viewBoxX / overviewWidth * windowWidth;
var portY = viewBoxY / overviewHeight * windowHeight; var portY = viewBoxY / overviewHeight * windowHeight;
$('#workarea').scrollLeft(portX); $('#workarea').scrollLeft(portX);
$('#workarea').scrollTop(portY); $('#workarea').scrollTop(portY);
}; };
$('#overview_window_view_box').draggable({ $('#overview_window_view_box').draggable({
containment: 'parent', containment: 'parent',
drag: updateViewPortFromViewBox, drag: updateViewPortFromViewBox,
start: function () { overviewWindowGlobals.viewBoxDragging = true; }, start: function () { overviewWindowGlobals.viewBoxDragging = true; },
stop: function () { overviewWindowGlobals.viewBoxDragging = false; } stop: function () { overviewWindowGlobals.viewBoxDragging = false; }
}); });
$('#overviewMiniView').click(function (evt) { $('#overviewMiniView').click(function (evt) {
// Firefox doesn't support evt.offsetX and evt.offsetY. // Firefox doesn't support evt.offsetX and evt.offsetY.
var mouseX = (evt.offsetX || evt.originalEvent.layerX); var mouseX = (evt.offsetX || evt.originalEvent.layerX);
var mouseY = (evt.offsetY || evt.originalEvent.layerY); var mouseY = (evt.offsetY || evt.originalEvent.layerY);
var overviewWidth = $('#overviewMiniView').attr('width'); var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width')); var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height')); var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
var viewBoxX = mouseX - 0.5 * viewBoxWidth; var viewBoxX = mouseX - 0.5 * viewBoxWidth;
var viewBoxY = mouseY - 0.5 * viewBoxHeight; var viewBoxY = mouseY - 0.5 * viewBoxHeight;
// deal with constraints // deal with constraints
if (viewBoxX < 0) { if (viewBoxX < 0) {
viewBoxX = 0; viewBoxX = 0;
} }
if (viewBoxY < 0) { if (viewBoxY < 0) {
viewBoxY = 0; viewBoxY = 0;
} }
if (viewBoxX + viewBoxWidth > overviewWidth) { if (viewBoxX + viewBoxWidth > overviewWidth) {
viewBoxX = overviewWidth - viewBoxWidth; viewBoxX = overviewWidth - viewBoxWidth;
} }
if (viewBoxY + viewBoxHeight > overviewHeight) { if (viewBoxY + viewBoxHeight > overviewHeight) {
viewBoxY = overviewHeight - viewBoxHeight; viewBoxY = overviewHeight - viewBoxHeight;
} }
$('#overview_window_view_box').css('top', viewBoxY + 'px'); $('#overview_window_view_box').css('top', viewBoxY + 'px');
$('#overview_window_view_box').css('left', viewBoxX + 'px'); $('#overview_window_view_box').css('left', viewBoxX + 'px');
updateViewPortFromViewBox(); updateViewPortFromViewBox();
}); });
return { return {
name: 'overview window', name: 'overview window',
canvasUpdated: updateViewDimensions, canvasUpdated: updateViewDimensions,
workareaResized: updateViewBox workareaResized: updateViewBox
}; };
}); });

View File

@@ -9,38 +9,38 @@
*/ */
/* /*
This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem
*/ */
svgEditor.addExtension('ext-panning', function () { svgEditor.addExtension('ext-panning', function () {
'use strict'; 'use strict';
return { return {
name: 'Extension Panning', name: 'Extension Panning',
svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml', svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
buttons: [{ buttons: [{
id: 'ext-panning', id: 'ext-panning',
type: 'mode', type: 'mode',
title: 'Panning', title: 'Panning',
events: { events: {
click: function () { click: function () {
svgCanvas.setMode('ext-panning'); svgCanvas.setMode('ext-panning');
} }
} }
}], }],
mouseDown: function () { mouseDown: function () {
if (svgCanvas.getMode() === 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true); svgEditor.setPanning(true);
return {started: true}; return {started: true};
} }
}, },
mouseUp: function () { mouseUp: function () {
if (svgCanvas.getMode() === 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false); svgEditor.setPanning(false);
return { return {
keep: false, keep: false,
element: null element: null
}; };
} }
} }
}; };
}); });

View File

@@ -4,20 +4,20 @@
// handler as in "ext-server_opensave.js" (and in savefile.php) // handler as in "ext-server_opensave.js" (and in savefile.php)
svgEditor.addExtension('php_savefile', { svgEditor.addExtension('php_savefile', {
callback: function () { callback: function () {
'use strict'; 'use strict';
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
return $.trim(title); return $.trim(title);
} }
var saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php'; var saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php';
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save: function (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
$.post(saveSvgAction, {output_svg: svg, filename: filename}); $.post(saveSvgAction, {output_svg: svg, filename: filename});
} }
}); });
} }
}); });

View File

@@ -9,278 +9,278 @@
* *
*/ */
svgEditor.addExtension('polygon', function (S) { svgEditor.addExtension('polygon', function (S) {
'use strict'; 'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson, // addElem = S.addSvgElementFromJson,
selElems, selElems,
editingitex = false, editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG, // newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
// edg = 0, // edg = 0,
// undoCommand = 'Not image'; // undoCommand = 'Not image';
started, newFO; started, newFO;
// var ccZoom; // var ccZoom;
// var wEl, hEl; // var wEl, hEl;
// var wOffset, hOffset; // var wOffset, hOffset;
// var ccRBG; // var ccRBG;
// var ccOpacity; // var ccOpacity;
// var brushW, brushH; // var brushW, brushH;
// var ccDebug = document.getElementById('debugpanel'); // var ccDebug = document.getElementById('debugpanel');
/* var properlySourceSizeTextArea = function(){ /* var properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS // TODO: remove magic numbers here and get values from CSS
var height = $('#svg_source_container').height() - 80; var height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height); $('#svg_source_textarea').css('height', height);
}; */ }; */
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); var fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#polygon_panel').toggle(on); $('#polygon_panel').toggle(on);
} }
/* /*
function toggleSourceButtons(on){ function toggleSourceButtons(on){
$('#tool_source_save, #tool_source_cancel').toggle(!on); $('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#polygon_save, #polygon_cancel').toggle(on); $('#polygon_save, #polygon_cancel').toggle(on);
} }
*/ */
function setAttr (attr, val) { function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems); S.call('changed', selElems);
} }
function cot (n) { function cot (n) {
return 1 / Math.tan(n); return 1 / Math.tan(n);
} }
function sec (n) { function sec (n) {
return 1 / Math.cos(n); return 1 / Math.cos(n);
} }
/** /**
* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3 * Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
* This function sets the content of of the currently-selected foreignObject element, * This function sets the content of of the currently-selected foreignObject element,
* based on the itex contained in string. * based on the itex contained in string.
* @param {string} tex The itex text. * @param {string} tex The itex text.
* @returns This function returns false if the set was unsuccessful, true otherwise. * @returns This function returns false if the set was unsuccessful, true otherwise.
*/ */
/* /*
function setItexString(tex) { function setItexString(tex) {
var mathns = 'http://www.w3.org/1998/Math/MathML', var mathns = 'http://www.w3.org/1998/Math/MathML',
xmlnsns = 'http://www.w3.org/2000/xmlns/', xmlnsns = 'http://www.w3.org/2000/xmlns/',
ajaxEndpoint = '../../itex'; ajaxEndpoint = '../../itex';
var elt = selElems[0]; var elt = selElems[0];
try { try {
var math = svgdoc.createElementNS(mathns, 'math'); var math = svgdoc.createElementNS(mathns, 'math');
math.setAttributeNS(xmlnsns, 'xmlns', mathns); math.setAttributeNS(xmlnsns, 'xmlns', mathns);
math.setAttribute('display', 'inline'); math.setAttribute('display', 'inline');
var semantics = document.createElementNS(mathns, 'semantics'); var semantics = document.createElementNS(mathns, 'semantics');
var annotation = document.createElementNS(mathns, 'annotation'); var annotation = document.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex'); annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = tex; annotation.textContent = tex;
var mrow = document.createElementNS(mathns, 'mrow'); var mrow = document.createElementNS(mathns, 'mrow');
semantics.appendChild(mrow); semantics.appendChild(mrow);
semantics.appendChild(annotation); semantics.appendChild(annotation);
math.appendChild(semantics); math.appendChild(semantics);
// make an AJAX request to the server, to get the MathML // make an AJAX request to the server, to get the MathML
$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){ $.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){
var children = data.documentElement.childNodes; var children = data.documentElement.childNodes;
while (children.length > 0) { while (children.length > 0) {
mrow.appendChild(svgdoc.adoptNode(children[0], true)); mrow.appendChild(svgdoc.adoptNode(children[0], true));
} }
S.sanitizeSvg(math); S.sanitizeSvg(math);
S.call('changed', [elt]); S.call('changed', [elt]);
}); });
elt.replaceChild(math, elt.firstChild); elt.replaceChild(math, elt.firstChild);
S.call('changed', [elt]); S.call('changed', [elt]);
svgCanvas.clearSelection(); svgCanvas.clearSelection();
} catch(e) { } catch(e) {
console.log(e); console.log(e);
return false; return false;
} }
return true; return true;
} }
*/ */
return { return {
name: 'polygon', name: 'polygon',
svgicons: svgEditor.curConfig.extPath + 'polygon-icons.svg', svgicons: svgEditor.curConfig.extPath + 'polygon-icons.svg',
buttons: [{ buttons: [{
id: 'tool_polygon', id: 'tool_polygon',
type: 'mode', type: 'mode',
title: 'Polygon Tool', title: 'Polygon Tool',
position: 11, position: 11,
events: { events: {
'click': function () { 'click': function () {
svgCanvas.setMode('polygon'); svgCanvas.setMode('polygon');
showPanel(true); showPanel(true);
} }
} }
}], }],
context_tools: [{ context_tools: [{
type: 'input', type: 'input',
panel: 'polygon_panel', panel: 'polygon_panel',
title: 'Number of Sides', title: 'Number of Sides',
id: 'polySides', id: 'polySides',
label: 'sides', label: 'sides',
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function () { change: function () {
setAttr('sides', this.value); setAttr('sides', this.value);
} }
} }
}], }],
callback: function () { callback: function () {
$('#polygon_panel').hide(); $('#polygon_panel').hide();
var endChanges = function () { var endChanges = function () {
}; };
// TODO: Needs to be done after orig icon loads // TODO: Needs to be done after orig icon loads
setTimeout(function () { setTimeout(function () {
// Create source save/cancel buttons // Create source save/cancel buttons
/* var save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () { /* var save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () {
if (!editingitex) { if (!editingitex) {
return; return;
} }
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint? // Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
/* /*
if (!setItexString($('#svg_source_textarea').val())) { if (!setItexString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) { $.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) { if (!ok) {
return false; return false;
} }
endChanges(); endChanges();
}); });
} else { */ } else { */
endChanges(); endChanges();
// } // }
// setSelectMode(); // setSelectMode();
}); });
/* var cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () { /* var cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () {
endChanges(); endChanges();
}); });
}, 3000); }, 3000);
}, },
mouseDown: function (opts) { mouseDown: function (opts) {
// var e = opts.event; // var e = opts.event;
var rgb = svgCanvas.getColor('fill'); var rgb = svgCanvas.getColor('fill');
// var ccRgbEl = rgb.substring(1, rgb.length); // var ccRgbEl = rgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor('stroke'); var sRgb = svgCanvas.getColor('stroke');
// ccSRgbEl = sRgb.substring(1, rgb.length); // ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); var sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
started = true; started = true;
newFO = S.addSvgElementFromJson({ newFO = S.addSvgElementFromJson({
'element': 'polygon', 'element': 'polygon',
'attr': { 'attr': {
'cx': opts.start_x, 'cx': opts.start_x,
'cy': opts.start_y, 'cy': opts.start_y,
'id': S.getNextId(), 'id': S.getNextId(),
'shape': 'regularPoly', 'shape': 'regularPoly',
'sides': document.getElementById('polySides').value, 'sides': document.getElementById('polySides').value,
'orient': 'x', 'orient': 'x',
'edge': 0, 'edge': 0,
'fill': rgb, 'fill': rgb,
'strokecolor': sRgb, 'strokecolor': sRgb,
'strokeWidth': sWidth 'strokeWidth': sWidth
} }
}); });
return { return {
started: true started: true
}; };
} }
}, },
mouseMove: function (opts) { mouseMove: function (opts) {
if (!started) { if (!started) {
return; return;
} }
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
// var e = opts.event; // var e = opts.event;
var x = opts.mouse_x; var x = opts.mouse_x;
var y = opts.mouse_y; var y = opts.mouse_y;
var c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']); var c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides, var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides,
// orient = c.orient, // orient = c.orient,
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5; edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
newFO.setAttributeNS(null, 'edge', edg); newFO.setAttributeNS(null, 'edge', edg);
var inradius = (edg / 2) * cot(Math.PI / sides); var inradius = (edg / 2) * cot(Math.PI / sides);
var circumradius = inradius * sec(Math.PI / sides); var circumradius = inradius * sec(Math.PI / sides);
var points = ''; var points = '';
var s; var s;
for (s = 0; sides >= s; s++) { for (s = 0; sides >= s; s++) {
var angle = 2.0 * Math.PI * s / sides; var angle = 2.0 * Math.PI * s / sides;
x = (circumradius * Math.cos(angle)) + cx; x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy; y = (circumradius * Math.sin(angle)) + cy;
points += x + ',' + y + ' '; points += x + ',' + y + ' ';
} }
// var poly = newFO.createElementNS(NS.SVG, 'polygon'); // var poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttributeNS(null, 'points', points); newFO.setAttributeNS(null, 'points', points);
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokewidth);
// newFO.setAttributeNS(null, 'transform', 'rotate(-90)'); // newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
// var shape = newFO.getAttributeNS(null, 'shape'); // var shape = newFO.getAttributeNS(null, 'shape');
// newFO.appendChild(poly); // newFO.appendChild(poly);
// DrawPoly(cx, cy, sides, edg, orient); // DrawPoly(cx, cy, sides, edg, orient);
return { return {
started: true started: true
}; };
} }
}, },
mouseUp: function (opts) { mouseUp: function (opts) {
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
var attrs = $(newFO).attr('edge'); var attrs = $(newFO).attr('edge');
var keep = (attrs.edge !== '0'); var keep = (attrs.edge !== '0');
// svgCanvas.addToSelection([newFO], true); // svgCanvas.addToSelection([newFO], true);
return { return {
keep: keep, keep: keep,
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') { if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
$('#polySides').val(elem.getAttribute('sides')); $('#polySides').val(elem.getAttribute('sides'));
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
} }
} else { } else {
showPanel(false); showPanel(false);
} }
} }
}, },
elementChanged: function (opts) { elementChanged: function (opts) {
// var elem = opts.elems[0]; // var elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -13,46 +13,46 @@
*/ */
svgEditor.addExtension('server_opensave', { svgEditor.addExtension('server_opensave', {
callback: function () { callback: function () {
'use strict'; 'use strict';
var Utils = svgedit.utilities; var Utils = svgedit.utilities;
var saveSvgAction = '/+modify'; var saveSvgAction = '/+modify';
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
/* var target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); /* var target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save: function (win, data) {
var svg = '<?xml version="1.0"?>\n' + data; var svg = '<?xml version="1.0"?>\n' + data;
var qstr = $.param.querystring(); var qstr = $.param.querystring();
var name = qstr.substr(9).split('/+get/')[1]; var name = qstr.substr(9).split('/+get/')[1];
var svgData = Utils.encode64(svg); var svgData = Utils.encode64(svg);
if (!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
var c = $('#export_canvas')[0]; var c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, svg, {renderCallback: function () { canvg(c, svg, {renderCallback: function () {
var datauri = c.toDataURL('image/png'); var datauri = c.toDataURL('image/png');
// var uiStrings = svgEditor.uiStrings; // var uiStrings = svgEditor.uiStrings;
var pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary var pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary
/* var form = */ $('<form>').attr({ /* var form = */ $('<form>').attr({
method: 'post', method: 'post',
action: saveSvgAction + '/' + name, action: saveSvgAction + '/' + name,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="png_data" value="' + pngData + '">') }).append('<input type="hidden" name="png_data" value="' + pngData + '">')
.append('<input type="hidden" name="filepath" value="' + svgData + '">') .append('<input type="hidden" name="filepath" value="' + svgData + '">')
.append('<input type="hidden" name="filename" value="' + 'drawing.svg">') .append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">') .append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}}); }});
})(); })();
alert('Saved! Return to Item View!'); alert('Saved! Return to Item View!');
top.window.location = '/' + name; top.window.location = '/' + name;
} }
}); });
} }
}); });

View File

@@ -10,217 +10,217 @@
*/ */
svgEditor.addExtension('server_opensave', { svgEditor.addExtension('server_opensave', {
callback: function () { callback: function () {
'use strict'; 'use strict';
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
// We convert (to underscore) only those disallowed Win7 file name characters // We convert (to underscore) only those disallowed Win7 file name characters
return $.trim(title).replace(/[/\\:*?"<>|]/g, '_'); return $.trim(title).replace(/[/\\:*?"<>|]/g, '_');
} }
function xhtmlEscape (str) { function xhtmlEscape (str) {
return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways
} }
function clientDownloadSupport (filename, suffix, uri) { function clientDownloadSupport (filename, suffix, uri) {
var a, var a,
support = $('<a>')[0].download === ''; support = $('<a>')[0].download === '';
if (support) { if (support) {
a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body'); a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body');
a[0].click(); a[0].click();
return true; return true;
} }
} }
var openSvgAction, importSvgAction, importImgAction, var openSvgAction, importSvgAction, importImgAction,
openSvgForm, importSvgForm, importImgForm, openSvgForm, importSvgForm, importImgForm,
saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php', saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php',
saveImgAction = svgEditor.curConfig.extPath + 'filesave.php', saveImgAction = svgEditor.curConfig.extPath + 'filesave.php',
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
cancelled = false, cancelled = false,
Utils = svgedit.utilities; Utils = svgedit.utilities;
$('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save: function (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
if (clientDownloadSupport(filename, '.svg', 'data:image/svg+xml;charset=UTF-8;base64,' + Utils.encode64(svg))) { if (clientDownloadSupport(filename, '.svg', 'data:image/svg+xml;charset=UTF-8;base64,' + Utils.encode64(svg))) {
return; return;
} }
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: saveSvgAction, action: saveSvgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">') }).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">') .append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}, },
exportPDF: function (win, data) { exportPDF: function (win, data) {
var filename = getFileNameFromTitle(), var filename = getFileNameFromTitle(),
datauri = data.dataurlstring; datauri = data.dataurlstring;
if (clientDownloadSupport(filename, '.pdf', datauri)) { if (clientDownloadSupport(filename, '.pdf', datauri)) {
return; return;
} }
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: saveImgAction, action: saveImgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">') }).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="application/pdf">') .append('<input type="hidden" name="mime" value="application/pdf">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">') .append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}, },
// Todo: Integrate this extension with a new built-in exportWindowType, "download" // Todo: Integrate this extension with a new built-in exportWindowType, "download"
exportImage: function (win, data) { exportImage: function (win, data) {
var c, var c,
issues = data.issues, issues = data.issues,
mimeType = data.mimeType, mimeType = data.mimeType,
quality = data.quality; quality = data.quality;
if (!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
c = $('#export_canvas')[0]; c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, data.svg, {renderCallback: function () { canvg(c, data.svg, {renderCallback: function () {
var pre, filename, suffix, var pre, filename, suffix,
datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType), datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType),
// uiStrings = svgEditor.uiStrings, // uiStrings = svgEditor.uiStrings,
note = ''; note = '';
// Check if there are issues // Check if there are issues
if (issues.length) { if (issues.length) {
pre = '\n \u2022 '; pre = '\n \u2022 ';
note += ('\n\n' + pre + issues.join(pre)); note += ('\n\n' + pre + issues.join(pre));
} }
if (note.length) { if (note.length) {
alert(note); alert(note);
} }
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
suffix = '.' + data.type.toLowerCase(); suffix = '.' + data.type.toLowerCase();
if (clientDownloadSupport(filename, suffix, datauri)) { if (clientDownloadSupport(filename, suffix, datauri)) {
return; return;
} }
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: saveImgAction, action: saveImgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">') }).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="' + mimeType + '">') .append('<input type="hidden" name="mime" value="' + mimeType + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">') .append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}}); }});
})(); })();
} }
}); });
// Do nothing if client support is found // Do nothing if client support is found
if (window.FileReader) { return; } if (window.FileReader) { return; }
// Change these to appropriate script file // Change these to appropriate script file
openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg'; openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg'; importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img'; importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
// Set up function for PHP uploader to use // Set up function for PHP uploader to use
svgEditor.processFile = function (str64, type) { svgEditor.processFile = function (str64, type) {
var xmlstr; var xmlstr;
if (cancelled) { if (cancelled) {
cancelled = false; cancelled = false;
return; return;
} }
$('#dialog_box').hide(); $('#dialog_box').hide();
if (type !== 'import_img') { if (type !== 'import_img') {
xmlstr = Utils.decode64(str64); xmlstr = Utils.decode64(str64);
} }
switch (type) { switch (type) {
case 'load_svg': case 'load_svg':
svgCanvas.clear(); svgCanvas.clear();
svgCanvas.setSvgString(xmlstr); svgCanvas.setSvgString(xmlstr);
svgEditor.updateCanvas(); svgEditor.updateCanvas();
break; break;
case 'import_svg': case 'import_svg':
svgCanvas.importSvgString(xmlstr); svgCanvas.importSvgString(xmlstr);
svgEditor.updateCanvas(); svgEditor.updateCanvas();
break; break;
case 'import_img': case 'import_img':
svgCanvas.setGoodImage(str64); svgCanvas.setGoodImage(str64);
break; break;
} }
}; };
// Create upload form // Create upload form
openSvgForm = $('<form>'); openSvgForm = $('<form>');
openSvgForm.attr({ openSvgForm.attr({
enctype: 'multipart/form-data', enctype: 'multipart/form-data',
method: 'post', method: 'post',
action: openSvgAction, action: openSvgAction,
target: 'output_frame' target: 'output_frame'
}); });
// Create import form // Create import form
importSvgForm = openSvgForm.clone().attr('action', importSvgAction); importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
// Create image form // Create image form
importImgForm = openSvgForm.clone().attr('action', importImgAction); importImgForm = openSvgForm.clone().attr('action', importImgAction);
// It appears necessary to rebuild this input every time a file is // It appears necessary to rebuild this input every time a file is
// selected so the same file can be picked and the change event can fire. // selected so the same file can be picked and the change event can fire.
function rebuildInput (form) { function rebuildInput (form) {
form.empty(); form.empty();
var inp = $('<input type="file" name="svg_file">').appendTo(form); var inp = $('<input type="file" name="svg_file">').appendTo(form);
function submit () { function submit () {
// This submits the form, which returns the file data using svgEditor.processFile() // This submits the form, which returns the file data using svgEditor.processFile()
form.submit(); form.submit();
rebuildInput(form); rebuildInput(form);
$.process_cancel('Uploading...', function () { $.process_cancel('Uploading...', function () {
cancelled = true; cancelled = true;
$('#dialog_box').hide(); $('#dialog_box').hide();
}); });
} }
if (form[0] === openSvgForm[0]) { if (form[0] === openSvgForm[0]) {
inp.change(function () { inp.change(function () {
// This takes care of the "are you sure" dialog box // This takes care of the "are you sure" dialog box
svgEditor.openPrep(function (ok) { svgEditor.openPrep(function (ok) {
if (!ok) { if (!ok) {
rebuildInput(form); rebuildInput(form);
return; return;
} }
submit(); submit();
}); });
}); });
} else { } else {
inp.change(function () { inp.change(function () {
// This submits the form, which returns the file data using svgEditor.processFile() // This submits the form, which returns the file data using svgEditor.processFile()
submit(); submit();
}); });
} }
} }
// Create the input elements // Create the input elements
rebuildInput(openSvgForm); rebuildInput(openSvgForm);
rebuildInput(importSvgForm); rebuildInput(importSvgForm);
rebuildInput(importImgForm); rebuildInput(importImgForm);
// Add forms to buttons // Add forms to buttons
$('#tool_open').show().prepend(openSvgForm); $('#tool_open').show().prepend(openSvgForm);
$('#tool_import').show().prepend(importSvgForm); $('#tool_import').show().prepend(importSvgForm);
$('#tool_image').prepend(importImgForm); $('#tool_image').prepend(importImgForm);
} }
}); });

View File

@@ -11,345 +11,345 @@
*/ */
svgEditor.addExtension('shapes', function () { svgEditor.addExtension('shapes', function () {
'use strict'; 'use strict';
var currentD, curShapeId; var currentD, curShapeId;
var canv = svgEditor.canvas; var canv = svgEditor.canvas;
var curShape; var curShape;
var startX, startY; var startX, startY;
var svgroot = canv.getRootElem(); var svgroot = canv.getRootElem();
var lastBBox = {}; var lastBBox = {};
// This populates the category list // This populates the category list
var categories = { var categories = {
basic: 'Basic', basic: 'Basic',
object: 'Objects', object: 'Objects',
symbol: 'Symbols', symbol: 'Symbols',
arrow: 'Arrows', arrow: 'Arrows',
flowchart: 'Flowchart', flowchart: 'Flowchart',
animal: 'Animals', animal: 'Animals',
game: 'Cards & Chess', game: 'Cards & Chess',
dialog_balloon: 'Dialog balloons', dialog_balloon: 'Dialog balloons',
electronics: 'Electronics', electronics: 'Electronics',
math: 'Mathematical', math: 'Mathematical',
music: 'Music', music: 'Music',
misc: 'Miscellaneous', misc: 'Miscellaneous',
raphael_1: 'raphaeljs.com set 1', raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2' raphael_2: 'raphaeljs.com set 2'
}; };
var library = { var library = {
basic: { basic: {
data: { data: {
'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z', 'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
'frame': 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z', 'frame': 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z', 'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
'triangle': 'm1,280.375l149,-260.75l149,260.75z', 'triangle': 'm1,280.375l149,-260.75l149,260.75z',
'right_triangle': 'm1,299l0,-298l298,298z', 'right_triangle': 'm1,299l0,-298l298,298z',
'diamond': 'm1,150l149,-149l149,149l-149,149l-149,-149z', 'diamond': 'm1,150l149,-149l149,149l-149,149l-149,-149z',
'pentagon': 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z', 'pentagon': 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z',
'hexagon': 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z', 'hexagon': 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z',
'septagon1': 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z', 'septagon1': 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z',
'heptagon': 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z', 'heptagon': 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z',
'decagon': 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z', 'decagon': 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z',
'dodecagon': 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z', 'dodecagon': 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z',
'star_points_5': 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z', 'star_points_5': 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z',
'trapezoid': 'm1,299l55.875,-298l186.25001,0l55.87498,298z', 'trapezoid': 'm1,299l55.875,-298l186.25001,0l55.87498,298z',
'arrow_up': 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z', 'arrow_up': 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z',
'vertical_scrool': 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875', 'vertical_scrool': 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875',
'smiley': 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z', 'smiley': 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z',
'left_braket': 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066', 'left_braket': 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066',
'uml_actor': 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z', 'uml_actor': 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z',
'dialog_balloon_1': 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z', 'dialog_balloon_1': 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z',
'cloud': 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z', 'cloud': 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z',
'cylinder': 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z', 'cylinder': 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z',
'arrow_u_turn': 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z', 'arrow_u_turn': 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z',
'arrow_left_up': 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z', 'arrow_left_up': 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z',
'maximize': 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z', 'maximize': 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z',
'cross': 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z', 'cross': 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z',
'plaque': 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z', 'plaque': 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z',
'page': 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234' 'page': 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234'
}, },
buttons: [] buttons: []
} }
}; };
var curLib = library.basic; var curLib = library.basic;
var modeId = 'shapelib'; var modeId = 'shapelib';
var startClientPos = {}; var startClientPos = {};
function loadIcons () { function loadIcons () {
$('#shape_buttons').empty().append(curLib.buttons); $('#shape_buttons').empty().append(curLib.buttons);
} }
function makeButtons (cat, shapes) { function makeButtons (cat, shapes) {
var size = curLib.size || 300; var size = curLib.size || 300;
var fill = curLib.fill || false; var fill = curLib.fill || false;
var off = size * 0.05; var off = size * 0.05;
var vb = [-off, -off, size + off * 2, size + off * 2].join(' '); var vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
var stroke = fill ? 0 : (size / 30); var stroke = fill ? 0 : (size / 30);
var shapeIcon = new DOMParser().parseFromString( var shapeIcon = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>', '<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
'text/xml'); 'text/xml');
var width = 24; var width = 24;
var height = 24; var height = 24;
shapeIcon.documentElement.setAttribute('width', width); shapeIcon.documentElement.setAttribute('width', width);
shapeIcon.documentElement.setAttribute('height', height); shapeIcon.documentElement.setAttribute('height', height);
var svgElem = $(document.importNode(shapeIcon.documentElement, true)); var svgElem = $(document.importNode(shapeIcon.documentElement, true));
var data = shapes.data; var data = shapes.data;
curLib.buttons = []; curLib.buttons = [];
var id; var id;
for (id in data) { for (id in data) {
var pathD = data[id]; var pathD = data[id];
var icon = svgElem.clone(); var icon = svgElem.clone();
icon.find('path').attr('d', pathD); icon.find('path').attr('d', pathD);
var iconBtn = icon.wrap('<div class="tool_button">').parent().attr({ var iconBtn = icon.wrap('<div class="tool_button">').parent().attr({
id: modeId + '_' + id, id: modeId + '_' + id,
title: id title: id
}); });
// Store for later use // Store for later use
curLib.buttons.push(iconBtn[0]); curLib.buttons.push(iconBtn[0]);
} }
} }
function loadLibrary (catId) { function loadLibrary (catId) {
var lib = library[catId]; var lib = library[catId];
if (!lib) { if (!lib) {
$('#shape_buttons').html('Loading...'); $('#shape_buttons').html('Loading...');
$.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + catId + '.json', function (result) { $.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + catId + '.json', function (result) {
curLib = library[catId] = { curLib = library[catId] = {
data: result.data, data: result.data,
size: result.size, size: result.size,
fill: result.fill fill: result.fill
}; };
makeButtons(catId, result); makeButtons(catId, result);
loadIcons(); loadIcons();
}); });
return; return;
} }
curLib = lib; curLib = lib;
if (!lib.buttons.length) { makeButtons(catId, lib); } if (!lib.buttons.length) { makeButtons(catId, lib); }
loadIcons(); loadIcons();
} }
return { return {
svgicons: svgEditor.curConfig.extPath + 'ext-shapes.xml', svgicons: svgEditor.curConfig.extPath + 'ext-shapes.xml',
buttons: [{ buttons: [{
id: 'tool_shapelib', id: 'tool_shapelib',
type: 'mode_flyout', // _flyout type: 'mode_flyout', // _flyout
position: 6, position: 6,
title: 'Shape library', title: 'Shape library',
events: { events: {
click: function () { click: function () {
canv.setMode(modeId); canv.setMode(modeId);
} }
} }
}], }],
callback: function () { callback: function () {
$('<style>').text( $('<style>').text(
'#shape_buttons {' + '#shape_buttons {' +
'overflow: auto;' + 'overflow: auto;' +
'width: 180px;' + 'width: 180px;' +
'max-height: 300px;' + 'max-height: 300px;' +
'display: table-cell;' + 'display: table-cell;' +
'vertical-align: middle;' + 'vertical-align: middle;' +
'}' + '}' +
'#shape_cats {' + '#shape_cats {' +
'min-width: 110px;' + 'min-width: 110px;' +
'display: table-cell;' + 'display: table-cell;' +
'vertical-align: middle;' + 'vertical-align: middle;' +
'height: 300px;' + 'height: 300px;' +
'}' + '}' +
'#shape_cats > div {' + '#shape_cats > div {' +
'line-height: 1em;' + 'line-height: 1em;' +
'padding: .5em;' + 'padding: .5em;' +
'border:1px solid #B0B0B0;' + 'border:1px solid #B0B0B0;' +
'background: #E8E8E8;' + 'background: #E8E8E8;' +
'margin-bottom: -1px;' + 'margin-bottom: -1px;' +
'}' + '}' +
'#shape_cats div:hover {' + '#shape_cats div:hover {' +
'background: #FFFFCC;' + 'background: #FFFFCC;' +
'}' + '}' +
'#shape_cats div.current {' + '#shape_cats div.current {' +
'font-weight: bold;' + 'font-weight: bold;' +
'}').appendTo('head'); '}').appendTo('head');
var btnDiv = $('<div id="shape_buttons">'); var btnDiv = $('<div id="shape_buttons">');
$('#tools_shapelib > *').wrapAll(btnDiv); $('#tools_shapelib > *').wrapAll(btnDiv);
var shower = $('#tools_shapelib_show'); var shower = $('#tools_shapelib_show');
loadLibrary('basic'); loadLibrary('basic');
// Do mouseup on parent element rather than each button // Do mouseup on parent element rather than each button
$('#shape_buttons').mouseup(function (evt) { $('#shape_buttons').mouseup(function (evt) {
var btn = $(evt.target).closest('div.tool_button'); var btn = $(evt.target).closest('div.tool_button');
if (!btn.length) { return; } if (!btn.length) { return; }
var copy = btn.children().clone(); var copy = btn.children().clone();
shower.children(':not(.flyout_arrow_horiz)').remove(); shower.children(':not(.flyout_arrow_horiz)').remove();
shower shower
.append(copy) .append(copy)
.attr('data-curopt', '#' + btn[0].id) // This sets the current mode .attr('data-curopt', '#' + btn[0].id) // This sets the current mode
.mouseup(); .mouseup();
canv.setMode(modeId); canv.setMode(modeId);
curShapeId = btn[0].id.substr((modeId + '_').length); curShapeId = btn[0].id.substr((modeId + '_').length);
currentD = curLib.data[curShapeId]; currentD = curLib.data[curShapeId];
$('.tools_flyout').fadeOut(); $('.tools_flyout').fadeOut();
}); });
var shapeCats = $('<div id="shape_cats">'); var shapeCats = $('<div id="shape_cats">');
var catStr = ''; var catStr = '';
$.each(categories, function (id, label) { $.each(categories, function (id, label) {
catStr += '<div data-cat=' + id + '>' + label + '</div>'; catStr += '<div data-cat=' + id + '>' + label + '</div>';
}); });
shapeCats.html(catStr).children().bind('mouseup', function () { shapeCats.html(catStr).children().bind('mouseup', function () {
var catlink = $(this); var catlink = $(this);
catlink.siblings().removeClass('current'); catlink.siblings().removeClass('current');
catlink.addClass('current'); catlink.addClass('current');
loadLibrary(catlink.attr('data-cat')); loadLibrary(catlink.attr('data-cat'));
// Get stuff // Get stuff
return false; return false;
}); });
shapeCats.children().eq(0).addClass('current'); shapeCats.children().eq(0).addClass('current');
$('#tools_shapelib').append(shapeCats); $('#tools_shapelib').append(shapeCats);
shower.mouseup(function () { shower.mouseup(function () {
canv.setMode(currentD ? modeId : 'select'); canv.setMode(currentD ? modeId : 'select');
}); });
$('#tool_shapelib').remove(); $('#tool_shapelib').remove();
var h = $('#tools_shapelib').height(); var h = $('#tools_shapelib').height();
$('#tools_shapelib').css({ $('#tools_shapelib').css({
'margin-top': -(h / 2 - 15), 'margin-top': -(h / 2 - 15),
'margin-left': 3 'margin-left': 3
}); });
}, },
mouseDown: function (opts) { mouseDown: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
startX = opts.start_x; startX = opts.start_x;
var x = startX; var x = startX;
startY = opts.start_y; startY = opts.start_y;
var y = startY; var y = startY;
var curStyle = canv.getStyle(); var curStyle = canv.getStyle();
startClientPos.x = opts.event.clientX; startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY; startClientPos.y = opts.event.clientY;
curShape = canv.addSvgElementFromJson({ curShape = canv.addSvgElementFromJson({
'element': 'path', 'element': 'path',
'curStyles': true, 'curStyles': true,
'attr': { 'attr': {
'd': currentD, 'd': currentD,
'id': canv.getNextId(), 'id': canv.getNextId(),
'opacity': curStyle.opacity / 2, 'opacity': curStyle.opacity / 2,
'style': 'pointer-events:none' 'style': 'pointer-events:none'
} }
}); });
// Make sure shape uses absolute values // Make sure shape uses absolute values
if (/[a-z]/.test(currentD)) { if (/[a-z]/.test(currentD)) {
currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape); currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape);
curShape.setAttribute('d', currentD); curShape.setAttribute('d', currentD);
canv.pathActions.fixEnd(curShape); canv.pathActions.fixEnd(curShape);
} }
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')'); curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
canv.recalculateDimensions(curShape); canv.recalculateDimensions(curShape);
/* var tlist = */ canv.getTransformList(curShape); /* var tlist = */ canv.getTransformList(curShape);
lastBBox = curShape.getBBox(); lastBBox = curShape.getBBox();
return { return {
started: true started: true
}; };
}, },
mouseMove: function (opts) { mouseMove: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
var zoom = canv.getZoom(); var zoom = canv.getZoom();
var evt = opts.event; var evt = opts.event;
var x = opts.mouse_x / zoom; var x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom; var y = opts.mouse_y / zoom;
var tlist = canv.getTransformList(curShape), var tlist = canv.getTransformList(curShape),
box = curShape.getBBox(), box = curShape.getBBox(),
left = box.x, top = box.y, width = box.width, left = box.x, top = box.y, width = box.width,
height = box.height; height = box.height;
var dx = (x - startX), dy = (y - startY); var dx = (x - startX), dy = (y - startY);
var newbox = { var newbox = {
'x': Math.min(startX, x), 'x': Math.min(startX, x),
'y': Math.min(startY, y), 'y': Math.min(startY, y),
'width': Math.abs(x - startX), 'width': Math.abs(x - startX),
'height': Math.abs(y - startY) 'height': Math.abs(y - startY)
}; };
var tx = 0, ty = 0, var tx = 0, ty = 0,
sy = height ? (height + dy) / height : 1, sy = height ? (height + dy) / height : 1,
sx = width ? (width + dx) / width : 1; sx = width ? (width + dx) / width : 1;
sx = (newbox.width / lastBBox.width) || 1; sx = (newbox.width / lastBBox.width) || 1;
sy = (newbox.height / lastBBox.height) || 1; sy = (newbox.height / lastBBox.height) || 1;
// Not perfect, but mostly works... // Not perfect, but mostly works...
if (x < startX) { if (x < startX) {
tx = lastBBox.width; tx = lastBBox.width;
} }
if (y < startY) { ty = lastBBox.height; } if (y < startY) { ty = lastBBox.height; }
// update the transform list with translate,scale,translate // update the transform list with translate,scale,translate
var translateOrigin = svgroot.createSVGTransform(), var translateOrigin = svgroot.createSVGTransform(),
scale = svgroot.createSVGTransform(), scale = svgroot.createSVGTransform(),
translateBack = svgroot.createSVGTransform(); translateBack = svgroot.createSVGTransform();
translateOrigin.setTranslate(-(left + tx), -(top + ty)); translateOrigin.setTranslate(-(left + tx), -(top + ty));
if (!evt.shiftKey) { if (!evt.shiftKey) {
var max = Math.min(Math.abs(sx), Math.abs(sy)); var max = Math.min(Math.abs(sx), Math.abs(sy));
sx = max * (sx < 0 ? -1 : 1); sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1); sy = max * (sy < 0 ? -1 : 1);
} }
scale.setScale(sx, sy); scale.setScale(sx, sy);
translateBack.setTranslate(left + tx, top + ty); translateBack.setTranslate(left + tx, top + ty);
tlist.appendItem(translateBack); tlist.appendItem(translateBack);
tlist.appendItem(scale); tlist.appendItem(scale);
tlist.appendItem(translateOrigin); tlist.appendItem(translateOrigin);
canv.recalculateDimensions(curShape); canv.recalculateDimensions(curShape);
lastBBox = curShape.getBBox(); lastBBox = curShape.getBBox();
}, },
mouseUp: function (opts) { mouseUp: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
var keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y); var keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
return { return {
keep: keepObject, keep: keepObject,
element: curShape, element: curShape,
started: false started: false
}; };
} }
}; };
}); });

View File

@@ -10,225 +10,225 @@
*/ */
svgEditor.addExtension('star', function (S) { svgEditor.addExtension('star', function (S) {
'use strict'; 'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
selElems, selElems,
// editingitex = false, // editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
started, started,
newFO; newFO;
// edg = 0, // edg = 0,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, // newFOG, newFOGParent, newDef, newImageName, newMaskID,
// undoCommand = 'Not image', // undoCommand = 'Not image',
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH; // modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); var fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#star_panel').toggle(on); $('#star_panel').toggle(on);
} }
/* /*
function toggleSourceButtons(on){ function toggleSourceButtons(on){
$('#star_save, #star_cancel').toggle(on); $('#star_save, #star_cancel').toggle(on);
} }
*/ */
function setAttr (attr, val) { function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems); S.call('changed', selElems);
} }
/* /*
function cot(n){ function cot(n){
return 1 / Math.tan(n); return 1 / Math.tan(n);
} }
function sec(n){ function sec(n){
return 1 / Math.cos(n); return 1 / Math.cos(n);
} }
*/ */
return { return {
name: 'star', name: 'star',
svgicons: svgEditor.curConfig.extPath + 'star-icons.svg', svgicons: svgEditor.curConfig.extPath + 'star-icons.svg',
buttons: [{ buttons: [{
id: 'tool_star', id: 'tool_star',
type: 'mode', type: 'mode',
title: 'Star Tool', title: 'Star Tool',
position: 12, position: 12,
events: { events: {
click: function () { click: function () {
showPanel(true); showPanel(true);
svgCanvas.setMode('star'); svgCanvas.setMode('star');
} }
} }
}], }],
context_tools: [{ context_tools: [{
type: 'input', type: 'input',
panel: 'star_panel', panel: 'star_panel',
title: 'Number of Sides', title: 'Number of Sides',
id: 'starNumPoints', id: 'starNumPoints',
label: 'points', label: 'points',
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function () { change: function () {
setAttr('point', this.value); setAttr('point', this.value);
} }
} }
}, { }, {
type: 'input', type: 'input',
panel: 'star_panel', panel: 'star_panel',
title: 'Pointiness', title: 'Pointiness',
id: 'starRadiusMulitplier', id: 'starRadiusMulitplier',
label: 'Pointiness', label: 'Pointiness',
size: 3, size: 3,
defval: 2.5 defval: 2.5
}, { }, {
type: 'input', type: 'input',
panel: 'star_panel', panel: 'star_panel',
title: 'Twists the star', title: 'Twists the star',
id: 'radialShift', id: 'radialShift',
label: 'Radial Shift', label: 'Radial Shift',
size: 3, size: 3,
defval: 0, defval: 0,
events: { events: {
change: function () { change: function () {
setAttr('radialshift', this.value); setAttr('radialshift', this.value);
} }
} }
}], }],
callback: function () { callback: function () {
$('#star_panel').hide(); $('#star_panel').hide();
// var endChanges = function(){}; // var endChanges = function(){};
}, },
mouseDown: function (opts) { mouseDown: function (opts) {
var rgb = svgCanvas.getColor('fill'); var rgb = svgCanvas.getColor('fill');
// var ccRgbEl = rgb.substring(1, rgb.length); // var ccRgbEl = rgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor('stroke'); var sRgb = svgCanvas.getColor('stroke');
// var ccSRgbEl = sRgb.substring(1, rgb.length); // var ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); var sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
started = true; started = true;
newFO = S.addSvgElementFromJson({ newFO = S.addSvgElementFromJson({
'element': 'polygon', 'element': 'polygon',
'attr': { 'attr': {
'cx': opts.start_x, 'cx': opts.start_x,
'cy': opts.start_y, 'cy': opts.start_y,
'id': S.getNextId(), 'id': S.getNextId(),
'shape': 'star', 'shape': 'star',
'point': document.getElementById('starNumPoints').value, 'point': document.getElementById('starNumPoints').value,
'r': 0, 'r': 0,
'radialshift': document.getElementById('radialShift').value, 'radialshift': document.getElementById('radialShift').value,
'r2': 0, 'r2': 0,
'orient': 'point', 'orient': 'point',
'fill': rgb, 'fill': rgb,
'strokecolor': sRgb, 'strokecolor': sRgb,
'strokeWidth': sWidth 'strokeWidth': sWidth
} }
}); });
return { return {
started: true started: true
}; };
} }
}, },
mouseMove: function (opts) { mouseMove: function (opts) {
if (!started) { if (!started) {
return; return;
} }
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
var x = opts.mouse_x; var x = opts.mouse_x;
var y = opts.mouse_y; var y = opts.mouse_y;
var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']); var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, radialShift = c.radialshift, point = c.point, orient = c.orient, circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5, inradius = circumradius / document.getElementById('starRadiusMulitplier').value; var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, radialShift = c.radialshift, point = c.point, orient = c.orient, circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5, inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
newFO.setAttributeNS(null, 'r', circumradius); newFO.setAttributeNS(null, 'r', circumradius);
newFO.setAttributeNS(null, 'r2', inradius); newFO.setAttributeNS(null, 'r2', inradius);
var polyPoints = ''; var polyPoints = '';
var s; var s;
for (s = 0; point >= s; s++) { for (s = 0; point >= s; s++) {
var angle = 2.0 * Math.PI * (s / point); var angle = 2.0 * Math.PI * (s / point);
if (orient === 'point') { if (orient === 'point') {
angle -= (Math.PI / 2); angle -= (Math.PI / 2);
} else if (orient === 'edge') { } else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2); angle = (angle + (Math.PI / point)) - (Math.PI / 2);
} }
x = (circumradius * Math.cos(angle)) + cx; x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy; y = (circumradius * Math.sin(angle)) + cy;
polyPoints += x + ',' + y + ' '; polyPoints += x + ',' + y + ' ';
if (inradius != null) { if (inradius != null) {
angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point); angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point);
if (orient === 'point') { if (orient === 'point') {
angle -= (Math.PI / 2); angle -= (Math.PI / 2);
} else if (orient === 'edge') { } else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2); angle = (angle + (Math.PI / point)) - (Math.PI / 2);
} }
angle += radialShift; angle += radialShift;
x = (inradius * Math.cos(angle)) + cx; x = (inradius * Math.cos(angle)) + cx;
y = (inradius * Math.sin(angle)) + cy; y = (inradius * Math.sin(angle)) + cy;
polyPoints += x + ',' + y + ' '; polyPoints += x + ',' + y + ' ';
} }
} }
newFO.setAttributeNS(null, 'points', polyPoints); newFO.setAttributeNS(null, 'points', polyPoints);
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokewidth);
/* var shape = */ newFO.getAttributeNS(null, 'shape'); /* var shape = */ newFO.getAttributeNS(null, 'shape');
return { return {
started: true started: true
}; };
} }
}, },
mouseUp: function () { mouseUp: function () {
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
var attrs = $(newFO).attr(['r']); var attrs = $(newFO).attr(['r']);
// svgCanvas.addToSelection([newFO], true); // svgCanvas.addToSelection([newFO], true);
return { return {
keep: (attrs.r !== '0'), keep: (attrs.r !== '0'),
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'star') { if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
// $('#starRadiusMulitplier').val(elem.getAttribute('r2')); // $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
$('#starNumPoints').val(elem.getAttribute('point')); $('#starNumPoints').val(elem.getAttribute('point'));
$('#radialShift').val(elem.getAttribute('radialshift')); $('#radialShift').val(elem.getAttribute('radialshift'));
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
} }
} else { } else {
showPanel(false); showPanel(false);
} }
} }
}, },
elementChanged: function (opts) { elementChanged: function (opts) {
// var elem = opts.elems[0]; // var elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -21,265 +21,265 @@
/* /*
TODOS TODOS
1. Revisit on whether to use $.pref over directly setting curConfig in all 1. Revisit on whether to use $.pref over directly setting curConfig in all
extensions for a more public API (not only for extPath and imagePath, extensions for a more public API (not only for extPath and imagePath,
but other currently used config in the extensions) but other currently used config in the extensions)
2. We might provide control of storage settings through the UI besides the 2. We might provide control of storage settings through the UI besides the
initial (or URL-forced) dialog. initial (or URL-forced) dialog.
*/ */
svgEditor.addExtension('storage', function () { svgEditor.addExtension('storage', function () {
// We could empty any already-set data for users when they decline storage, // We could empty any already-set data for users when they decline storage,
// but it would be a risk for users who wanted to store but accidentally // but it would be a risk for users who wanted to store but accidentally
// said "no"; instead, we'll let those who already set it, delete it themselves; // said "no"; instead, we'll let those who already set it, delete it themselves;
// to change, set the "emptyStorageOnDecline" config setting to true // to change, set the "emptyStorageOnDecline" config setting to true
// in config.js. // in config.js.
var emptyStorageOnDecline = svgEditor.curConfig.emptyStorageOnDecline, var emptyStorageOnDecline = svgEditor.curConfig.emptyStorageOnDecline,
// When the code in svg-editor.js prevents local storage on load per // When the code in svg-editor.js prevents local storage on load per
// user request, we also prevent storing on unload here so as to // user request, we also prevent storing on unload here so as to
// avoid third-party sites making XSRF requests or providing links // avoid third-party sites making XSRF requests or providing links
// which would cause the user's local storage not to load and then // which would cause the user's local storage not to load and then
// upon page unload (such as the user closing the window), the storage // upon page unload (such as the user closing the window), the storage
// would thereby be set with an empty value, erasing any of the // would thereby be set with an empty value, erasing any of the
// user's prior work. To change this behavior so that no use of storage // user's prior work. To change this behavior so that no use of storage
// or adding of new storage takes place regardless of settings, set // or adding of new storage takes place regardless of settings, set
// the "noStorageOnLoad" config setting to true in config.js. // the "noStorageOnLoad" config setting to true in config.js.
noStorageOnLoad = svgEditor.curConfig.noStorageOnLoad, noStorageOnLoad = svgEditor.curConfig.noStorageOnLoad,
forceStorage = svgEditor.curConfig.forceStorage, forceStorage = svgEditor.curConfig.forceStorage,
storage = svgEditor.storage; storage = svgEditor.storage;
function replaceStoragePrompt (val) { function replaceStoragePrompt (val) {
val = val ? 'storagePrompt=' + val : ''; val = val ? 'storagePrompt=' + val : '';
var loc = top.location; // Allow this to work with the embedded editor as well var loc = top.location; // Allow this to work with the embedded editor as well
if (loc.href.indexOf('storagePrompt=') > -1) { if (loc.href.indexOf('storagePrompt=') > -1) {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) { loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
}); });
} else { } else {
loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val; loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val;
} }
} }
function setSVGContentStorage (val) { function setSVGContentStorage (val) {
if (storage) { if (storage) {
var name = 'svgedit-' + svgEditor.curConfig.canvasName; var name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) { if (!val) {
storage.removeItem(name); storage.removeItem(name);
} else { } else {
storage.setItem(name, val); storage.setItem(name, val);
} }
} }
} }
function expireCookie (cookie) { function expireCookie (cookie) {
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
} }
function removeStoragePrefCookie () { function removeStoragePrefCookie () {
expireCookie('store'); expireCookie('store');
} }
function emptyStorage () { function emptyStorage () {
setSVGContentStorage(''); setSVGContentStorage('');
var name; var name;
for (name in svgEditor.curPrefs) { for (name in svgEditor.curPrefs) {
if (svgEditor.curPrefs.hasOwnProperty(name)) { if (svgEditor.curPrefs.hasOwnProperty(name)) {
name = 'svg-edit-' + name; name = 'svg-edit-' + name;
if (storage) { if (storage) {
storage.removeItem(name); storage.removeItem(name);
} }
expireCookie(name); expireCookie(name);
} }
} }
} }
// emptyStorage(); // emptyStorage();
/** /**
* Listen for unloading: If and only if opted in by the user, set the content * Listen for unloading: If and only if opted in by the user, set the content
* document and preferences into storage: * document and preferences into storage:
* 1. Prevent save warnings (since we're automatically saving unsaved * 1. Prevent save warnings (since we're automatically saving unsaved
* content into storage) * content into storage)
* 2. Use localStorage to set SVG contents (potentially too large to allow in cookies) * 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
* 3. Use localStorage (where available) or cookies to set preferences. * 3. Use localStorage (where available) or cookies to set preferences.
*/ */
function setupBeforeUnloadListener () { function setupBeforeUnloadListener () {
window.addEventListener('beforeunload', function (e) { window.addEventListener('beforeunload', function (e) {
// Don't save anything unless the user opted in to storage // Don't save anything unless the user opted in to storage
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) { if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return; return;
} }
var key; var key;
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) { if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
setSVGContentStorage(svgCanvas.getSvgString()); setSVGContentStorage(svgCanvas.getSvgString());
} }
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
// svgEditor.showSaveWarning = false; // svgEditor.showSaveWarning = false;
var curPrefs = svgEditor.curPrefs; var curPrefs = svgEditor.curPrefs;
for (key in curPrefs) { for (key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
var val = curPrefs[key], var val = curPrefs[key],
store = (val !== undefined); store = (val !== undefined);
key = 'svg-edit-' + key; key = 'svg-edit-' + key;
if (!store) { if (!store) {
continue; continue;
} }
if (storage) { if (storage) {
storage.setItem(key, val); storage.setItem(key, val);
} else if (window.widget) { } else if (window.widget) {
widget.setPreferenceForKey(val, key); widget.setPreferenceForKey(val, key);
} else { } else {
val = encodeURIComponent(val); val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
} }
} }
} }
}, false); }, false);
} }
/* /*
// We could add locales here instead (and also thereby avoid the need // We could add locales here instead (and also thereby avoid the need
// to keep our content within "langReady"), but this would be less // to keep our content within "langReady"), but this would be less
// convenient for translators. // convenient for translators.
$.extend(uiStrings, {confirmSetStorage: { $.extend(uiStrings, {confirmSetStorage: {
message: "By default and where supported, SVG-Edit can store your editor "+ message: "By default and where supported, SVG-Edit can store your editor "+
"preferences and SVG content locally on your machine so you do not "+ "preferences and SVG content locally on your machine so you do not "+
"need to add these back each time you load SVG-Edit. If, for privacy "+ "need to add these back each time you load SVG-Edit. If, for privacy "+
"reasons, you do not wish to store this information on your machine, "+ "reasons, you do not wish to store this information on your machine, "+
"you can change away from the default option below.", "you can change away from the default option below.",
storagePrefsAndContent: "Store preferences and SVG content locally", storagePrefsAndContent: "Store preferences and SVG content locally",
storagePrefsOnly: "Only store preferences locally", storagePrefsOnly: "Only store preferences locally",
storagePrefs: "Store preferences locally", storagePrefs: "Store preferences locally",
storageNoPrefsOrContent: "Do not store my preferences or SVG content locally", storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
storageNoPrefs: "Do not store my preferences locally", storageNoPrefs: "Do not store my preferences locally",
rememberLabel: "Remember this choice?", rememberLabel: "Remember this choice?",
rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again." rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
}}); }});
*/ */
var loaded = false; var loaded = false;
return { return {
name: 'storage', name: 'storage',
langReady: function (data) { langReady: function (data) {
var // lang = data.lang, var // lang = data.lang,
uiStrings = data.uiStrings, // No need to store as dialog should only run once uiStrings = data.uiStrings, // No need to store as dialog should only run once
storagePrompt = $.deparam.querystring(true).storagePrompt; storagePrompt = $.deparam.querystring(true).storagePrompt;
// No need to run this one-time dialog again just because the user // No need to run this one-time dialog again just because the user
// changes the language // changes the language
if (loaded) { if (loaded) {
return; return;
} }
loaded = true; loaded = true;
// Note that the following can load even if "noStorageOnLoad" is // Note that the following can load even if "noStorageOnLoad" is
// set to false; to avoid any chance of storage, avoid this // set to false; to avoid any chance of storage, avoid this
// extension! (and to avoid using any prior storage, set the // extension! (and to avoid using any prior storage, set the
// config option "noStorageOnLoad" to true). // config option "noStorageOnLoad" to true).
if (!forceStorage && ( if (!forceStorage && (
// If the URL has been explicitly set to always prompt the // If the URL has been explicitly set to always prompt the
// user (e.g., so one can be pointed to a URL where one // user (e.g., so one can be pointed to a URL where one
// can alter one's settings, say to prevent future storage)... // can alter one's settings, say to prevent future storage)...
storagePrompt === true || storagePrompt === true ||
( (
// ...or...if the URL at least doesn't explicitly prevent a // ...or...if the URL at least doesn't explicitly prevent a
// storage prompt (as we use for users who // storage prompt (as we use for users who
// don't want to set cookies at all but who don't want // don't want to set cookies at all but who don't want
// continual prompts about it)... // continual prompts about it)...
storagePrompt !== false && storagePrompt !== false &&
// ...and this user hasn't previously indicated a desire for storage // ...and this user hasn't previously indicated a desire for storage
!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/) !document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)
) )
// ...then show the storage prompt. // ...then show the storage prompt.
)) { )) {
var options = []; var options = [];
if (storage) { if (storage) {
options.unshift( options.unshift(
{value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent}, {value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent},
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly}, {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent} {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
); );
} else { } else {
options.unshift( options.unshift(
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs}, {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs} {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
); );
} }
// Hack to temporarily provide a wide and high enough dialog // Hack to temporarily provide a wide and high enough dialog
var oldContainerWidth = $('#dialog_container')[0].style.width, var oldContainerWidth = $('#dialog_container')[0].style.width,
oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft, oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
oldContentHeight = $('#dialog_content')[0].style.height, oldContentHeight = $('#dialog_content')[0].style.height,
oldContainerHeight = $('#dialog_container')[0].style.height; oldContainerHeight = $('#dialog_container')[0].style.height;
$('#dialog_content')[0].style.height = '120px'; $('#dialog_content')[0].style.height = '120px';
$('#dialog_container')[0].style.height = '170px'; $('#dialog_container')[0].style.height = '170px';
$('#dialog_container')[0].style.width = '800px'; $('#dialog_container')[0].style.width = '800px';
$('#dialog_container')[0].style.marginLeft = '-400px'; $('#dialog_container')[0].style.marginLeft = '-400px';
// Open select-with-checkbox dialog // Open select-with-checkbox dialog
$.select( $.select(
uiStrings.confirmSetStorage.message, uiStrings.confirmSetStorage.message,
options, options,
function (pref, checked) { function (pref, checked) {
if (pref && pref !== 'noPrefsOrContent') { if (pref && pref !== 'noPrefsOrContent') {
// Regardless of whether the user opted // Regardless of whether the user opted
// to remember the choice (and move to a URL which won't // to remember the choice (and move to a URL which won't
// ask them again), we have to assume the user // ask them again), we have to assume the user
// doesn't even want to remember their not wanting // doesn't even want to remember their not wanting
// storage, so we don't set the cookie or continue on with // storage, so we don't set the cookie or continue on with
// setting storage on beforeunload // setting storage on beforeunload
document.cookie = 'store=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly' document.cookie = 'store=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'
// If the URL was configured to always insist on a prompt, if // If the URL was configured to always insist on a prompt, if
// the user does indicate a wish to store their info, we // the user does indicate a wish to store their info, we
// don't want ask them again upon page refresh so move // don't want ask them again upon page refresh so move
// them instead to a URL which does not always prompt // them instead to a URL which does not always prompt
if (storagePrompt === true && checked) { if (storagePrompt === true && checked) {
replaceStoragePrompt(); replaceStoragePrompt();
return; return;
} }
} else { // The user does not wish storage (or cancelled, which we treat equivalently) } else { // The user does not wish storage (or cancelled, which we treat equivalently)
removeStoragePrefCookie(); removeStoragePrefCookie();
if (pref && // If the user explicitly expresses wish for no storage if (pref && // If the user explicitly expresses wish for no storage
emptyStorageOnDecline emptyStorageOnDecline
) { ) {
emptyStorage(); emptyStorage();
} }
if (pref && checked) { if (pref && checked) {
// Open a URL which won't set storage and won't prompt user about storage // Open a URL which won't set storage and won't prompt user about storage
replaceStoragePrompt('false'); replaceStoragePrompt('false');
return; return;
} }
} }
// Reset width/height of dialog (e.g., for use by Export) // Reset width/height of dialog (e.g., for use by Export)
$('#dialog_container')[0].style.width = oldContainerWidth; $('#dialog_container')[0].style.width = oldContainerWidth;
$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft; $('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
$('#dialog_content')[0].style.height = oldContentHeight; $('#dialog_content')[0].style.height = oldContentHeight;
$('#dialog_container')[0].style.height = oldContainerHeight; $('#dialog_container')[0].style.height = oldContainerHeight;
// It should be enough to (conditionally) add to storage on // It should be enough to (conditionally) add to storage on
// beforeunload, but if we wished to update immediately, // beforeunload, but if we wished to update immediately,
// we might wish to try setting: // we might wish to try setting:
// svgEditor.setConfig({noStorageOnLoad: true}); // svgEditor.setConfig({noStorageOnLoad: true});
// and then call: // and then call:
// svgEditor.loadContentAndPrefs(); // svgEditor.loadContentAndPrefs();
// We don't check for noStorageOnLoad here because // We don't check for noStorageOnLoad here because
// the prompt gives the user the option to store data // the prompt gives the user the option to store data
setupBeforeUnloadListener(); setupBeforeUnloadListener();
svgEditor.storagePromptClosed = true; svgEditor.storagePromptClosed = true;
}, },
null, null,
null, null,
{ {
label: uiStrings.confirmSetStorage.rememberLabel, label: uiStrings.confirmSetStorage.rememberLabel,
checked: false, checked: false,
tooltip: uiStrings.confirmSetStorage.rememberTooltip tooltip: uiStrings.confirmSetStorage.rememberTooltip
} }
); );
} else if (!noStorageOnLoad || forceStorage) { } else if (!noStorageOnLoad || forceStorage) {
setupBeforeUnloadListener(); setupBeforeUnloadListener();
} }
} }
}; };
}); });

View File

@@ -10,58 +10,58 @@ Todos:
'use strict'; 'use strict';
var pathID, var pathID,
saveMessage = 'webapp-save', saveMessage = 'webapp-save',
readMessage = 'webapp-read', readMessage = 'webapp-read',
excludedMessages = [readMessage, saveMessage]; excludedMessages = [readMessage, saveMessage];
window.addEventListener('message', function (e) { window.addEventListener('message', function (e) {
if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively) if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively)
(!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below (!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below
) { ) {
return; return;
} }
var svgString, var svgString,
messageType = e.data[0]; messageType = e.data[0];
switch (messageType) { switch (messageType) {
case 'webapp-view': case 'webapp-view':
// Populate the contents // Populate the contents
pathID = e.data[1]; pathID = e.data[1];
svgString = e.data[2]; svgString = e.data[2];
svgEditor.loadFromString(svgString); svgEditor.loadFromString(svgString);
/* if ($('#tool_save_file')) { /* if ($('#tool_save_file')) {
$('#tool_save_file').disabled = false; $('#tool_save_file').disabled = false;
} */ } */
break; break;
case 'webapp-save-end': case 'webapp-save-end':
alert('save complete for pathID ' + e.data[1] + '!'); alert('save complete for pathID ' + e.data[1] + '!');
break; break;
default: default:
throw new Error('Unexpected mode'); throw new Error('Unexpected mode');
} }
}, false); }, false);
window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on) window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on)
svgEditor.addExtension('WebAppFind', function () { svgEditor.addExtension('WebAppFind', function () {
return { return {
name: 'WebAppFind', name: 'WebAppFind',
svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg', svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg',
buttons: [{ buttons: [{
id: 'webappfind_save', // id: 'webappfind_save', //
type: 'app_menu', type: 'app_menu',
title: 'Save Image back to Disk', title: 'Save Image back to Disk',
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)") position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
events: { events: {
click: function () { click: function () {
if (!pathID) { // Not ready yet as haven't received first payload if (!pathID) { // Not ready yet as haven't received first payload
return; return;
} }
window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin); window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin);
} }
} }
}] }]
}; };
}); });
}()); }());

View File

@@ -6,38 +6,38 @@
* in embedapi.js with a demo at embedapi.html * in embedapi.js with a demo at embedapi.html
*/ */
svgEditor.addExtension('xdomain-messaging', function () { svgEditor.addExtension('xdomain-messaging', function () {
'use strict'; 'use strict';
try { try {
window.addEventListener('message', function (e) { window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support // We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') { if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return; return;
} }
var cbid, name, args, message, allowedOrigins, data = JSON.parse(e.data); var cbid, name, args, message, allowedOrigins, data = JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') { if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') {
return; return;
} }
// The default is not to allow any origins, including even the same domain or if run on a file:// URL // The default is not to allow any origins, including even the same domain or if run on a file:// URL
// See config-sample.js for an example of how to configure // See config-sample.js for an example of how to configure
allowedOrigins = svgEditor.curConfig.allowedOrigins; allowedOrigins = svgEditor.curConfig.allowedOrigins;
if (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) { if (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) {
return; return;
} }
cbid = data.id; cbid = data.id;
name = data.name; name = data.name;
args = data.args; args = data.args;
message = { message = {
namespace: 'svg-edit', namespace: 'svg-edit',
id: cbid id: cbid
}; };
try { try {
message.result = svgCanvas[name].apply(svgCanvas, args); message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) { } catch (err) {
message.error = err.message; message.error = err.message;
} }
e.source.postMessage(JSON.stringify(message), '*'); e.source.postMessage(JSON.stringify(message), '*');
}, false); }, false);
} catch (err) { } catch (err) {
console.log('Error with xdomain message listener: ' + err); console.log('Error with xdomain message listener: ' + err);
} }
}); });

View File

@@ -1,51 +1,51 @@
/* eslint-disable no-var */ /* eslint-disable no-var */
/* globals $ */ /* globals $ */
$('a').click(function () { $('a').click(function () {
'use strict'; 'use strict';
var metaStr; var metaStr;
var href = this.href; var href = this.href;
var target = window.parent; var target = window.parent;
// Convert Non-SVG images to data URL first // Convert Non-SVG images to data URL first
// (this could also have been done server-side by the library) // (this could also have been done server-side by the library)
if (this.href.indexOf('.svg') === -1) { if (this.href.indexOf('.svg') === -1) {
metaStr = JSON.stringify({ metaStr = JSON.stringify({
name: $(this).text(), name: $(this).text(),
id: href id: href
}); });
target.postMessage(metaStr, '*'); target.postMessage(metaStr, '*');
var img = new Image(); var img = new Image();
img.onload = function () { img.onload = function () {
var canvas = document.createElement('canvas'); var canvas = document.createElement('canvas');
canvas.width = this.width; canvas.width = this.width;
canvas.height = this.height; canvas.height = this.height;
// load the raster image into the canvas // load the raster image into the canvas
canvas.getContext('2d').drawImage(this, 0, 0); canvas.getContext('2d').drawImage(this, 0, 0);
// retrieve the data: URL // retrieve the data: URL
var dataurl; var dataurl;
try { try {
dataurl = canvas.toDataURL(); dataurl = canvas.toDataURL();
} catch (err) { } catch (err) {
// This fails in Firefox with file:// URLs :( // This fails in Firefox with file:// URLs :(
alert('Data URL conversion failed: ' + err); alert('Data URL conversion failed: ' + err);
dataurl = ''; dataurl = '';
} }
target.postMessage('|' + href + '|' + dataurl, '*'); target.postMessage('|' + href + '|' + dataurl, '*');
}; };
img.src = href; img.src = href;
} else { } else {
// Send metadata (also indicates file is about to be sent) // Send metadata (also indicates file is about to be sent)
metaStr = JSON.stringify({ metaStr = JSON.stringify({
name: $(this).text(), name: $(this).text(),
id: href id: href
}); });
target.postMessage(metaStr, '*'); target.postMessage(metaStr, '*');
// Do ajax request for image's href value // Do ajax request for image's href value
$.get(href, function (data) { $.get(href, function (data) {
data = '|' + href + '|' + data; data = '|' + href + '|' + data;
// This is where the magic happens! // This is where the magic happens!
target.postMessage(data, '*'); target.postMessage(data, '*');
}, 'html'); // 'html' is necessary to keep returned data as a string }, 'html'); // 'html' is necessary to keep returned data as a string
} }
return false; return false;
}); });