diff --git a/editor/extensions/ext-arrows.js b/editor/extensions/ext-arrows.js index cd00b119..cb8fb612 100644 --- a/editor/extensions/ext-arrows.js +++ b/editor/extensions/ext-arrows.js @@ -10,283 +10,283 @@ */ svgEditor.addExtension('Arrows', function (S) { - var // svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomizeIds = S.randomize_ids, - selElems, pathdata, - langList = { - 'en': [ - {'id': 'arrow_none', 'textContent': 'No arrow'} - ], - 'fr': [ - {'id': 'arrow_none', 'textContent': 'Sans flèche'} - ] - }, - arrowprefix, - prefix = 'se_arrow_'; + var // svgcontent = S.svgcontent, + addElem = S.addSvgElementFromJson, + nonce = S.nonce, + randomizeIds = S.randomize_ids, + selElems, pathdata, + langList = { + 'en': [ + {'id': 'arrow_none', 'textContent': 'No arrow'} + ], + 'fr': [ + {'id': 'arrow_none', 'textContent': 'Sans flèche'} + ] + }, + arrowprefix, + prefix = 'se_arrow_'; - function setArrowNonce (window, n) { - randomizeIds = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } + function setArrowNonce (window, n) { + randomizeIds = true; + arrowprefix = prefix + n + '_'; + pathdata.fw.id = arrowprefix + 'fw'; + pathdata.bk.id = arrowprefix + 'bk'; + } - function unsetArrowNonce (window) { - randomizeIds = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } + function unsetArrowNonce (window) { + randomizeIds = false; + arrowprefix = prefix; + pathdata.fw.id = arrowprefix + 'fw'; + pathdata.bk.id = arrowprefix + 'bk'; + } - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); + svgCanvas.bind('setnonce', setArrowNonce); + svgCanvas.bind('unsetnonce', unsetArrowNonce); - if (randomizeIds) { - arrowprefix = prefix + nonce + '_'; - } else { - arrowprefix = prefix; - } + if (randomizeIds) { + arrowprefix = prefix + nonce + '_'; + } else { + arrowprefix = prefix; + } - pathdata = { - 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'} - }; + pathdata = { + 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'} + }; - function getLinked (elem, attr) { - var str = elem.getAttribute(attr); - if (!str) { return null; } - var m = str.match(/\(#(.*)\)/); - if (!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } + function getLinked (elem, attr) { + var str = elem.getAttribute(attr); + if (!str) { return null; } + var m = str.match(/\(#(.*)\)/); + if (!m || m.length !== 2) { + return null; + } + return S.getElem(m[1]); + } - function showPanel (on) { - $('#arrow_panel').toggle(on); - if (on) { - var el = selElems[0]; - var end = el.getAttribute('marker-end'); - var start = el.getAttribute('marker-start'); - var mid = el.getAttribute('marker-mid'); - var val; + function showPanel (on) { + $('#arrow_panel').toggle(on); + if (on) { + var el = selElems[0]; + var end = el.getAttribute('marker-end'); + var start = el.getAttribute('marker-start'); + var mid = el.getAttribute('marker-mid'); + var val; - if (end && start) { - val = 'both'; - } else if (end) { - val = 'end'; - } else if (start) { - val = 'start'; - } else if (mid) { - val = 'mid'; - if (mid.indexOf('bk') !== -1) { - val = 'mid_bk'; - } - } + if (end && start) { + val = 'both'; + } else if (end) { + val = 'end'; + } else if (start) { + val = 'start'; + } else if (mid) { + val = 'mid'; + if (mid.indexOf('bk') !== -1) { + val = 'mid_bk'; + } + } - if (!start && !mid && !end) { - val = 'none'; - } + if (!start && !mid && !end) { + val = 'none'; + } - $('#arrow_list').val(val); - } - } + $('#arrow_list').val(val); + } + } - function resetMarker () { - var el = selElems[0]; - el.removeAttribute('marker-start'); - el.removeAttribute('marker-mid'); - el.removeAttribute('marker-end'); - } + function resetMarker () { + var el = selElems[0]; + el.removeAttribute('marker-start'); + el.removeAttribute('marker-mid'); + el.removeAttribute('marker-end'); + } - function addMarker (dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; + function addMarker (dir, type, id) { + // TODO: Make marker (or use?) per arrow type, since refX can be different + id = id || arrowprefix + dir; - var marker = S.getElem(id); - var data = pathdata[dir]; + var marker = S.getElem(id); + var data = pathdata[dir]; - if (type === 'mid') { - data.refx = 5; - } + if (type === 'mid') { + data.refx = 5; + } - if (!marker) { - marker = addElem({ - 'element': 'marker', - 'attr': { - 'viewBox': '0 0 10 10', - 'id': id, - 'refY': 5, - 'markerUnits': 'strokeWidth', - 'markerWidth': 5, - 'markerHeight': 5, - 'orient': 'auto', - 'style': 'pointer-events:none' // Currently needed for Opera - } - }); - var arrow = addElem({ - 'element': 'path', - 'attr': { - 'd': data.d, - 'fill': '#000000' - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } + if (!marker) { + marker = addElem({ + 'element': 'marker', + 'attr': { + 'viewBox': '0 0 10 10', + 'id': id, + 'refY': 5, + 'markerUnits': 'strokeWidth', + 'markerWidth': 5, + 'markerHeight': 5, + 'orient': 'auto', + 'style': 'pointer-events:none' // Currently needed for Opera + } + }); + var arrow = addElem({ + 'element': 'path', + 'attr': { + 'd': data.d, + 'fill': '#000000' + } + }); + marker.appendChild(arrow); + S.findDefs().appendChild(marker); + } - marker.setAttribute('refX', data.refx); + marker.setAttribute('refX', data.refx); - return marker; - } + return marker; + } - function setArrow () { - var type = this.value; - resetMarker(); + function setArrow () { + var type = this.value; + resetMarker(); - if (type === 'none') { - return; - } + if (type === 'none') { + return; + } - // Set marker on element - var dir = 'fw'; - if (type === 'mid_bk') { - type = 'mid'; - dir = 'bk'; - } else if (type === 'both') { - addMarker('bk', type); - svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); - type = 'end'; - dir = 'fw'; - } else if (type === 'start') { - dir = 'bk'; - } + // Set marker on element + var dir = 'fw'; + if (type === 'mid_bk') { + type = 'mid'; + dir = 'bk'; + } else if (type === 'both') { + addMarker('bk', type); + svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); + type = 'end'; + dir = 'fw'; + } else if (type === 'start') { + dir = 'bk'; + } - addMarker(dir, type); - svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); - S.call('changed', selElems); - } + addMarker(dir, type); + svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); + S.call('changed', selElems); + } - function colorChanged (elem) { - var color = elem.getAttribute('stroke'); - var mtypes = ['start', 'mid', 'end']; - var defs = S.findDefs(); + function colorChanged (elem) { + var color = elem.getAttribute('stroke'); + var mtypes = ['start', 'mid', 'end']; + var defs = S.findDefs(); - $.each(mtypes, function (i, type) { - var marker = getLinked(elem, 'marker-' + type); - if (!marker) { return; } + $.each(mtypes, function (i, type) { + var marker = getLinked(elem, 'marker-' + type); + if (!marker) { return; } - var curColor = $(marker).children().attr('fill'); - var curD = $(marker).children().attr('d'); - var newMarker = null; - if (curColor === color) { return; } + var curColor = $(marker).children().attr('fill'); + var curD = $(marker).children().attr('d'); + var newMarker = null; + if (curColor === color) { return; } - var allMarkers = $(defs).find('marker'); - // Different color, check if already made - allMarkers.each(function () { - var attrs = $(this).children().attr(['fill', 'd']); - if (attrs.fill === color && attrs.d === curD) { - // Found another marker with this color and this path - newMarker = this; - } - }); + var allMarkers = $(defs).find('marker'); + // Different color, check if already made + allMarkers.each(function () { + var attrs = $(this).children().attr(['fill', 'd']); + if (attrs.fill === color && attrs.d === curD) { + // Found another marker with this color and this path + newMarker = this; + } + }); - if (!newMarker) { - // Create a new marker with this color - var lastId = marker.id; - var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk'; + if (!newMarker) { + // Create a new marker with this color + var lastId = marker.id; + 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 - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function () { - var elem = this; - $.each(mtypes, function (j, mtype) { - if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { - remove = false; - return remove; - } - }); - if (!remove) { return false; } - }); + // Check if last marker can be removed + var remove = true; + $(S.svgcontent).find('line, polyline, path, polygon').each(function () { + var elem = this; + $.each(mtypes, function (j, mtype) { + if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { + remove = false; + return remove; + } + }); + if (!remove) { return false; } + }); - // Not found, so can safely remove - if (remove) { - $(marker).remove(); - } - }); - } + // Not found, so can safely remove + if (remove) { + $(marker).remove(); + } + }); + } - return { - name: 'Arrows', - context_tools: [{ - type: 'select', - panel: 'arrow_panel', - title: 'Select arrow type', - id: 'arrow_list', - options: { - none: 'No arrow', - end: '---->', - start: '<----', - both: '<--->', - mid: '-->--', - mid_bk: '--<--' - }, - defval: 'none', - events: { - change: setArrow - } - }], - callback: function () { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function (lang) { - return { - data: langList[lang] - }; - }, - selectedChanged: function (opts) { - // Use this to update the current selected elements - selElems = opts.elems; + return { + name: 'Arrows', + context_tools: [{ + type: 'select', + panel: 'arrow_panel', + title: 'Select arrow type', + id: 'arrow_list', + options: { + none: 'No arrow', + end: '---->', + start: '<----', + both: '<--->', + mid: '-->--', + mid_bk: '--<--' + }, + defval: 'none', + events: { + change: setArrow + } + }], + callback: function () { + $('#arrow_panel').hide(); + // Set ID so it can be translated in locale file + $('#arrow_list option')[0].id = 'connector_no_arrow'; + }, + addLangData: function (lang) { + return { + data: langList[lang] + }; + }, + selectedChanged: function (opts) { + // Use this to update the current selected elements + selElems = opts.elems; - var i = selElems.length; - var markerElems = ['line', 'path', 'polyline', 'polygon']; - while (i--) { - var elem = selElems[i]; - if (elem && $.inArray(elem.tagName, markerElems) !== -1) { - if (opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function (opts) { - var elem = opts.elems[0]; - if (elem && ( - elem.getAttribute('marker-start') || - elem.getAttribute('marker-mid') || - elem.getAttribute('marker-end') - )) { - // var start = elem.getAttribute('marker-start'); - // var mid = elem.getAttribute('marker-mid'); - // var end = elem.getAttribute('marker-end'); - // Has marker, so see if it should match color - colorChanged(elem); - } - } - }; + var i = selElems.length; + var markerElems = ['line', 'path', 'polyline', 'polygon']; + while (i--) { + var elem = selElems[i]; + if (elem && $.inArray(elem.tagName, markerElems) !== -1) { + if (opts.selectedElement && !opts.multiselected) { + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + }, + elementChanged: function (opts) { + var elem = opts.elems[0]; + if (elem && ( + elem.getAttribute('marker-start') || + elem.getAttribute('marker-mid') || + elem.getAttribute('marker-end') + )) { + // var start = elem.getAttribute('marker-start'); + // var mid = elem.getAttribute('marker-mid'); + // var end = elem.getAttribute('marker-end'); + // Has marker, so see if it should match color + colorChanged(elem); + } + } + }; }); diff --git a/editor/extensions/ext-closepath.js b/editor/extensions/ext-closepath.js index 23adae60..c1a5dd7d 100644 --- a/editor/extensions/ext-closepath.js +++ b/editor/extensions/ext-closepath.js @@ -12,81 +12,81 @@ // This extension adds a simple button to the contextual panel for paths // The button toggles whether the path is open or closed svgEditor.addExtension('ClosePath', function () { - 'use strict'; - var selElems, - updateButton = function (path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function (on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) { updateButton(path); } - } - }, - toggleClosed = function () { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if (seglist.getItem(last).pathSegType === 1) { - seglist.removeItem(last); - } else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; + 'use strict'; + var selElems, + updateButton = function (path) { + var seglist = path.pathSegList, + closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, + showbutton = closed ? '#tool_openpath' : '#tool_closepath', + hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; + $(hidebutton).hide(); + $(showbutton).show(); + }, + showPanel = function (on) { + $('#closepath_panel').toggle(on); + if (on) { + var path = selElems[0]; + if (path) { updateButton(path); } + } + }, + toggleClosed = function () { + var path = selElems[0]; + if (path) { + var seglist = path.pathSegList, + last = seglist.numberOfItems - 1; + // is closed + if (seglist.getItem(last).pathSegType === 1) { + seglist.removeItem(last); + } else { + seglist.appendItem(path.createSVGPathSegClosePath()); + } + updateButton(path); + } + }; - return { - name: 'ClosePath', - svgicons: svgEditor.curConfig.extPath + 'closepath_icons.svg', - buttons: [{ - id: 'tool_openpath', - type: 'context', - panel: 'closepath_panel', - title: 'Open path', - events: { - click: function () { - toggleClosed(); - } - } - }, - { - id: 'tool_closepath', - type: 'context', - panel: 'closepath_panel', - title: 'Close path', - events: { - click: function () { - toggleClosed(); - } - } - }], - callback: function () { - $('#closepath_panel').hide(); - }, - selectedChanged: function (opts) { - selElems = opts.elems; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && elem.tagName === 'path') { - if (opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; + return { + name: 'ClosePath', + svgicons: svgEditor.curConfig.extPath + 'closepath_icons.svg', + buttons: [{ + id: 'tool_openpath', + type: 'context', + panel: 'closepath_panel', + title: 'Open path', + events: { + click: function () { + toggleClosed(); + } + } + }, + { + id: 'tool_closepath', + type: 'context', + panel: 'closepath_panel', + title: 'Close path', + events: { + click: function () { + toggleClosed(); + } + } + }], + callback: function () { + $('#closepath_panel').hide(); + }, + selectedChanged: function (opts) { + selElems = opts.elems; + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (elem && elem.tagName === 'path') { + if (opts.selectedElement && !opts.multiselected) { + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + } + }; }); diff --git a/editor/extensions/ext-connector.js b/editor/extensions/ext-connector.js index f41a5e15..700bc402 100644 --- a/editor/extensions/ext-connector.js +++ b/editor/extensions/ext-connector.js @@ -10,605 +10,605 @@ */ svgEditor.addExtension('Connector', function (S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = svgEditor.curConfig, - started = false, - startX, - startY, - curLine, - startElem, - endElem, - connections = [], - connSel = '.se_connector', - seNs, - // connect_str = '-SE_CONNECT-', - selElems = [], - elData = $.data; - - var langList = { - 'en': [ - {'id': 'mode_connect', 'title': 'Connect two objects'} - ], - 'fr': [ - {'id': 'mode_connect', 'title': 'Connecter deux objets'} - ] - }; - - function getBBintersect (x, y, bb, offset) { - if (offset) { - offset -= 0; - bb = $.extend({}, bb); - bb.width += offset; - bb.height += offset; - bb.x -= offset / 2; - bb.y -= offset / 2; - } - - var midX = bb.x + bb.width / 2; - var midY = bb.y + bb.height / 2; - var lenX = x - midX; - var lenY = y - midY; - - var slope = Math.abs(lenY / lenX); - - var ratio; - - if (slope < bb.height / bb.width) { - ratio = (bb.width / 2) / Math.abs(lenX); - } else { - ratio = (bb.height / 2) / Math.abs(lenY); - } - - return { - x: midX + lenX * ratio, - y: midY + lenY * ratio - }; - } - - function getOffset (side, line) { - var giveOffset = !!line.getAttribute('marker-' + side); - // var giveOffset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return giveOffset ? size : 0; - } - - function showPanel (on) { - var connRules = $('#connector_rules'); - if (!connRules.length) { - connRules = $('').appendTo('head'); - } - connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }'); - $('#connector_panel').toggle(on); - } - - function setPoint (elem, pos, x, y, setMid) { - var i, pts = elem.points; - var pt = svgroot.createSVGPoint(); - pt.x = x; - pt.y = y; - if (pos === 'end') { pos = pts.numberOfItems - 1; } - // TODO: Test for this on init, then use alt only if needed - try { - pts.replaceItem(pt, pos); - } catch (err) { - // Should only occur in FF which formats points attr as "n,n n,n", so just split - var ptArr = elem.getAttribute('points').split(' '); - for (i = 0; i < ptArr.length; i++) { - if (i === pos) { - ptArr[i] = x + ',' + y; - } - } - elem.setAttribute('points', ptArr.join(' ')); - } - - if (setMid) { - // Add center point - var ptStart = pts.getItem(0); - var ptEnd = pts.getItem(pts.numberOfItems - 1); - setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2); - } - } - - function updateLine (diffX, diffY) { - // Update line with element - var i = connections.length; - while (i--) { - var conn = connections[i]; - var line = conn.connector; - // var elem = conn.elem; - - var pre = conn.is_start ? 'start' : 'end'; - // var sw = line.getAttribute('stroke-width') * 5; - - // Update bbox for this element - var bb = elData(line, pre + '_bb'); - bb.x = conn.start_x + diffX; - bb.y = conn.start_y + diffY; - elData(line, pre + '_bb', bb); - - var altPre = conn.is_start ? 'end' : 'start'; - - // Get center pt of connected element - var bb2 = elData(line, altPre + '_bb'); - var srcX = bb2.x + bb2.width / 2; - var srcY = bb2.y + bb2.height / 2; - - // Set point of element being moved - var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 - setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); - - // Set point of connected element - var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); - setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); - } - } - - function findConnectors (elems) { - var i; - if (!elems) { elems = selElems; } - var connectors = $(svgcontent).find(connSel); - connections = []; - - // Loop through connectors to see if one is connected to the element - connectors.each(function () { - var addThis; - function add () { - if ($.inArray(this, elems) !== -1) { - // Pretend this element is selected - addThis = true; - } - } - - // Grab the ends - var parts = []; - ['start', 'end'].forEach(function (pos, i) { - var key = 'c_' + pos; - var part = elData(this, key); - if (part == null) { - part = document.getElementById( - this.attributes['se:connector'].value.split(' ')[i] - ); - elData(this, 'c_' + pos, part.id); - elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part])); - } else part = document.getElementById(part); - parts.push(part); - }.bind(this)); - - for (i = 0; i < 2; i++) { - var cElem = parts[i]; - - addThis = false; - // The connected element might be part of a selected group - $(cElem).parents().each(add); - - if (!cElem || !cElem.parentNode) { - $(this).remove(); - continue; - } - if ($.inArray(cElem, elems) !== -1 || addThis) { - var bb = svgCanvas.getStrokedBBox([cElem]); - connections.push({ - elem: cElem, - connector: this, - is_start: (i === 0), - start_x: bb.x, - start_y: bb.y - }); - } - } - }); - } - - function updateConnectors (elems) { - // Updates connector lines based on selected elements - // Is not used on mousemove, as it runs getStrokedBBox every time, - // which isn't necessary there. - var i, j; - findConnectors(elems); - if (connections.length) { - // Update line with element - i = connections.length; - while (i--) { - var conn = connections[i]; - var line = conn.connector; - var elem = conn.elem; - - // var sw = line.getAttribute('stroke-width') * 5; - var pre = conn.is_start ? 'start' : 'end'; - - // Update bbox for this element - var bb = svgCanvas.getStrokedBBox([elem]); - bb.x = conn.start_x; - bb.y = conn.start_y; - elData(line, pre + '_bb', bb); - /* var addOffset = */ elData(line, pre + '_off'); - - var altPre = conn.is_start ? 'end' : 'start'; - - // Get center pt of connected element - var bb2 = elData(line, altPre + '_bb'); - var srcX = bb2.x + bb2.width / 2; - var srcY = bb2.y + bb2.height / 2; - - // Set point of element being moved - var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); - setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); - - // Set point of connected element - var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); - setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); - - // Update points attribute manually for webkit - if (navigator.userAgent.indexOf('AppleWebKit') !== -1) { - var pts = line.points; - var len = pts.numberOfItems; - var ptArr = []; - for (j = 0; j < len; j++) { - pt = pts.getItem(j); - ptArr[j] = pt.x + ',' + pt.y; - } - line.setAttribute('points', ptArr.join(' ')); - } - } - } - } - - // Do once - (function () { - var gse = svgCanvas.groupSelectedElements; - - svgCanvas.groupSelectedElements = function () { - svgCanvas.removeFromSelection($(connSel).toArray()); - return gse.apply(this, arguments); - }; - - var mse = svgCanvas.moveSelectedElements; - - svgCanvas.moveSelectedElements = function () { - var cmd = mse.apply(this, arguments); - updateConnectors(); - return cmd; - }; - - seNs = svgCanvas.getEditorNS(); - }()); - - // Do on reset - function init () { - // Make sure all connectors have data set - $(svgcontent).find('*').each(function () { - var conn = this.getAttributeNS(seNs, 'connector'); - if (conn) { - this.setAttribute('class', connSel.substr(1)); - var connData = conn.split(' '); - var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]); - var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]); - $(this).data('c_start', connData[0]) - .data('c_end', connData[1]) - .data('start_bb', sbb) - .data('end_bb', ebb); - svgCanvas.getEditorNS(true); - } - }); - // updateConnectors(); - } - - // $(svgroot).parent().mousemove(function (e) { - // // if (started - // // || svgCanvas.getMode() !== 'connector' - // // || e.target.parentNode.parentNode !== svgcontent) return; - // - // console.log('y') - // // if (e.target.parentNode.parentNode === svgcontent) { - // // - // // } - // }); - - return { - name: 'Connector', - svgicons: svgEditor.curConfig.imgPath + 'conn.svg', - buttons: [{ - id: 'mode_connect', - type: 'mode', - icon: svgEditor.curConfig.imgPath + 'cut.png', - title: 'Connect two objects', - includeWith: { - button: '#tool_line', - isDefault: false, - position: 1 - }, - events: { - 'click': function () { - svgCanvas.setMode('connector'); - } - } - }], - addLangData: function (lang) { - return { - data: langList[lang] - }; - }, - mouseDown: function (opts) { - var e = opts.event; - startX = opts.start_x; - startY = opts.start_y; - var mode = svgCanvas.getMode(); - - if (mode === 'connector') { - if (started) { return; } - - var mouseTarget = e.target; - - var parents = $(mouseTarget).parents(); - - if ($.inArray(svgcontent, parents) !== -1) { - // Connectable element - - // If child of foreignObject, use parent - var fo = $(mouseTarget).closest('foreignObject'); - startElem = fo.length ? fo[0] : mouseTarget; - - // Get center of source element - var bb = svgCanvas.getStrokedBBox([startElem]); - var x = bb.x + bb.width / 2; - var y = bb.y + bb.height / 2; - - started = true; - curLine = addElem({ - 'element': 'polyline', - 'attr': { - 'id': getNextId(), - 'points': (x + ',' + y + ' ' + x + ',' + y + ' ' + startX + ',' + startY), - 'stroke': '#' + curConfig.initStroke.color, - 'stroke-width': (!startElem.stroke_width || startElem.stroke_width === 0) ? curConfig.initStroke.width : startElem.stroke_width, - 'fill': 'none', - 'opacity': curConfig.initStroke.opacity, - 'style': 'pointer-events:none' - } - }); - elData(curLine, 'start_bb', bb); - } - return { - started: true - }; - } - if (mode === 'select') { - findConnectors(); - } - }, - mouseMove: function (opts) { - var zoom = svgCanvas.getZoom(); - // var e = opts.event; - var x = opts.mouse_x / zoom; - var y = opts.mouse_y / zoom; - - var diffX = x - startX, - diffY = y - startY; - - var mode = svgCanvas.getMode(); - - if (mode === 'connector' && started) { - // var sw = curLine.getAttribute('stroke-width') * 3; - // Set start point (adjusts based on bb) - var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine)); - startX = pt.x; - startY = pt.y; - - setPoint(curLine, 0, pt.x, pt.y, true); - - // Set end point - setPoint(curLine, 'end', x, y, true); - } else if (mode === 'select') { - var slen = selElems.length; - - while (slen--) { - var elem = selElems[slen]; - // Look for selected connector elements - if (elem && elData(elem, 'c_start')) { - // Remove the "translate" transform given to move - svgCanvas.removeFromSelection([elem]); - svgCanvas.getTransformList(elem).clear(); - } - } - if (connections.length) { - updateLine(diffX, diffY); - } - } - }, - mouseUp: function (opts) { - // var zoom = svgCanvas.getZoom(); - var e = opts.event, - // x = opts.mouse_x / zoom, - // y = opts.mouse_y / zoom, - mouseTarget = e.target; - - if (svgCanvas.getMode() === 'connector') { - var fo = $(mouseTarget).closest('foreignObject'); - if (fo.length) { mouseTarget = fo[0]; } - - var parents = $(mouseTarget).parents(); - - if (mouseTarget === startElem) { - // Start line through click - started = true; - return { - keep: true, - element: null, - started: started - }; - } - if ($.inArray(svgcontent, parents) === -1) { - // Not a valid target element, so remove line - $(curLine).remove(); - started = false; - return { - keep: false, - element: null, - started: started - }; - } - // Valid end element - endElem = mouseTarget; - - var startId = startElem.id, endId = endElem.id; - var connStr = startId + ' ' + endId; - var altStr = endId + ' ' + startId; - // Don't create connector if one already exists - var dupe = $(svgcontent).find(connSel).filter(function () { - var conn = this.getAttributeNS(seNs, 'connector'); - if (conn === connStr || conn === altStr) { return true; } - }); - if (dupe.length) { - $(curLine).remove(); - return { - keep: false, - element: null, - started: false - }; - } - - var bb = svgCanvas.getStrokedBBox([endElem]); - - var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine)); - setPoint(curLine, 'end', pt.x, pt.y, true); - $(curLine) - .data('c_start', startId) - .data('c_end', endId) - .data('end_bb', bb); - seNs = svgCanvas.getEditorNS(true); - curLine.setAttributeNS(seNs, 'se:connector', connStr); - curLine.setAttribute('class', connSel.substr(1)); - curLine.setAttribute('opacity', 1); - svgCanvas.addToSelection([curLine]); - svgCanvas.moveToBottomSelectedElement(); - selManager.requestSelector(curLine).showGrips(false); - started = false; - return { - keep: true, - element: curLine, - started: started - }; - } - }, - selectedChanged: function (opts) { - // TODO: Find better way to skip operations if no connectors are in use - if (!$(svgcontent).find(connSel).length) { return; } - - if (svgCanvas.getMode() === 'connector') { - svgCanvas.setMode('select'); - } - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - - while (i--) { - var elem = selElems[i]; - if (elem && elData(elem, 'c_start')) { - selManager.requestSelector(elem).showGrips(false); - if (opts.selectedElement && !opts.multiselected) { - // TODO: Set up context tools and hide most regular line tools - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - updateConnectors(); - }, - elementChanged: function (opts) { - var elem = opts.elems[0]; - if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { - // Update svgcontent (can change on import) - svgcontent = elem; - init(); - } - - // Has marker, so change offset - var start; - if (elem && ( - elem.getAttribute('marker-start') || - elem.getAttribute('marker-mid') || - elem.getAttribute('marker-end') - )) { - start = elem.getAttribute('marker-start'); - var mid = elem.getAttribute('marker-mid'); - var end = elem.getAttribute('marker-end'); - curLine = elem; - $(elem) - .data('start_off', !!start) - .data('end_off', !!end); - - if (elem.tagName === 'line' && mid) { - // Convert to polyline to accept mid-arrow - - var x1 = Number(elem.getAttribute('x1')); - var x2 = Number(elem.getAttribute('x2')); - var y1 = Number(elem.getAttribute('y1')); - var y2 = Number(elem.getAttribute('y2')); - var id = elem.id; - - var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' '); - var pline = addElem({ - 'element': 'polyline', - 'attr': { - 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2), - 'stroke': elem.getAttribute('stroke'), - 'stroke-width': elem.getAttribute('stroke-width'), - 'marker-mid': mid, - 'fill': 'none', - 'opacity': elem.getAttribute('opacity') || 1 - } - }); - $(elem).after(pline).remove(); - svgCanvas.clearSelection(); - pline.id = id; - svgCanvas.addToSelection([pline]); - elem = pline; - } - } - // Update line if it's a connector - if (elem.getAttribute('class') === connSel.substr(1)) { - start = getElem(elData(elem, 'c_start')); - updateConnectors([start]); - } else { - updateConnectors(); - } - }, - IDsUpdated: function (input) { - var remove = []; - input.elems.forEach(function (elem) { - if ('se:connector' in elem.attr) { - elem.attr['se:connector'] = elem.attr['se:connector'].split(' ') - .map(function (oldID) { return input.changes[oldID]; }).join(' '); - - // Check validity - the field would be something like 'svg_21 svg_22', but - // if one end is missing, it would be 'svg_21' and therefore fail this test - if (!/. ./.test(elem.attr['se:connector'])) { - remove.push(elem.attr.id); - } - } - }); - return {remove: remove}; - }, - toolButtonStateUpdate: function (opts) { - if (opts.nostroke) { - if ($('#mode_connect').hasClass('tool_button_current')) { - svgEditor.clickSelect(); - } - } - $('#mode_connect') - .toggleClass('disabled', opts.nostroke); - } - }; + var svgcontent = S.svgcontent, + svgroot = S.svgroot, + getNextId = S.getNextId, + getElem = S.getElem, + addElem = S.addSvgElementFromJson, + selManager = S.selectorManager, + curConfig = svgEditor.curConfig, + started = false, + startX, + startY, + curLine, + startElem, + endElem, + connections = [], + connSel = '.se_connector', + seNs, + // connect_str = '-SE_CONNECT-', + selElems = [], + elData = $.data; + + var langList = { + 'en': [ + {'id': 'mode_connect', 'title': 'Connect two objects'} + ], + 'fr': [ + {'id': 'mode_connect', 'title': 'Connecter deux objets'} + ] + }; + + function getBBintersect (x, y, bb, offset) { + if (offset) { + offset -= 0; + bb = $.extend({}, bb); + bb.width += offset; + bb.height += offset; + bb.x -= offset / 2; + bb.y -= offset / 2; + } + + var midX = bb.x + bb.width / 2; + var midY = bb.y + bb.height / 2; + var lenX = x - midX; + var lenY = y - midY; + + var slope = Math.abs(lenY / lenX); + + var ratio; + + if (slope < bb.height / bb.width) { + ratio = (bb.width / 2) / Math.abs(lenX); + } else { + ratio = (bb.height / 2) / Math.abs(lenY); + } + + return { + x: midX + lenX * ratio, + y: midY + lenY * ratio + }; + } + + function getOffset (side, line) { + var giveOffset = !!line.getAttribute('marker-' + side); + // var giveOffset = $(line).data(side+'_off'); + + // TODO: Make this number (5) be based on marker width/height + var size = line.getAttribute('stroke-width') * 5; + return giveOffset ? size : 0; + } + + function showPanel (on) { + var connRules = $('#connector_rules'); + if (!connRules.length) { + connRules = $('').appendTo('head'); + } + connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }'); + $('#connector_panel').toggle(on); + } + + function setPoint (elem, pos, x, y, setMid) { + var i, pts = elem.points; + var pt = svgroot.createSVGPoint(); + pt.x = x; + pt.y = y; + if (pos === 'end') { pos = pts.numberOfItems - 1; } + // TODO: Test for this on init, then use alt only if needed + try { + pts.replaceItem(pt, pos); + } catch (err) { + // Should only occur in FF which formats points attr as "n,n n,n", so just split + var ptArr = elem.getAttribute('points').split(' '); + for (i = 0; i < ptArr.length; i++) { + if (i === pos) { + ptArr[i] = x + ',' + y; + } + } + elem.setAttribute('points', ptArr.join(' ')); + } + + if (setMid) { + // Add center point + var ptStart = pts.getItem(0); + var ptEnd = pts.getItem(pts.numberOfItems - 1); + setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2); + } + } + + function updateLine (diffX, diffY) { + // Update line with element + var i = connections.length; + while (i--) { + var conn = connections[i]; + var line = conn.connector; + // var elem = conn.elem; + + var pre = conn.is_start ? 'start' : 'end'; + // var sw = line.getAttribute('stroke-width') * 5; + + // Update bbox for this element + var bb = elData(line, pre + '_bb'); + bb.x = conn.start_x + diffX; + bb.y = conn.start_y + diffY; + elData(line, pre + '_bb', bb); + + var altPre = conn.is_start ? 'end' : 'start'; + + // Get center pt of connected element + var bb2 = elData(line, altPre + '_bb'); + var srcX = bb2.x + bb2.width / 2; + var srcY = bb2.y + bb2.height / 2; + + // Set point of element being moved + var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 + setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); + + // Set point of connected element + var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); + setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); + } + } + + function findConnectors (elems) { + var i; + if (!elems) { elems = selElems; } + var connectors = $(svgcontent).find(connSel); + connections = []; + + // Loop through connectors to see if one is connected to the element + connectors.each(function () { + var addThis; + function add () { + if ($.inArray(this, elems) !== -1) { + // Pretend this element is selected + addThis = true; + } + } + + // Grab the ends + var parts = []; + ['start', 'end'].forEach(function (pos, i) { + var key = 'c_' + pos; + var part = elData(this, key); + if (part == null) { + part = document.getElementById( + this.attributes['se:connector'].value.split(' ')[i] + ); + elData(this, 'c_' + pos, part.id); + elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part])); + } else part = document.getElementById(part); + parts.push(part); + }.bind(this)); + + for (i = 0; i < 2; i++) { + var cElem = parts[i]; + + addThis = false; + // The connected element might be part of a selected group + $(cElem).parents().each(add); + + if (!cElem || !cElem.parentNode) { + $(this).remove(); + continue; + } + if ($.inArray(cElem, elems) !== -1 || addThis) { + var bb = svgCanvas.getStrokedBBox([cElem]); + connections.push({ + elem: cElem, + connector: this, + is_start: (i === 0), + start_x: bb.x, + start_y: bb.y + }); + } + } + }); + } + + function updateConnectors (elems) { + // Updates connector lines based on selected elements + // Is not used on mousemove, as it runs getStrokedBBox every time, + // which isn't necessary there. + var i, j; + findConnectors(elems); + if (connections.length) { + // Update line with element + i = connections.length; + while (i--) { + var conn = connections[i]; + var line = conn.connector; + var elem = conn.elem; + + // var sw = line.getAttribute('stroke-width') * 5; + var pre = conn.is_start ? 'start' : 'end'; + + // Update bbox for this element + var bb = svgCanvas.getStrokedBBox([elem]); + bb.x = conn.start_x; + bb.y = conn.start_y; + elData(line, pre + '_bb', bb); + /* var addOffset = */ elData(line, pre + '_off'); + + var altPre = conn.is_start ? 'end' : 'start'; + + // Get center pt of connected element + var bb2 = elData(line, altPre + '_bb'); + var srcX = bb2.x + bb2.width / 2; + var srcY = bb2.y + bb2.height / 2; + + // Set point of element being moved + var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); + setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); + + // Set point of connected element + var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); + setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); + + // Update points attribute manually for webkit + if (navigator.userAgent.indexOf('AppleWebKit') !== -1) { + var pts = line.points; + var len = pts.numberOfItems; + var ptArr = []; + for (j = 0; j < len; j++) { + pt = pts.getItem(j); + ptArr[j] = pt.x + ',' + pt.y; + } + line.setAttribute('points', ptArr.join(' ')); + } + } + } + } + + // Do once + (function () { + var gse = svgCanvas.groupSelectedElements; + + svgCanvas.groupSelectedElements = function () { + svgCanvas.removeFromSelection($(connSel).toArray()); + return gse.apply(this, arguments); + }; + + var mse = svgCanvas.moveSelectedElements; + + svgCanvas.moveSelectedElements = function () { + var cmd = mse.apply(this, arguments); + updateConnectors(); + return cmd; + }; + + seNs = svgCanvas.getEditorNS(); + }()); + + // Do on reset + function init () { + // Make sure all connectors have data set + $(svgcontent).find('*').each(function () { + var conn = this.getAttributeNS(seNs, 'connector'); + if (conn) { + this.setAttribute('class', connSel.substr(1)); + var connData = conn.split(' '); + var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]); + var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]); + $(this).data('c_start', connData[0]) + .data('c_end', connData[1]) + .data('start_bb', sbb) + .data('end_bb', ebb); + svgCanvas.getEditorNS(true); + } + }); + // updateConnectors(); + } + + // $(svgroot).parent().mousemove(function (e) { + // // if (started + // // || svgCanvas.getMode() !== 'connector' + // // || e.target.parentNode.parentNode !== svgcontent) return; + // + // console.log('y') + // // if (e.target.parentNode.parentNode === svgcontent) { + // // + // // } + // }); + + return { + name: 'Connector', + svgicons: svgEditor.curConfig.imgPath + 'conn.svg', + buttons: [{ + id: 'mode_connect', + type: 'mode', + icon: svgEditor.curConfig.imgPath + 'cut.png', + title: 'Connect two objects', + includeWith: { + button: '#tool_line', + isDefault: false, + position: 1 + }, + events: { + 'click': function () { + svgCanvas.setMode('connector'); + } + } + }], + addLangData: function (lang) { + return { + data: langList[lang] + }; + }, + mouseDown: function (opts) { + var e = opts.event; + startX = opts.start_x; + startY = opts.start_y; + var mode = svgCanvas.getMode(); + + if (mode === 'connector') { + if (started) { return; } + + var mouseTarget = e.target; + + var parents = $(mouseTarget).parents(); + + if ($.inArray(svgcontent, parents) !== -1) { + // Connectable element + + // If child of foreignObject, use parent + var fo = $(mouseTarget).closest('foreignObject'); + startElem = fo.length ? fo[0] : mouseTarget; + + // Get center of source element + var bb = svgCanvas.getStrokedBBox([startElem]); + var x = bb.x + bb.width / 2; + var y = bb.y + bb.height / 2; + + started = true; + curLine = addElem({ + 'element': 'polyline', + 'attr': { + 'id': getNextId(), + 'points': (x + ',' + y + ' ' + x + ',' + y + ' ' + startX + ',' + startY), + 'stroke': '#' + curConfig.initStroke.color, + 'stroke-width': (!startElem.stroke_width || startElem.stroke_width === 0) ? curConfig.initStroke.width : startElem.stroke_width, + 'fill': 'none', + 'opacity': curConfig.initStroke.opacity, + 'style': 'pointer-events:none' + } + }); + elData(curLine, 'start_bb', bb); + } + return { + started: true + }; + } + if (mode === 'select') { + findConnectors(); + } + }, + mouseMove: function (opts) { + var zoom = svgCanvas.getZoom(); + // var e = opts.event; + var x = opts.mouse_x / zoom; + var y = opts.mouse_y / zoom; + + var diffX = x - startX, + diffY = y - startY; + + var mode = svgCanvas.getMode(); + + if (mode === 'connector' && started) { + // var sw = curLine.getAttribute('stroke-width') * 3; + // Set start point (adjusts based on bb) + var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine)); + startX = pt.x; + startY = pt.y; + + setPoint(curLine, 0, pt.x, pt.y, true); + + // Set end point + setPoint(curLine, 'end', x, y, true); + } else if (mode === 'select') { + var slen = selElems.length; + + while (slen--) { + var elem = selElems[slen]; + // Look for selected connector elements + if (elem && elData(elem, 'c_start')) { + // Remove the "translate" transform given to move + svgCanvas.removeFromSelection([elem]); + svgCanvas.getTransformList(elem).clear(); + } + } + if (connections.length) { + updateLine(diffX, diffY); + } + } + }, + mouseUp: function (opts) { + // var zoom = svgCanvas.getZoom(); + var e = opts.event, + // x = opts.mouse_x / zoom, + // y = opts.mouse_y / zoom, + mouseTarget = e.target; + + if (svgCanvas.getMode() === 'connector') { + var fo = $(mouseTarget).closest('foreignObject'); + if (fo.length) { mouseTarget = fo[0]; } + + var parents = $(mouseTarget).parents(); + + if (mouseTarget === startElem) { + // Start line through click + started = true; + return { + keep: true, + element: null, + started: started + }; + } + if ($.inArray(svgcontent, parents) === -1) { + // Not a valid target element, so remove line + $(curLine).remove(); + started = false; + return { + keep: false, + element: null, + started: started + }; + } + // Valid end element + endElem = mouseTarget; + + var startId = startElem.id, endId = endElem.id; + var connStr = startId + ' ' + endId; + var altStr = endId + ' ' + startId; + // Don't create connector if one already exists + var dupe = $(svgcontent).find(connSel).filter(function () { + var conn = this.getAttributeNS(seNs, 'connector'); + if (conn === connStr || conn === altStr) { return true; } + }); + if (dupe.length) { + $(curLine).remove(); + return { + keep: false, + element: null, + started: false + }; + } + + var bb = svgCanvas.getStrokedBBox([endElem]); + + var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine)); + setPoint(curLine, 'end', pt.x, pt.y, true); + $(curLine) + .data('c_start', startId) + .data('c_end', endId) + .data('end_bb', bb); + seNs = svgCanvas.getEditorNS(true); + curLine.setAttributeNS(seNs, 'se:connector', connStr); + curLine.setAttribute('class', connSel.substr(1)); + curLine.setAttribute('opacity', 1); + svgCanvas.addToSelection([curLine]); + svgCanvas.moveToBottomSelectedElement(); + selManager.requestSelector(curLine).showGrips(false); + started = false; + return { + keep: true, + element: curLine, + started: started + }; + } + }, + selectedChanged: function (opts) { + // TODO: Find better way to skip operations if no connectors are in use + if (!$(svgcontent).find(connSel).length) { return; } + + if (svgCanvas.getMode() === 'connector') { + svgCanvas.setMode('select'); + } + + // Use this to update the current selected elements + selElems = opts.elems; + + var i = selElems.length; + + while (i--) { + var elem = selElems[i]; + if (elem && elData(elem, 'c_start')) { + selManager.requestSelector(elem).showGrips(false); + if (opts.selectedElement && !opts.multiselected) { + // TODO: Set up context tools and hide most regular line tools + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + updateConnectors(); + }, + elementChanged: function (opts) { + var elem = opts.elems[0]; + if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { + // Update svgcontent (can change on import) + svgcontent = elem; + init(); + } + + // Has marker, so change offset + var start; + if (elem && ( + elem.getAttribute('marker-start') || + elem.getAttribute('marker-mid') || + elem.getAttribute('marker-end') + )) { + start = elem.getAttribute('marker-start'); + var mid = elem.getAttribute('marker-mid'); + var end = elem.getAttribute('marker-end'); + curLine = elem; + $(elem) + .data('start_off', !!start) + .data('end_off', !!end); + + if (elem.tagName === 'line' && mid) { + // Convert to polyline to accept mid-arrow + + var x1 = Number(elem.getAttribute('x1')); + var x2 = Number(elem.getAttribute('x2')); + var y1 = Number(elem.getAttribute('y1')); + var y2 = Number(elem.getAttribute('y2')); + var id = elem.id; + + var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' '); + var pline = addElem({ + 'element': 'polyline', + 'attr': { + 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2), + 'stroke': elem.getAttribute('stroke'), + 'stroke-width': elem.getAttribute('stroke-width'), + 'marker-mid': mid, + 'fill': 'none', + 'opacity': elem.getAttribute('opacity') || 1 + } + }); + $(elem).after(pline).remove(); + svgCanvas.clearSelection(); + pline.id = id; + svgCanvas.addToSelection([pline]); + elem = pline; + } + } + // Update line if it's a connector + if (elem.getAttribute('class') === connSel.substr(1)) { + start = getElem(elData(elem, 'c_start')); + updateConnectors([start]); + } else { + updateConnectors(); + } + }, + IDsUpdated: function (input) { + var remove = []; + input.elems.forEach(function (elem) { + if ('se:connector' in elem.attr) { + elem.attr['se:connector'] = elem.attr['se:connector'].split(' ') + .map(function (oldID) { return input.changes[oldID]; }).join(' '); + + // Check validity - the field would be something like 'svg_21 svg_22', but + // if one end is missing, it would be 'svg_21' and therefore fail this test + if (!/. ./.test(elem.attr['se:connector'])) { + remove.push(elem.attr.id); + } + } + }); + return {remove: remove}; + }, + toolButtonStateUpdate: function (opts) { + if (opts.nostroke) { + if ($('#mode_connect').hasClass('tool_button_current')) { + svgEditor.clickSelect(); + } + } + $('#mode_connect') + .toggleClass('disabled', opts.nostroke); + } + }; }); diff --git a/editor/extensions/ext-eyedropper.js b/editor/extensions/ext-eyedropper.js index 00d3e303..57704f21 100644 --- a/editor/extensions/ext-eyedropper.js +++ b/editor/extensions/ext-eyedropper.js @@ -16,96 +16,96 @@ // 4) svgcanvas.js svgEditor.addExtension('eyedropper', function (S) { - 'use strict'; - var // NS = svgedit.NS, - // svgcontent = S.svgcontent, - // svgdoc = S.svgroot.parentNode.ownerDocument, - svgCanvas = svgEditor.canvas, - ChangeElementCommand = svgedit.history.ChangeElementCommand, - addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, - currentStyle = { - fillPaint: 'red', fillOpacity: 1.0, - strokePaint: 'black', strokeOpacity: 1.0, - strokeWidth: 5, strokeDashArray: null, - opacity: 1.0, - strokeLinecap: 'butt', - strokeLinejoin: 'miter' - }; + 'use strict'; + var // NS = svgedit.NS, + // svgcontent = S.svgcontent, + // svgdoc = S.svgroot.parentNode.ownerDocument, + svgCanvas = svgEditor.canvas, + ChangeElementCommand = svgedit.history.ChangeElementCommand, + addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, + currentStyle = { + fillPaint: 'red', fillOpacity: 1.0, + strokePaint: 'black', strokeOpacity: 1.0, + strokeWidth: 5, strokeDashArray: null, + opacity: 1.0, + strokeLinecap: 'butt', + strokeLinejoin: 'miter' + }; - function getStyle (opts) { - // if we are in eyedropper mode, we don't want to disable the eye-dropper tool - var mode = svgCanvas.getMode(); - if (mode === 'eyedropper') { return; } + function getStyle (opts) { + // if we are in eyedropper mode, we don't want to disable the eye-dropper tool + var mode = svgCanvas.getMode(); + if (mode === 'eyedropper') { return; } - var elem = null; - var tool = $('#tool_eyedropper'); - // enable-eye-dropper if one element is selected - if (!opts.multiselected && opts.elems[0] && - $.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1 - ) { - elem = opts.elems[0]; - tool.removeClass('disabled'); - // grab the current style - currentStyle.fillPaint = elem.getAttribute('fill') || 'black'; - currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0; - currentStyle.strokePaint = elem.getAttribute('stroke'); - currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0; - currentStyle.strokeWidth = elem.getAttribute('stroke-width'); - currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray'); - currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap'); - currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin'); - currentStyle.opacity = elem.getAttribute('opacity') || 1.0; - // disable eye-dropper tool - } else { - tool.addClass('disabled'); - } - } + var elem = null; + var tool = $('#tool_eyedropper'); + // enable-eye-dropper if one element is selected + if (!opts.multiselected && opts.elems[0] && + $.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1 + ) { + elem = opts.elems[0]; + tool.removeClass('disabled'); + // grab the current style + currentStyle.fillPaint = elem.getAttribute('fill') || 'black'; + currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0; + currentStyle.strokePaint = elem.getAttribute('stroke'); + currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0; + currentStyle.strokeWidth = elem.getAttribute('stroke-width'); + currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray'); + currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap'); + currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin'); + currentStyle.opacity = elem.getAttribute('opacity') || 1.0; + // disable eye-dropper tool + } else { + tool.addClass('disabled'); + } + } - return { - name: 'eyedropper', - svgicons: svgEditor.curConfig.extPath + 'eyedropper-icon.xml', - buttons: [{ - id: 'tool_eyedropper', - type: 'mode', - title: 'Eye Dropper Tool', - key: 'I', - events: { - click: function () { - svgCanvas.setMode('eyedropper'); - } - } - }], + return { + name: 'eyedropper', + svgicons: svgEditor.curConfig.extPath + 'eyedropper-icon.xml', + buttons: [{ + id: 'tool_eyedropper', + type: 'mode', + title: 'Eye Dropper Tool', + key: 'I', + events: { + click: function () { + svgCanvas.setMode('eyedropper'); + } + } + }], - // if we have selected an element, grab its paint and enable the eye dropper button - selectedChanged: getStyle, - elementChanged: getStyle, + // if we have selected an element, grab its paint and enable the eye dropper button + selectedChanged: getStyle, + elementChanged: getStyle, - mouseDown: function (opts) { - var mode = svgCanvas.getMode(); - if (mode === 'eyedropper') { - var e = opts.event; - var target = e.target; - if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) { - var changes = {}; + mouseDown: function (opts) { + var mode = svgCanvas.getMode(); + if (mode === 'eyedropper') { + var e = opts.event; + var target = e.target; + if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) { + var changes = {}; - var change = function (elem, attrname, newvalue) { - changes[attrname] = elem.getAttribute(attrname); - elem.setAttribute(attrname, newvalue); - }; + var change = function (elem, attrname, newvalue) { + changes[attrname] = elem.getAttribute(attrname); + elem.setAttribute(attrname, newvalue); + }; - if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); } - if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); } - if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); } - if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); } - if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); } - if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); } - if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); } - if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); } - if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); } + if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); } + if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); } + if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); } + if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); } + if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); } + if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); } + if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); } + if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); } + if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); } - addToHistory(new ChangeElementCommand(target, changes)); - } - } - } - }; + addToHistory(new ChangeElementCommand(target, changes)); + } + } + } + }; }); diff --git a/editor/extensions/ext-foreignobject.js b/editor/extensions/ext-foreignobject.js index fec8cd22..af87e8fd 100644 --- a/editor/extensions/ext-foreignobject.js +++ b/editor/extensions/ext-foreignobject.js @@ -11,254 +11,254 @@ */ svgEditor.addExtension('foreignObject', function (S) { - var NS = svgedit.NS, - Utils = svgedit.utilities, - // svgcontent = S.svgcontent, - // addElem = S.addSvgElementFromJson, - selElems, - editingforeign = false, - svgdoc = S.svgroot.parentNode.ownerDocument, - started, - newFO; + var NS = svgedit.NS, + Utils = svgedit.utilities, + // svgcontent = S.svgcontent, + // addElem = S.addSvgElementFromJson, + selElems, + editingforeign = false, + svgdoc = S.svgroot.parentNode.ownerDocument, + started, + newFO; - var properlySourceSizeTextArea = function () { - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 80; - $('#svg_source_textarea').css('height', height); - }; + var properlySourceSizeTextArea = function () { + // TODO: remove magic numbers here and get values from CSS + var height = $('#svg_source_container').height() - 80; + $('#svg_source_textarea').css('height', height); + }; - function showPanel (on) { - var fcRules = $('#fc_rules'); - if (!fcRules.length) { - fcRules = $('').appendTo('head'); - } - fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); - $('#foreignObject_panel').toggle(on); - } + function showPanel (on) { + var fcRules = $('#fc_rules'); + if (!fcRules.length) { + fcRules = $('').appendTo('head'); + } + fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); + $('#foreignObject_panel').toggle(on); + } - function toggleSourceButtons (on) { - $('#tool_source_save, #tool_source_cancel').toggle(!on); - $('#foreign_save, #foreign_cancel').toggle(on); - } + function toggleSourceButtons (on) { + $('#tool_source_save, #tool_source_cancel').toggle(!on); + $('#foreign_save, #foreign_cancel').toggle(on); + } - // Function: setForeignString(xmlString, elt) - // This function sets the content of element elt to the input XML. - // - // Parameters: - // xmlString - The XML text. - // elt - the parent element to append to - // - // Returns: - // This function returns false if the set was unsuccessful, true otherwise. - function setForeignString (xmlString) { - var elt = selElems[0]; - try { - // convert string into XML document - var newDoc = Utils.text2xml('' + xmlString + ''); - // run it through our sanitizer to remove anything we do not support - S.sanitizeSvg(newDoc.documentElement); - elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); - S.call('changed', [elt]); - svgCanvas.clearSelection(); - } catch (e) { - console.log(e); - return false; - } + // Function: setForeignString(xmlString, elt) + // This function sets the content of element elt to the input XML. + // + // Parameters: + // xmlString - The XML text. + // elt - the parent element to append to + // + // Returns: + // This function returns false if the set was unsuccessful, true otherwise. + function setForeignString (xmlString) { + var elt = selElems[0]; + try { + // convert string into XML document + var newDoc = Utils.text2xml('' + xmlString + ''); + // run it through our sanitizer to remove anything we do not support + S.sanitizeSvg(newDoc.documentElement); + elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); + S.call('changed', [elt]); + svgCanvas.clearSelection(); + } catch (e) { + console.log(e); + return false; + } - return true; - } + return true; + } - function showForeignEditor () { - var elt = selElems[0]; - if (!elt || editingforeign) { return; } - editingforeign = true; - toggleSourceButtons(true); - elt.removeAttribute('fill'); + function showForeignEditor () { + var elt = selElems[0]; + if (!elt || editingforeign) { return; } + editingforeign = true; + toggleSourceButtons(true); + elt.removeAttribute('fill'); - var str = S.svgToString(elt, 0); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - } + var str = S.svgToString(elt, 0); + $('#svg_source_textarea').val(str); + $('#svg_source_editor').fadeIn(); + properlySourceSizeTextArea(); + $('#svg_source_textarea').focus(); + } - function setAttr (attr, val) { - svgCanvas.changeSelectedAttribute(attr, val); - S.call('changed', selElems); - } + function setAttr (attr, val) { + svgCanvas.changeSelectedAttribute(attr, val); + S.call('changed', selElems); + } - return { - name: 'foreignObject', - svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml', - buttons: [{ - id: 'tool_foreign', - type: 'mode', - title: 'Foreign Object Tool', - events: { - 'click': function () { - svgCanvas.setMode('foreign'); - } - } - }, { - id: 'edit_foreign', - type: 'context', - panel: 'foreignObject_panel', - title: 'Edit ForeignObject Content', - events: { - 'click': function () { - showForeignEditor(); - } - } - }], + return { + name: 'foreignObject', + svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml', + buttons: [{ + id: 'tool_foreign', + type: 'mode', + title: 'Foreign Object Tool', + events: { + 'click': function () { + svgCanvas.setMode('foreign'); + } + } + }, { + id: 'edit_foreign', + type: 'context', + panel: 'foreignObject_panel', + title: 'Edit ForeignObject Content', + events: { + 'click': function () { + showForeignEditor(); + } + } + }], - context_tools: [{ - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's width", - id: 'foreign_width', - label: 'w', - size: 3, - events: { - change: function () { - setAttr('width', this.value); - } - } - }, { - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's height", - id: 'foreign_height', - label: 'h', - events: { - change: function () { - setAttr('height', this.value); - } - } - }, { - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's font size", - id: 'foreign_font_size', - label: 'font-size', - size: 2, - defval: 16, - events: { - change: function () { - setAttr('font-size', this.value); - } - } - } + context_tools: [{ + type: 'input', + panel: 'foreignObject_panel', + title: "Change foreignObject's width", + id: 'foreign_width', + label: 'w', + size: 3, + events: { + change: function () { + setAttr('width', this.value); + } + } + }, { + type: 'input', + panel: 'foreignObject_panel', + title: "Change foreignObject's height", + id: 'foreign_height', + label: 'h', + events: { + change: function () { + setAttr('height', this.value); + } + } + }, { + type: 'input', + panel: 'foreignObject_panel', + title: "Change foreignObject's font size", + id: 'foreign_font_size', + label: 'font-size', + size: 2, + defval: 16, + events: { + change: function () { + setAttr('font-size', this.value); + } + } + } - ], - callback: function () { - $('#foreignObject_panel').hide(); + ], + callback: function () { + $('#foreignObject_panel').hide(); - var endChanges = function () { - $('#svg_source_editor').hide(); - editingforeign = false; - $('#svg_source_textarea').blur(); - toggleSourceButtons(false); - }; + var endChanges = function () { + $('#svg_source_editor').hide(); + editingforeign = false; + $('#svg_source_textarea').blur(); + toggleSourceButtons(false); + }; - // TODO: Needs to be done after orig icon loads - setTimeout(function () { - // Create source save/cancel buttons - /* var save = */ $('#tool_source_save').clone() - .hide().attr('id', 'foreign_save').unbind() - .appendTo('#tool_source_back').click(function () { - if (!editingforeign) { return; } + // TODO: Needs to be done after orig icon loads + setTimeout(function () { + // Create source save/cancel buttons + /* var save = */ $('#tool_source_save').clone() + .hide().attr('id', 'foreign_save').unbind() + .appendTo('#tool_source_back').click(function () { + if (!editingforeign) { return; } - if (!setForeignString($('#svg_source_textarea').val())) { - $.confirm('Errors found. Revert to original?', function (ok) { - if (!ok) { return false; } - endChanges(); - }); - } else { - endChanges(); - } - // setSelectMode(); - }); + if (!setForeignString($('#svg_source_textarea').val())) { + $.confirm('Errors found. Revert to original?', function (ok) { + if (!ok) { return false; } + endChanges(); + }); + } else { + endChanges(); + } + // setSelectMode(); + }); - /* var cancel = */ $('#tool_source_cancel').clone() - .hide().attr('id', 'foreign_cancel').unbind() - .appendTo('#tool_source_back').click(function () { - endChanges(); - }); - }, 3000); - }, - mouseDown: function (opts) { - // var e = opts.event; + /* var cancel = */ $('#tool_source_cancel').clone() + .hide().attr('id', 'foreign_cancel').unbind() + .appendTo('#tool_source_back').click(function () { + endChanges(); + }); + }, 3000); + }, + mouseDown: function (opts) { + // var e = opts.event; - if (svgCanvas.getMode() === 'foreign') { - started = true; - newFO = S.addSvgElementFromJson({ - 'element': 'foreignObject', - 'attr': { - 'x': opts.start_x, - 'y': opts.start_y, - 'id': S.getNextId(), - 'font-size': 16, // cur_text.font_size, - 'width': '48', - 'height': '20', - 'style': 'pointer-events:inherit' - } - }); - var m = svgdoc.createElementNS(NS.MATH, 'math'); - m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); - m.setAttribute('display', 'inline'); - var mi = svgdoc.createElementNS(NS.MATH, 'mi'); - mi.setAttribute('mathvariant', 'normal'); - mi.textContent = '\u03A6'; - var mo = svgdoc.createElementNS(NS.MATH, 'mo'); - mo.textContent = '\u222A'; - var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); - mi2.textContent = '\u2133'; - m.appendChild(mi); - m.appendChild(mo); - m.appendChild(mi2); - newFO.appendChild(m); - return { - started: true - }; - } - }, - mouseUp: function (opts) { - // var e = opts.event; - if (svgCanvas.getMode() === 'foreign' && started) { - var attrs = $(newFO).attr(['width', 'height']); - var keep = (attrs.width !== '0' || attrs.height !== '0'); - svgCanvas.addToSelection([newFO], true); + if (svgCanvas.getMode() === 'foreign') { + started = true; + newFO = S.addSvgElementFromJson({ + 'element': 'foreignObject', + 'attr': { + 'x': opts.start_x, + 'y': opts.start_y, + 'id': S.getNextId(), + 'font-size': 16, // cur_text.font_size, + 'width': '48', + 'height': '20', + 'style': 'pointer-events:inherit' + } + }); + var m = svgdoc.createElementNS(NS.MATH, 'math'); + m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); + m.setAttribute('display', 'inline'); + var mi = svgdoc.createElementNS(NS.MATH, 'mi'); + mi.setAttribute('mathvariant', 'normal'); + mi.textContent = '\u03A6'; + var mo = svgdoc.createElementNS(NS.MATH, 'mo'); + mo.textContent = '\u222A'; + var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); + mi2.textContent = '\u2133'; + m.appendChild(mi); + m.appendChild(mo); + m.appendChild(mi2); + newFO.appendChild(m); + return { + started: true + }; + } + }, + mouseUp: function (opts) { + // var e = opts.event; + if (svgCanvas.getMode() === 'foreign' && started) { + var attrs = $(newFO).attr(['width', 'height']); + var keep = (attrs.width !== '0' || attrs.height !== '0'); + svgCanvas.addToSelection([newFO], true); - return { - keep: keep, - element: newFO - }; - } - }, - selectedChanged: function (opts) { - // Use this to update the current selected elements - selElems = opts.elems; + return { + keep: keep, + element: newFO + }; + } + }, + selectedChanged: function (opts) { + // Use this to update the current selected elements + selElems = opts.elems; - var i = selElems.length; + var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && elem.tagName === 'foreignObject') { - if (opts.selectedElement && !opts.multiselected) { - $('#foreign_font_size').val(elem.getAttribute('font-size')); - $('#foreign_width').val(elem.getAttribute('width')); - $('#foreign_height').val(elem.getAttribute('height')); - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function (opts) { - // var elem = opts.elems[0]; - } - }; + while (i--) { + var elem = selElems[i]; + if (elem && elem.tagName === 'foreignObject') { + if (opts.selectedElement && !opts.multiselected) { + $('#foreign_font_size').val(elem.getAttribute('font-size')); + $('#foreign_width').val(elem.getAttribute('width')); + $('#foreign_height').val(elem.getAttribute('height')); + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + }, + elementChanged: function (opts) { + // var elem = opts.elems[0]; + } + }; }); diff --git a/editor/extensions/ext-grid.js b/editor/extensions/ext-grid.js index c857a9a8..d352371d 100644 --- a/editor/extensions/ext-grid.js +++ b/editor/extensions/ext-grid.js @@ -15,149 +15,149 @@ // 2) everything else svgEditor.addExtension('view_grid', function () { - 'use strict'; + 'use strict'; - var NS = svgedit.NS, - svgdoc = document.getElementById('svgcanvas').ownerDocument, - showGrid = svgEditor.curConfig.showGrid || false, - assignAttributes = svgCanvas.assignAttributes, - hcanvas = document.createElement('canvas'), - canvBG = $('#canvasBackground'), - units = svgedit.units.getTypeMap(), - intervals = [0.01, 0.1, 1, 10, 100, 1000]; + var NS = svgedit.NS, + svgdoc = document.getElementById('svgcanvas').ownerDocument, + showGrid = svgEditor.curConfig.showGrid || false, + assignAttributes = svgCanvas.assignAttributes, + hcanvas = document.createElement('canvas'), + canvBG = $('#canvasBackground'), + units = svgedit.units.getTypeMap(), + intervals = [0.01, 0.1, 1, 10, 100, 1000]; - $(hcanvas).hide().appendTo('body'); + $(hcanvas).hide().appendTo('body'); - var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); - assignAttributes(canvasGrid, { - 'id': 'canvasGrid', - 'width': '100%', - 'height': '100%', - 'x': 0, - 'y': 0, - 'overflow': 'visible', - 'display': 'none' - }); - canvBG.append(canvasGrid); + var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); + assignAttributes(canvasGrid, { + 'id': 'canvasGrid', + 'width': '100%', + 'height': '100%', + 'x': 0, + 'y': 0, + 'overflow': 'visible', + 'display': 'none' + }); + canvBG.append(canvasGrid); - // grid-pattern - var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); - assignAttributes(gridPattern, { - 'id': 'gridpattern', - 'patternUnits': 'userSpaceOnUse', - 'x': 0, // -(value.strokeWidth / 2), // position for strokewidth - 'y': 0, // -(value.strokeWidth / 2), // position for strokewidth - 'width': 100, - 'height': 100 - }); + // grid-pattern + var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); + assignAttributes(gridPattern, { + 'id': 'gridpattern', + 'patternUnits': 'userSpaceOnUse', + 'x': 0, // -(value.strokeWidth / 2), // position for strokewidth + 'y': 0, // -(value.strokeWidth / 2), // position for strokewidth + 'width': 100, + 'height': 100 + }); - var gridimg = svgdoc.createElementNS(NS.SVG, 'image'); - assignAttributes(gridimg, { - 'x': 0, - 'y': 0, - 'width': 100, - 'height': 100 - }); - gridPattern.appendChild(gridimg); - $('#svgroot defs').append(gridPattern); + var gridimg = svgdoc.createElementNS(NS.SVG, 'image'); + assignAttributes(gridimg, { + 'x': 0, + 'y': 0, + 'width': 100, + 'height': 100 + }); + gridPattern.appendChild(gridimg); + $('#svgroot defs').append(gridPattern); - // grid-box - var gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); - assignAttributes(gridBox, { - 'width': '100%', - 'height': '100%', - 'x': 0, - 'y': 0, - 'stroke-width': 0, - 'stroke': 'none', - 'fill': 'url(#gridpattern)', - 'style': 'pointer-events: none; display:visible;' - }); - $('#canvasGrid').append(gridBox); + // grid-box + var gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); + assignAttributes(gridBox, { + 'width': '100%', + 'height': '100%', + 'x': 0, + 'y': 0, + 'stroke-width': 0, + 'stroke': 'none', + 'fill': 'url(#gridpattern)', + 'style': 'pointer-events: none; display:visible;' + }); + $('#canvasGrid').append(gridBox); - function updateGrid (zoom) { - var i; - // TODO: Try this with elements, then compare performance difference - var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px - var uMulti = unit * zoom; - // Calculate the main number interval - var rawM = 100 / uMulti; - var multi = 1; - for (i = 0; i < intervals.length; i++) { - var num = intervals[i]; - multi = num; - if (rawM <= num) { - break; - } - } - var bigInt = multi * uMulti; + function updateGrid (zoom) { + var i; + // TODO: Try this with elements, then compare performance difference + var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px + var uMulti = unit * zoom; + // Calculate the main number interval + var rawM = 100 / uMulti; + var multi = 1; + for (i = 0; i < intervals.length; i++) { + var num = intervals[i]; + multi = num; + if (rawM <= num) { + break; + } + } + var bigInt = multi * uMulti; - // Set the canvas size to the width of the container - hcanvas.width = bigInt; - hcanvas.height = bigInt; - var ctx = hcanvas.getContext('2d'); - var curD = 0.5; - var part = bigInt / 10; + // Set the canvas size to the width of the container + hcanvas.width = bigInt; + hcanvas.height = bigInt; + var ctx = hcanvas.getContext('2d'); + var curD = 0.5; + var part = bigInt / 10; - ctx.globalAlpha = 0.2; - ctx.strokeStyle = svgEditor.curConfig.gridColor; - for (i = 1; i < 10; i++) { - var subD = Math.round(part * i) + 0.5; - // var lineNum = (i % 2)?12:10; - var lineNum = 0; - ctx.moveTo(subD, bigInt); - ctx.lineTo(subD, lineNum); - ctx.moveTo(bigInt, subD); - ctx.lineTo(lineNum, subD); - } - ctx.stroke(); - ctx.beginPath(); - ctx.globalAlpha = 0.5; - ctx.moveTo(curD, bigInt); - ctx.lineTo(curD, 0); + ctx.globalAlpha = 0.2; + ctx.strokeStyle = svgEditor.curConfig.gridColor; + for (i = 1; i < 10; i++) { + var subD = Math.round(part * i) + 0.5; + // var lineNum = (i % 2)?12:10; + var lineNum = 0; + ctx.moveTo(subD, bigInt); + ctx.lineTo(subD, lineNum); + ctx.moveTo(bigInt, subD); + ctx.lineTo(lineNum, subD); + } + ctx.stroke(); + ctx.beginPath(); + ctx.globalAlpha = 0.5; + ctx.moveTo(curD, bigInt); + ctx.lineTo(curD, 0); - ctx.moveTo(bigInt, curD); - ctx.lineTo(0, curD); - ctx.stroke(); + ctx.moveTo(bigInt, curD); + ctx.lineTo(0, curD); + ctx.stroke(); - var datauri = hcanvas.toDataURL('image/png'); - gridimg.setAttribute('width', bigInt); - gridimg.setAttribute('height', bigInt); - gridimg.parentNode.setAttribute('width', bigInt); - gridimg.parentNode.setAttribute('height', bigInt); - svgCanvas.setHref(gridimg, datauri); - } + var datauri = hcanvas.toDataURL('image/png'); + gridimg.setAttribute('width', bigInt); + gridimg.setAttribute('height', bigInt); + gridimg.parentNode.setAttribute('width', bigInt); + gridimg.parentNode.setAttribute('height', bigInt); + svgCanvas.setHref(gridimg, datauri); + } - function gridUpdate () { - if (showGrid) { - updateGrid(svgCanvas.getZoom()); - } - $('#canvasGrid').toggle(showGrid); - $('#view_grid').toggleClass('push_button_pressed tool_button'); - } - return { - name: 'view_grid', - svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml', + function gridUpdate () { + if (showGrid) { + updateGrid(svgCanvas.getZoom()); + } + $('#canvasGrid').toggle(showGrid); + $('#view_grid').toggleClass('push_button_pressed tool_button'); + } + return { + name: 'view_grid', + svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml', - zoomChanged: function (zoom) { - if (showGrid) { updateGrid(zoom); } - }, - callback: function () { - if (showGrid) { - gridUpdate(); - } - }, - buttons: [{ - id: 'view_grid', - type: 'context', - panel: 'editor_panel', - title: 'Show/Hide Grid', - events: { - click: function () { - svgEditor.curConfig.showGrid = showGrid = !showGrid; - gridUpdate(); - } - } - }] - }; + zoomChanged: function (zoom) { + if (showGrid) { updateGrid(zoom); } + }, + callback: function () { + if (showGrid) { + gridUpdate(); + } + }, + buttons: [{ + id: 'view_grid', + type: 'context', + panel: 'editor_panel', + title: 'Show/Hide Grid', + events: { + click: function () { + svgEditor.curConfig.showGrid = showGrid = !showGrid; + gridUpdate(); + } + } + }] + }; }); diff --git a/editor/extensions/ext-helloworld.js b/editor/extensions/ext-helloworld.js index 742816af..e6572932 100644 --- a/editor/extensions/ext-helloworld.js +++ b/editor/extensions/ext-helloworld.js @@ -10,70 +10,70 @@ */ /* - 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 - user the point on the canvas that was clicked on. + 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 + user the point on the canvas that was clicked on. */ svgEditor.addExtension('Hello World', function () { - 'use strict'; + 'use strict'; - return { - name: 'Hello World', - // For more notes on how to make an icon file, see the source of - // the helloworld-icon.xml - svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml', + return { + name: 'Hello World', + // For more notes on how to make an icon file, see the source of + // the helloworld-icon.xml + svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml', - // Multiple buttons can be added in this array - buttons: [{ - // Must match the icon ID in helloworld-icon.xml - id: 'hello_world', + // Multiple buttons can be added in this array + buttons: [{ + // Must match the icon ID in helloworld-icon.xml + id: 'hello_world', - // This indicates that the button will be added to the "mode" - // button panel on the left side - type: 'mode', + // This indicates that the button will be added to the "mode" + // button panel on the left side + type: 'mode', - // Tooltip text - title: "Say 'Hello World'", + // Tooltip text + title: "Say 'Hello World'", - // Events - events: { - 'click': function () { - // The action taken when the button is clicked on. - // For "mode" buttons, any other button will - // automatically be de-pressed. - svgCanvas.setMode('hello_world'); - } - } - }], - // This is triggered when the main mouse button is pressed down - // on the editor canvas (not the tool panels) - mouseDown: function () { - // Check the mode on mousedown - if (svgCanvas.getMode() === 'hello_world') { - // The returned object must include "started" with - // a value of true in order for mouseUp to be triggered - return {started: true}; - } - }, + // Events + events: { + 'click': function () { + // The action taken when the button is clicked on. + // For "mode" buttons, any other button will + // automatically be de-pressed. + svgCanvas.setMode('hello_world'); + } + } + }], + // This is triggered when the main mouse button is pressed down + // on the editor canvas (not the tool panels) + mouseDown: function () { + // Check the mode on mousedown + if (svgCanvas.getMode() === 'hello_world') { + // The returned object must include "started" with + // a value of true in order for mouseUp to be triggered + return {started: true}; + } + }, - // This is triggered from anywhere, but "started" must have been set - // to true (see above). Note that "opts" is an object with event info - mouseUp: function (opts) { - // Check the mode on mouseup - if (svgCanvas.getMode() === 'hello_world') { - var zoom = svgCanvas.getZoom(); + // This is triggered from anywhere, but "started" must have been set + // to true (see above). Note that "opts" is an object with event info + mouseUp: function (opts) { + // Check the mode on mouseup + if (svgCanvas.getMode() === 'hello_world') { + var zoom = svgCanvas.getZoom(); - // Get the actual coordinate by dividing by the zoom value - var x = opts.mouse_x / zoom; - var y = opts.mouse_y / zoom; + // Get the actual coordinate by dividing by the zoom value + var x = opts.mouse_x / zoom; + var y = opts.mouse_y / zoom; - var text = 'Hello World!\n\nYou clicked here: ' + - x + ', ' + y; + var text = 'Hello World!\n\nYou clicked here: ' + + x + ', ' + y; - // Show the text using the custom alert function - $.alert(text); - } - } - }; + // Show the text using the custom alert function + $.alert(text); + } + } + }; }); diff --git a/editor/extensions/ext-imagelib.js b/editor/extensions/ext-imagelib.js index 338c4de2..c0e9bd3f 100644 --- a/editor/extensions/ext-imagelib.js +++ b/editor/extensions/ext-imagelib.js @@ -10,447 +10,447 @@ */ svgEditor.addExtension('imagelib', function () { - 'use strict'; + 'use strict'; - var uiStrings = svgEditor.uiStrings; + var uiStrings = svgEditor.uiStrings; - $.extend(uiStrings, { - imagelib: { - select_lib: 'Select an image library', - show_list: 'Show library list', - import_single: 'Import single', - import_multi: 'Import multiple', - open: 'Open as new document' - } - }); + $.extend(uiStrings, { + imagelib: { + select_lib: 'Select an image library', + show_list: 'Show library list', + import_single: 'Import single', + import_multi: 'Import multiple', + open: 'Open as new document' + } + }); - var imgLibs = [ - { - name: 'Demo library (local)', - url: svgEditor.curConfig.extPath + 'imagelib/index.html', - description: 'Demonstration library for SVG-edit on this server' - }, - { - name: 'IAN Symbol Libraries', - url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php', - description: 'Free library of illustrations' - }, - { - name: 'Openclipart', - url: 'https://openclipart.org/svgedit', - description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.' - } - ]; + var imgLibs = [ + { + name: 'Demo library (local)', + url: svgEditor.curConfig.extPath + 'imagelib/index.html', + description: 'Demonstration library for SVG-edit on this server' + }, + { + name: 'IAN Symbol Libraries', + url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php', + description: 'Free library of illustrations' + }, + { + name: 'Openclipart', + url: 'https://openclipart.org/svgedit', + description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.' + } + ]; - function closeBrowser () { - $('#imgbrowse_holder').hide(); - } + function closeBrowser () { + $('#imgbrowse_holder').hide(); + } - function importImage (url) { - var newImage = svgCanvas.addSvgElementFromJson({ - 'element': 'image', - 'attr': { - 'x': 0, - 'y': 0, - 'width': 0, - 'height': 0, - 'id': svgCanvas.getNextId(), - 'style': 'pointer-events:inherit' - } - }); - svgCanvas.clearSelection(); - svgCanvas.addToSelection([newImage]); - svgCanvas.setImageURL(url); - } + function importImage (url) { + var newImage = svgCanvas.addSvgElementFromJson({ + 'element': 'image', + 'attr': { + 'x': 0, + 'y': 0, + 'width': 0, + 'height': 0, + 'id': svgCanvas.getNextId(), + 'style': 'pointer-events:inherit' + } + }); + svgCanvas.clearSelection(); + svgCanvas.addToSelection([newImage]); + svgCanvas.setImageURL(url); + } - var mode = 's'; - var multiArr = []; - var transferStopped = false; - var pending = {}; - var preview, submit; + var mode = 's'; + var multiArr = []; + var transferStopped = false; + var pending = {}; + var preview, submit; - window.addEventListener('message', function (evt) { - // Receive postMessage data - var response = evt.data; + window.addEventListener('message', function (evt) { + // Receive postMessage data + var response = evt.data; - if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here - // Do nothing - return; - } - 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); - if (res.namespace) { // Part of embedAPI communications - return; - } - } catch (e) {} + if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here + // Do nothing + return; + } + 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); + if (res.namespace) { // Part of embedAPI communications + return; + } + } catch (e) {} - var char1 = response.charAt(0); - var id; - var svgStr; - var imgStr; + var char1 = response.charAt(0); + var id; + var svgStr; + var imgStr; - if (char1 !== '{' && transferStopped) { - transferStopped = false; - return; - } + if (char1 !== '{' && transferStopped) { + transferStopped = false; + return; + } - if (char1 === '|') { - var secondpos = response.indexOf('|', 1); - id = response.substr(1, secondpos - 1); - response = response.substr(secondpos + 1); - char1 = response.charAt(0); - } + if (char1 === '|') { + var secondpos = response.indexOf('|', 1); + id = response.substr(1, secondpos - 1); + response = response.substr(secondpos + 1); + char1 = response.charAt(0); + } - // Hide possible transfer dialog box - $('#dialog_box').hide(); - var entry, curMeta; - switch (char1) { - case '{': - // Metadata - transferStopped = false; - curMeta = JSON.parse(response); + // Hide possible transfer dialog box + $('#dialog_box').hide(); + var entry, curMeta; + switch (char1) { + case '{': + // Metadata + transferStopped = false; + 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') { - $.process_cancel(message, function () { - transferStopped = true; - // Should a message be sent back to the frame? + if (mode !== 'm') { + $.process_cancel(message, function () { + transferStopped = true; + // Should a message be sent back to the frame? - $('#dialog_box').hide(); - }); - } else { - entry = $('
' + message + '
').data('id', curMeta.id); - preview.append(entry); - curMeta.entry = entry; - } + $('#dialog_box').hide(); + }); + } else { + entry = $('
' + message + '
').data('id', curMeta.id); + preview.append(entry); + curMeta.entry = entry; + } - return; - case '<': - svgStr = true; - break; - case 'd': - if (response.indexOf('data:image/svg+xml') === 0) { - var pre = 'data:image/svg+xml;base64,'; - var src = response.substring(pre.length); - response = svgedit.utilities.decode64(src); - svgStr = true; - break; - } else if (response.indexOf('data:image/') === 0) { - imgStr = true; - break; - } - // Else fall through - default: - // TODO: See if there's a way to base64 encode the binary data stream - // var str = 'data:;base64,' + svgedit.utilities.encode64(response, true); + return; + case '<': + svgStr = true; + break; + case 'd': + if (response.indexOf('data:image/svg+xml') === 0) { + var pre = 'data:image/svg+xml;base64,'; + var src = response.substring(pre.length); + response = svgedit.utilities.decode64(src); + svgStr = true; + break; + } else if (response.indexOf('data:image/') === 0) { + imgStr = true; + break; + } + // Else fall through + default: + // TODO: See if there's a way to base64 encode the binary data stream + // var str = 'data:;base64,' + svgedit.utilities.encode64(response, true); - // Assume it's raw image data - // importImage(str); + // Assume it's raw image data + // importImage(str); - // Don't give warning as postMessage may have been used by something else - if (mode !== 'm') { - closeBrowser(); - } else { - pending[id].entry.remove(); - } - // $.alert('Unexpected data was returned: ' + response, function() { - // if (mode !== 'm') { - // closeBrowser(); - // } else { - // pending[id].entry.remove(); - // } - // }); - return; - } + // Don't give warning as postMessage may have been used by something else + if (mode !== 'm') { + closeBrowser(); + } else { + pending[id].entry.remove(); + } + // $.alert('Unexpected data was returned: ' + response, function() { + // if (mode !== 'm') { + // closeBrowser(); + // } else { + // pending[id].entry.remove(); + // } + // }); + return; + } - switch (mode) { - case 's': - // Import one - if (svgStr) { - svgCanvas.importSvgString(response); - } else if (imgStr) { - importImage(response); - } - closeBrowser(); - break; - case 'm': - // Import multiple - multiArr.push([(svgStr ? 'svg' : 'img'), response]); - var title; - curMeta = pending[id]; - if (svgStr) { - if (curMeta && curMeta.name) { - title = curMeta.name; - } else { - // Try to find a title - var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement; - title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')'; - } - if (curMeta) { - preview.children().each(function () { - if ($(this).data('id') === id) { - if (curMeta.preview_url) { - $(this).html('' + title); - } else { - $(this).text(title); - } - submit.removeAttr('disabled'); - } - }); - } else { - preview.append('
' + title + '
'); - submit.removeAttr('disabled'); - } - } else { - if (curMeta && curMeta.preview_url) { - title = curMeta.name || ''; - } - if (curMeta && curMeta.preview_url) { - entry = '' + title; - } else { - entry = ''; - } + switch (mode) { + case 's': + // Import one + if (svgStr) { + svgCanvas.importSvgString(response); + } else if (imgStr) { + importImage(response); + } + closeBrowser(); + break; + case 'm': + // Import multiple + multiArr.push([(svgStr ? 'svg' : 'img'), response]); + var title; + curMeta = pending[id]; + if (svgStr) { + if (curMeta && curMeta.name) { + title = curMeta.name; + } else { + // Try to find a title + var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement; + title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')'; + } + if (curMeta) { + preview.children().each(function () { + if ($(this).data('id') === id) { + if (curMeta.preview_url) { + $(this).html('' + title); + } else { + $(this).text(title); + } + submit.removeAttr('disabled'); + } + }); + } else { + preview.append('
' + title + '
'); + submit.removeAttr('disabled'); + } + } else { + if (curMeta && curMeta.preview_url) { + title = curMeta.name || ''; + } + if (curMeta && curMeta.preview_url) { + entry = '' + title; + } else { + entry = ''; + } - if (curMeta) { - preview.children().each(function () { - if ($(this).data('id') === id) { - $(this).html(entry); - submit.removeAttr('disabled'); - } - }); - } else { - preview.append($('
').append(entry)); - submit.removeAttr('disabled'); - } - } - break; - case 'o': - // Open - if (!svgStr) { break; } - svgEditor.openPrep(function (ok) { - if (!ok) { return; } - svgCanvas.clear(); - svgCanvas.setSvgString(response); - // updateCanvas(); - }); - closeBrowser(); - break; - } - }, true); + if (curMeta) { + preview.children().each(function () { + if ($(this).data('id') === id) { + $(this).html(entry); + submit.removeAttr('disabled'); + } + }); + } else { + preview.append($('
').append(entry)); + submit.removeAttr('disabled'); + } + } + break; + case 'o': + // Open + if (!svgStr) { break; } + svgEditor.openPrep(function (ok) { + if (!ok) { return; } + svgCanvas.clear(); + svgCanvas.setSvgString(response); + // updateCanvas(); + }); + closeBrowser(); + break; + } + }, true); - function toggleMulti (show) { - $('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)}); - if (!preview) { - preview = $('
').css({ - position: 'absolute', - top: 45, - right: 10, - width: 180, - bottom: 45, - background: '#fff', - overflow: 'auto' - }).insertAfter('#lib_framewrap'); + function toggleMulti (show) { + $('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)}); + if (!preview) { + preview = $('
').css({ + position: 'absolute', + top: 45, + right: 10, + width: 180, + bottom: 45, + background: '#fff', + overflow: 'auto' + }).insertAfter('#lib_framewrap'); - submit = $('') - .appendTo('#imgbrowse') - .on('click touchend', function () { - $.each(multiArr, function (i) { - var type = this[0]; - var data = this[1]; - if (type === 'svg') { - svgCanvas.importSvgString(data); - } else { - importImage(data); - } - svgCanvas.moveSelectedElements(i * 20, i * 20, false); - }); - preview.empty(); - multiArr = []; - $('#imgbrowse_holder').hide(); - }).css({ - position: 'absolute', - bottom: 10, - right: -10 - }); - } + submit = $('') + .appendTo('#imgbrowse') + .on('click touchend', function () { + $.each(multiArr, function (i) { + var type = this[0]; + var data = this[1]; + if (type === 'svg') { + svgCanvas.importSvgString(data); + } else { + importImage(data); + } + svgCanvas.moveSelectedElements(i * 20, i * 20, false); + }); + preview.empty(); + multiArr = []; + $('#imgbrowse_holder').hide(); + }).css({ + position: 'absolute', + bottom: 10, + right: -10 + }); + } - preview.toggle(show); - submit.toggle(show); - } + preview.toggle(show); + submit.toggle(show); + } - function showBrowser () { - var browser = $('#imgbrowse'); - if (!browser.length) { - $('
' + - '
').insertAfter('#svg_docprops'); - browser = $('#imgbrowse'); + function showBrowser () { + var browser = $('#imgbrowse'); + if (!browser.length) { + $('
' + + '
').insertAfter('#svg_docprops'); + browser = $('#imgbrowse'); - var allLibs = uiStrings.imagelib.select_lib; + var allLibs = uiStrings.imagelib.select_lib; - var libOpts = $('
    ').appendTo(browser); - var frame = $('