@@ -16,6 +16,7 @@ export const NS = {
|
||||
SE: 'http://svg-edit.googlecode.com',
|
||||
SVG: 'http://www.w3.org/2000/svg',
|
||||
XLINK: 'http://www.w3.org/1999/xlink',
|
||||
OI: 'http://www.optimistik.fr/namespace/svg/OIdata',
|
||||
XML: 'http://www.w3.org/XML/1998/namespace',
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/' // see http://www.w3.org/TR/REC-xml-names/#xmlReserved
|
||||
};
|
||||
|
||||
@@ -166,7 +166,8 @@ export default class ConfigObj {
|
||||
'ext-eyedropper',
|
||||
'ext-grid',
|
||||
'ext-imagelib',
|
||||
'ext-markers',
|
||||
// 'ext-arrows',
|
||||
// 'ext-markers',
|
||||
'ext-overview_window',
|
||||
'ext-panning',
|
||||
'ext-polygon',
|
||||
|
||||
@@ -37,6 +37,33 @@ import MainMenu from './MainMenu.js';
|
||||
|
||||
const {$id, $qa, isNullish, encode64, decode64, blankPageObjectURL} = SvgCanvas;
|
||||
|
||||
/** A storage solution aimed at replacing jQuerys data function.
|
||||
* Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap].
|
||||
* This makes sure the data is garbage collected when the node is removed.
|
||||
*/
|
||||
window.dataStorage = {
|
||||
_storage: new WeakMap(),
|
||||
put: function (element, key, obj) {
|
||||
if (!this._storage.has(element)) {
|
||||
this._storage.set(element, new Map());
|
||||
}
|
||||
this._storage.get(element).set(key, obj);
|
||||
},
|
||||
get: function (element, key) {
|
||||
return this._storage.get(element).get(key);
|
||||
},
|
||||
has: function (element, key) {
|
||||
return this._storage.has(element) && this._storage.get(element).has(key);
|
||||
},
|
||||
remove: function (element, key) {
|
||||
var ret = this._storage.get(element).delete(key);
|
||||
if (!this._storage.get(element).size === 0) {
|
||||
this._storage.delete(element);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -293,20 +320,41 @@ class Editor extends EditorStartup {
|
||||
evt.preventDefault();
|
||||
});
|
||||
}
|
||||
// parents() https://stackoverflow.com/a/12981248
|
||||
getParents(el, parentSelector /* optional */) {
|
||||
|
||||
// If no parentSelector defined will bubble up all the way to *document*
|
||||
if (parentSelector === undefined) {
|
||||
parentSelector = document;
|
||||
}
|
||||
|
||||
var parents = [];
|
||||
var p = el.parentNode;
|
||||
|
||||
while (p !== parentSelector) {
|
||||
var o = p;
|
||||
parents.push(o);
|
||||
p = o.parentNode;
|
||||
}
|
||||
parents.push(parentSelector); // Push that parentSelector you wanted to stop at
|
||||
|
||||
return parents;
|
||||
}
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
setTitles () {
|
||||
// Tooltips not directly associated with a single function
|
||||
const keyAssocs = {
|
||||
'4/Shift+4': '#tools_rect',
|
||||
'5/Shift+5': '#tools_ellipse'
|
||||
'4/Shift+4': 'tools_rect',
|
||||
'5/Shift+5': 'tools_ellipse'
|
||||
};
|
||||
Object.entries(keyAssocs).forEach(([keyval, sel]) => {
|
||||
const menu = ($(sel).parents('#main_menu').length);
|
||||
const parentsElements = this.getParents($id(sel), $id('main_menu'))
|
||||
const menu = (parentsElements.length);
|
||||
|
||||
$qa(sel).forEach((element) => {
|
||||
const t = (menu) ? $(element).text().split(' [')[0] : element.title.split(' [')[0];
|
||||
const t = (menu) ? element.textContent.split(' [')[0] : element.title.split(' [')[0];
|
||||
let keyStr = '';
|
||||
// Shift+Up
|
||||
keyval.split('/').forEach((key, i) => {
|
||||
@@ -427,7 +475,7 @@ class Editor extends EditorStartup {
|
||||
// regular URL
|
||||
this.svgCanvas.embedImage(url, function (dataURI) {
|
||||
// Couldn't embed, so show warning
|
||||
$('#url_notice').toggle(!dataURI);
|
||||
$id('url_notice').style.display = (!dataURI) ? 'block' : 'none';
|
||||
this.defaultImageURL = url;
|
||||
});
|
||||
$id("image_url").style.display = 'block';
|
||||
@@ -559,7 +607,7 @@ class Editor extends EditorStartup {
|
||||
// if (this.curContext) {
|
||||
// new_title = new_title + this.curContext;
|
||||
// }
|
||||
$('title:first').text(newTitle);
|
||||
document.querySelector('title').textContent = newTitle;
|
||||
}
|
||||
|
||||
// called when we've selected a different element
|
||||
@@ -707,9 +755,7 @@ class Editor extends EditorStartup {
|
||||
*/
|
||||
zoomChanged (win, bbox, autoCenter) {
|
||||
const scrbar = 15,
|
||||
// res = this.svgCanvas.getResolution(), // Currently unused
|
||||
wArea = this.workarea;
|
||||
// const canvasPos = $('#svgcanvas').position(); // Currently unused
|
||||
const zInfo = this.svgCanvas.setBBoxZoom(bbox, parseFloat(getComputedStyle(wArea, null).width.replace("px", "")) - scrbar, parseFloat(getComputedStyle(wArea, null).height.replace("px", "")) - scrbar);
|
||||
if (!zInfo) { return; }
|
||||
const zoomlevel = zInfo.zoom,
|
||||
@@ -750,11 +796,11 @@ class Editor extends EditorStartup {
|
||||
if (context) {
|
||||
let str = '';
|
||||
linkStr = '<a href="#" data-root="y">' + this.svgCanvas.getCurrentDrawing().getCurrentLayerName() + '</a>';
|
||||
|
||||
$(context).parentsUntil('#svgcontent > g').andSelf().each(() => {
|
||||
if (this.id) {
|
||||
str += ' > ' + this.id;
|
||||
linkStr += (this !== context) ? ` > <a href="#">${this.id}</a>` : ` > ${this.id}`;
|
||||
const parentsUntil = getParentsUntil(context, '#svgcontent > g');
|
||||
parentsUntil.forEach(function (parent) {
|
||||
if (parent.id) {
|
||||
str += ' > ' + parent.id;
|
||||
linkStr += (parent !== context) ? ` > <a href="#">${parent.id}</a>` : ` > ${parent.id}`;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -762,7 +808,9 @@ class Editor extends EditorStartup {
|
||||
} else {
|
||||
this.curContext = null;
|
||||
}
|
||||
$('#cur_context_panel').toggle(Boolean(context)).html(linkStr);
|
||||
$id('cur_context_panel').style.display = (Boolean(context)) ? 'block' : 'none';
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
$id('cur_context_panel').innerHTML = linkStr;
|
||||
|
||||
this.updateTitle();
|
||||
}
|
||||
@@ -775,13 +823,18 @@ class Editor extends EditorStartup {
|
||||
*/
|
||||
setIcon (elem, iconId) {
|
||||
// eslint-disable-next-line max-len
|
||||
const icon = (typeof iconId === 'string') ? $('<img src="' + this.configObj.curConfig.imgPath + iconId + '">') : iconId.clone();
|
||||
const img = document.createElement("img");
|
||||
img.src = this.configObj.curConfig.imgPath + iconId;
|
||||
const icon = (typeof iconId === 'string') ? img : iconId.cloneNode(true);
|
||||
if (!icon) {
|
||||
// Todo: Investigate why this still occurs in some cases
|
||||
console.log('NOTE: Icon image missing: ' + iconId);
|
||||
return;
|
||||
}
|
||||
$(elem).empty().append(icon);
|
||||
// empty()
|
||||
while($id(elem).firstChild)
|
||||
$id(elem).removeChild($id(elem).firstChild);
|
||||
$id(elem).appendChild(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -817,55 +870,72 @@ class Editor extends EditorStartup {
|
||||
};
|
||||
|
||||
if (ext.context_tools) {
|
||||
$.each(ext.context_tools, function (i, tool) {
|
||||
ext.context_tools.forEach(function(tool, i){
|
||||
// Add select tool
|
||||
const contId = tool.container_id ? (' id="' + tool.container_id + '"') : '';
|
||||
|
||||
let panel = $('#' + tool.panel);
|
||||
let panel = $id(tool.panel);
|
||||
// create the panel if it doesn't exist
|
||||
if (!panel.length) {
|
||||
panel = $('<div>', {id: tool.panel}).appendTo('#tools_top');
|
||||
if (!panel) {
|
||||
panel = document.createElement("div");
|
||||
panel.id = tool.panel;
|
||||
$id('tools_top').appendChild(panel);
|
||||
}
|
||||
|
||||
let html;
|
||||
// TODO: Allow support for other types, or adding to existing tool
|
||||
switch (tool.type) {
|
||||
case 'tool_button': {
|
||||
html = '<div class="tool_button">' + tool.id + '</div>';
|
||||
const div = $(html).appendTo(panel);
|
||||
html = document.createElement("div");
|
||||
html.className = "tool_button";
|
||||
html.textContent = tool.id
|
||||
panel.appendChild(html);
|
||||
if (tool.events) {
|
||||
$.each(tool.events, function (evt, func) {
|
||||
$(div).bind(evt, func);
|
||||
tool.events.forEach((func, evt) => {
|
||||
html.addEventListener(evt, func);
|
||||
});
|
||||
}
|
||||
break;
|
||||
} case 'select': {
|
||||
html = '<label' + contId + '>' +
|
||||
'<select id="' + tool.id + '">';
|
||||
$.each(tool.options, function (val, text) {
|
||||
label = document.createElement("label");
|
||||
if (tool.container_id) {
|
||||
label.id = tool.container_id;
|
||||
}
|
||||
html = '<select id="' + tool.id + '">';
|
||||
tool.options.forEach((text, val) => {
|
||||
const sel = (val === tool.defval) ? ' selected' : '';
|
||||
html += '<option value="' + val + '"' + sel + '>' + text + '</option>';
|
||||
});
|
||||
html += '</select></label>';
|
||||
html += '</select>';
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
label.innerHTML = html;
|
||||
// Creates the tool, hides & adds it, returns the select element
|
||||
const sel = $(html).appendTo(panel).find('select');
|
||||
panel.appendChild(label);
|
||||
|
||||
$.each(tool.events, function (evt, func) {
|
||||
$(sel).bind(evt, func);
|
||||
const sel = label.querySelector('select');
|
||||
|
||||
tool.events.forEach((func, evt) => {
|
||||
sel.addEventListener(evt, func);
|
||||
});
|
||||
break;
|
||||
} case 'button-select': {
|
||||
html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">' +
|
||||
'<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>';
|
||||
const div = document.createElement("div");
|
||||
div.id = tool.id;
|
||||
div.className = "dropdown toolset";
|
||||
div.title = tool.title;
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
div.innerHTML = '<div id="cur_' + tool.id + '" class="icon_label"></div><button></button>';
|
||||
|
||||
const list = $('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists');
|
||||
const list = document.createElement("ul");
|
||||
list.id = tool.id;
|
||||
|
||||
if($id('option_lists')) $id('option_lists').appendChild(list);
|
||||
|
||||
if (tool.colnum) {
|
||||
list.addClass('optcols' + tool.colnum);
|
||||
list.className = ('optcols' + tool.colnum);
|
||||
}
|
||||
|
||||
panel.appendChild(div);
|
||||
// Creates the tool, hides & adds it, returns the select element
|
||||
/* const dropdown = */ $(html).appendTo(panel).children();
|
||||
|
||||
btnSelects.push({
|
||||
elem: ('#' + tool.id),
|
||||
@@ -877,25 +947,30 @@ class Editor extends EditorStartup {
|
||||
|
||||
break;
|
||||
} case 'input': {
|
||||
html = '<label' + contId + '>' +
|
||||
'<span id="' + tool.id + '_label">' +
|
||||
const html = document.createElement("label");
|
||||
if(tool.container_id) { html.id = tool.container_id; }
|
||||
html.innerHTML
|
||||
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
html.innerHTML = '<span id="' + tool.id + '_label">' +
|
||||
tool.label + ':</span>' +
|
||||
'<input id="' + tool.id + '" title="' + tool.title +
|
||||
'" size="' + (tool.size || '4') +
|
||||
'" value="' + (tool.defval || '') + '" type="text"/></label>';
|
||||
'" value="' + (tool.defval || '') + '" type="text"/>';
|
||||
|
||||
// Creates the tool, hides & adds it, returns the select element
|
||||
|
||||
// Add to given tool.panel
|
||||
const inp = $(html).appendTo(panel).find('input');
|
||||
panel.appendChild(html);
|
||||
const inp = html.querySelector('input');
|
||||
|
||||
if (tool.spindata) {
|
||||
inp.SpinButton(tool.spindata);
|
||||
}
|
||||
|
||||
if (tool.events) {
|
||||
$.each(tool.events, function (evt, func) {
|
||||
inp.bind(evt, func);
|
||||
if ( tool?.events !== undefined ) {
|
||||
Object.entries(tool.events).forEach((entry) => {
|
||||
const [evt, func] = entry;
|
||||
inp.addEventListener(evt, func);
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -911,11 +986,6 @@ class Editor extends EditorStartup {
|
||||
return runCallback();
|
||||
}
|
||||
|
||||
/*
|
||||
this.addDropDown('#font_family_dropdown', () => {
|
||||
$('#font_family').val($(this).text()).change();
|
||||
});
|
||||
*/
|
||||
/**
|
||||
* @param {Float} multiplier
|
||||
* @returns {void}
|
||||
@@ -1166,7 +1236,7 @@ class Editor extends EditorStartup {
|
||||
|
||||
// const notif = allStrings.notification; // Currently unused
|
||||
// $.extend will only replace the given strings
|
||||
const oldLayerName = $('#layerlist tr.layersel td.layername').text();
|
||||
const oldLayerName = ($id('#layerlist')) ? $id('#layerlist').querySelector('tr.layersel td.layername').textContent : "";
|
||||
const renameLayer = (oldLayerName === this.uiStrings.common.layer + ' 1');
|
||||
|
||||
this.svgCanvas.setUiStrings(allStrings);
|
||||
@@ -1186,14 +1256,28 @@ class Editor extends EditorStartup {
|
||||
'#linejoin_miter': '#cur_linejoin',
|
||||
'#linecap_butt': '#cur_linecap'
|
||||
};
|
||||
|
||||
$.each(this.elems, function (source, dest) {
|
||||
$(dest).attr('title', $(source)[0].title);
|
||||
});
|
||||
for (const [source, dest] of Object.entries(this.elems)) {
|
||||
if(dest === '#tool_stroke .color_block'){
|
||||
if($id('tool_stroke')) {
|
||||
$id('tool_stroke').querySelector('.color_block').setAttribute('title', $id(source).title);
|
||||
}
|
||||
} else if(dest === '#tool_fill label, #tool_fill .color_block'){
|
||||
if($id('tool_fill') && $id('tool_fill').querySelector('.color_block')) {
|
||||
$id('tool_fill').querySelector('label').setAttribute('title', $id(source).title);
|
||||
console.log($id('tool_fill').querySelector('.color_block'));
|
||||
$id('tool_fill').querySelector('.color_block').setAttribute('title', $id(source).title);
|
||||
}
|
||||
} else {
|
||||
if ($id(dest)) {
|
||||
$id(dest).setAttribute('title', $id(source).title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy alignment titles
|
||||
$('#multiselected_panel div[id^=tool_align]').each(() => {
|
||||
$('#tool_pos' + this.id.substr(10))[0].title = this.title;
|
||||
const selElements = $id('multiselected_panel').querySelectorAll('div[id^=tool_align]');
|
||||
Array.from(selElements).forEach(function(element) {
|
||||
$id('tool_pos' + element.id.substr(10)).title = element.title;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -131,16 +131,21 @@ class EditorStartup {
|
||||
this.selectedElement = null;
|
||||
this.multiselected = false;
|
||||
|
||||
$('#cur_context_panel').delegate('a', 'click', (evt) => {
|
||||
const link = $(evt.currentTarget);
|
||||
if (link.attr('data-root')) {
|
||||
this.svgCanvas.leaveContext();
|
||||
} else {
|
||||
this.svgCanvas.setContext(link.text());
|
||||
}
|
||||
this.svgCanvas.clearSelection();
|
||||
return false;
|
||||
});
|
||||
const aLinks = $id('cur_context_panel').querySelectorAll('a')
|
||||
|
||||
for (const aLink of aLinks) {
|
||||
aLink.addEventListener('click', (evt) => {
|
||||
const link = evt.currentTarget;
|
||||
if (link.hasAttribute('data-root')) {
|
||||
this.svgCanvas.leaveContext();
|
||||
} else {
|
||||
this.svgCanvas.setContext(link.textContent);
|
||||
}
|
||||
this.svgCanvas.clearSelection();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// bind the selected event to our function that handles updates to the UI
|
||||
this.svgCanvas.bind('selected', this.selectedChanged.bind(this));
|
||||
this.svgCanvas.bind('transition', this.elementTransition.bind(this));
|
||||
@@ -178,7 +183,7 @@ class EditorStartup {
|
||||
);
|
||||
this.svgCanvas.bind('contextset', this.contextChanged.bind(this));
|
||||
this.svgCanvas.bind('extension_added', this.extAdded.bind(this));
|
||||
this.svgCanvas.textActions.setInputElem($('#text')[0]);
|
||||
this.svgCanvas.textActions.setInputElem($id('text'));
|
||||
|
||||
this.setBackground(this.configObj.pref('bkgd_color'), this.configObj.pref('bkgd_url'));
|
||||
|
||||
@@ -195,7 +200,12 @@ class EditorStartup {
|
||||
$id('se-img-prop').setAttribute('save', this.configObj.pref('img_save'));
|
||||
|
||||
// Lose focus for select elements when changed (Allows keyboard shortcuts to work better)
|
||||
$('select').change((evt) => { $(evt.currentTarget).blur(); });
|
||||
const selElements = document.querySelectorAll("select");
|
||||
Array.from(selElements).forEach(function(element) {
|
||||
element.addEventListener('change', function(evt) {
|
||||
evt.currentTarget.blur();
|
||||
});
|
||||
});
|
||||
|
||||
// fired when user wants to move elements to another layer
|
||||
let promptMoveLayerOnce = false;
|
||||
@@ -233,8 +243,15 @@ class EditorStartup {
|
||||
self.svgCanvas.setSegType(evt.currentTarget.value);
|
||||
});
|
||||
|
||||
$('#text').bind('keyup input', (evt) => {
|
||||
this.svgCanvas.setTextContent(evt.currentTarget.value);
|
||||
function addListenerMulti(element, eventNames, listener) {
|
||||
var events = eventNames.split(' ');
|
||||
for (var i=0, iLen=events.length; i<iLen; i++) {
|
||||
element.addEventListener(events[i], listener, false);
|
||||
}
|
||||
}
|
||||
|
||||
addListenerMulti($id('text'), 'keyup input', function(evt){
|
||||
self.svgCanvas.setTextContent(evt.currentTarget.value);
|
||||
});
|
||||
$id('image_url').addEventListener('change', function(evt) {
|
||||
self.setImageURL(evt.currentTarget.value);
|
||||
@@ -257,7 +274,7 @@ class EditorStartup {
|
||||
let lastX = null, lastY = null,
|
||||
panning = false, keypan = false;
|
||||
|
||||
$('#svgcanvas').bind('mousemove mouseup', function (evt) {
|
||||
$id('svgcanvas').addEventListener('mouseup', function(evt) {
|
||||
if (panning === false) { return true; }
|
||||
|
||||
wArea.scrollLeft -= (evt.clientX - lastX);
|
||||
@@ -268,7 +285,20 @@ class EditorStartup {
|
||||
|
||||
if (evt.type === 'mouseup') { panning = false; }
|
||||
return false;
|
||||
}).mousedown(function (evt) {
|
||||
});
|
||||
$id('svgcanvas').addEventListener('mousemove', function(evt) {
|
||||
if (panning === false) { return true; }
|
||||
|
||||
wArea.scrollLeft -= (evt.clientX - lastX);
|
||||
wArea.scrollTop -= (evt.clientY - lastY);
|
||||
|
||||
lastX = evt.clientX;
|
||||
lastY = evt.clientY;
|
||||
|
||||
if (evt.type === 'mouseup') { panning = false; }
|
||||
return false;
|
||||
});
|
||||
$id('svgcanvas').addEventListener('mousedown', function(evt) {
|
||||
if (evt.button === 1 || keypan === true) {
|
||||
panning = true;
|
||||
lastX = evt.clientX;
|
||||
@@ -278,7 +308,7 @@ class EditorStartup {
|
||||
return true;
|
||||
});
|
||||
|
||||
$(window).mouseup(() => {
|
||||
window.addEventListener('mouseup', function(evt) {
|
||||
panning = false;
|
||||
});
|
||||
|
||||
@@ -323,20 +353,24 @@ class EditorStartup {
|
||||
* @returns {void}
|
||||
*/
|
||||
const unfocus = () => {
|
||||
$(inp).blur();
|
||||
inp.blur();
|
||||
};
|
||||
|
||||
$('#svg_editor').find('button, select, input:not(#text)').focus(() => {
|
||||
inp = this;
|
||||
this.uiContext = 'toolbars';
|
||||
this.workarea.addEventListener('mousedown', unfocus);
|
||||
}).blur(() => {
|
||||
this.uiContext = 'canvas';
|
||||
this.workarea.removeEventListener('mousedown', unfocus);
|
||||
// Go back to selecting text if in textedit mode
|
||||
if (this.svgCanvas.getMode() === 'textedit') {
|
||||
$('#text').focus();
|
||||
}
|
||||
const liElems = document.getElementById('svg_editor').querySelectorAll('button, select, input:not(#text)');
|
||||
Array.prototype.forEach.call(liElems, function(el, i){
|
||||
el.addEventListener("focus", (e) => {
|
||||
inp = e.currentTarget;
|
||||
this.uiContext = 'toolbars';
|
||||
this.workarea.addEventListener('mousedown', unfocus);
|
||||
});
|
||||
el.addEventListener("blur", () => {
|
||||
this.uiContext = 'canvas';
|
||||
this.workarea.removeEventListener('mousedown', unfocus);
|
||||
// Go back to selecting text if in textedit mode
|
||||
if (this.svgCanvas.getMode() === 'textedit') {
|
||||
$id('text').focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
// ref: https://stackoverflow.com/a/1038781
|
||||
function getWidth() {
|
||||
@@ -365,7 +399,7 @@ class EditorStartup {
|
||||
|
||||
window.addEventListener('resize', (evt) => {
|
||||
Object.entries(winWh).forEach(([type, val]) => {
|
||||
const curval = $(window)[type]();
|
||||
const curval = (type === 'width') ? window.innerWidth - 15 : window.innerHeight;
|
||||
this.workarea['scroll' + (type === 'width' ? 'Left' : 'Top')] -= (curval - val) / 2;
|
||||
winWh[type] = curval;
|
||||
});
|
||||
@@ -376,7 +410,7 @@ class EditorStartup {
|
||||
this.rulers.manageScroll();
|
||||
});
|
||||
|
||||
$('#url_notice').click(() => {
|
||||
$id('url_notice').addEventListener('click', () => {
|
||||
seAlert(this.title);
|
||||
});
|
||||
|
||||
@@ -407,10 +441,17 @@ class EditorStartup {
|
||||
this.workarea.style.lineHeight = this.workarea.style.height;
|
||||
};
|
||||
|
||||
$(window).bind('load resize', centerCanvas);
|
||||
addListenerMulti(window, 'load resize', centerCanvas);
|
||||
|
||||
// Prevent browser from erroneously repopulating fields
|
||||
$('input,select').attr('autocomplete', 'off');
|
||||
const inputEles = document.querySelectorAll('input');
|
||||
Array.from(inputEles).forEach(function(inputEle) {
|
||||
inputEle.setAttribute('autocomplete', 'off');
|
||||
});
|
||||
const selectEles = document.querySelectorAll('select');
|
||||
Array.from(selectEles).forEach(function(inputEle) {
|
||||
inputEle.setAttribute('autocomplete', 'off');
|
||||
});
|
||||
|
||||
$id('se-svg-editor-dialog').addEventListener('change', function (e) {
|
||||
if (e?.detail?.copy === 'click') {
|
||||
@@ -456,7 +497,7 @@ class EditorStartup {
|
||||
this.moveUpDownSelected('Down');
|
||||
break;
|
||||
case 'move_back':
|
||||
this.svgCanvas.moveToBottomSelected();
|
||||
this.svgCanvas.moveToBottomSelectedElement();
|
||||
break;
|
||||
default:
|
||||
if (hasCustomHandler(action)) {
|
||||
@@ -485,7 +526,7 @@ class EditorStartup {
|
||||
$id('tool_wireframe').click();
|
||||
}
|
||||
|
||||
$('#rulers').toggle(Boolean(this.configObj.curConfig.showRulers));
|
||||
$id('rulers').style.display = (Boolean(this.configObj.curConfig.showRulers)) ? 'block' : 'none';
|
||||
|
||||
if (this.configObj.curConfig.showRulers) {
|
||||
$editDialog.setAttribute('showrulers', true);
|
||||
@@ -625,8 +666,10 @@ class EditorStartup {
|
||||
this.workarea.addEventListener('dragover', this.onDragOver);
|
||||
this.workarea.addEventListener('dragleave', this.onDragLeave);
|
||||
this.workarea.addEventListener('drop', importImage);
|
||||
const imgImport = $('<input type="file">').change(importImage);
|
||||
$(window).on('importImages', () => imgImport.click());
|
||||
const imgImport = document.createElement('input');
|
||||
imgImport.type="file";
|
||||
imgImport.addEventListener('change', importImage);
|
||||
window.addEventListener('importImages', () => imgImport.click());
|
||||
}
|
||||
|
||||
this.updateCanvas(true);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* globals $ */
|
||||
import SvgCanvas from "../svgcanvas/svgcanvas.js";
|
||||
import {convertUnit, isValidUnit} from '../common/units.js';
|
||||
import {isChrome} from '../common/browser.js';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* globals $ */
|
||||
import {getTypeMap} from '../common/units.js';
|
||||
import rulersTemplate from './templates/rulersTemplate.js';
|
||||
/**
|
||||
@@ -53,14 +52,15 @@ class Rulers {
|
||||
const dim = isX ? 'x' : 'y';
|
||||
const lentype = isX ? 'width' : 'height';
|
||||
const contentDim = Number(contentElem.getAttribute(dim));
|
||||
|
||||
const $hcanvOrig = $('#ruler_' + dim + ' canvas:first');
|
||||
const {$id} = this.svgCanvas;
|
||||
const $hcanvOrig = $id('ruler_' + dim).querySelector('canvas');
|
||||
|
||||
// Bit of a hack to fully clear the canvas in Safari & IE9
|
||||
const $hcanv = $hcanvOrig.clone();
|
||||
const $hcanv = $hcanvOrig.cloneNode(true);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
$hcanvOrig.replaceWith($hcanv);
|
||||
|
||||
const hcanv = $hcanv[0];
|
||||
const hcanv = $hcanv;
|
||||
|
||||
// Set the canvas size to the width of the container
|
||||
let rulerLen;
|
||||
@@ -78,7 +78,12 @@ class Rulers {
|
||||
ctx.fillRect(0, 0, hcanv.width, hcanv.height);
|
||||
|
||||
// Remove any existing canvasses
|
||||
$hcanv.siblings().remove();
|
||||
const elements = Array.prototype.filter.call($hcanv.parentNode.children, function(child){
|
||||
return child !== $hcanv;
|
||||
});
|
||||
Array.from(elements).forEach(function(element) {
|
||||
element.remove();
|
||||
});
|
||||
|
||||
// Create multiple canvases when necessary (due to browser limits)
|
||||
if (rulerLen >= limit) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @param {any} obj
|
||||
* @returns {any}
|
||||
*/
|
||||
export function findPos (obj) {
|
||||
export function findPos(obj) {
|
||||
let curleft = 0;
|
||||
let curtop = 0;
|
||||
if (obj.offsetParent) {
|
||||
@@ -10,9 +10,9 @@ export function findPos (obj) {
|
||||
curleft += obj.offsetLeft;
|
||||
curtop += obj.offsetTop;
|
||||
} while (obj = obj.offsetParent);
|
||||
return {left: curleft, top: curtop};
|
||||
return { left: curleft, top: curtop };
|
||||
}
|
||||
return {left: curleft, top: curtop};
|
||||
return { left: curleft, top: curtop };
|
||||
}
|
||||
|
||||
export function isObject(item) {
|
||||
@@ -34,4 +34,184 @@ export function mergeDeep(target, source) {
|
||||
});
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the closest matching element up the DOM tree.
|
||||
* @param {Element} elem Starting element
|
||||
* @param {String} selector Selector to match against (class, ID, data attribute, or tag)
|
||||
* @return {Boolean|Element} Returns null if not match found
|
||||
*/
|
||||
export function getClosest(elem, selector) {
|
||||
const firstChar = selector.charAt(0);
|
||||
const supports = 'classList' in document.documentElement;
|
||||
let attribute, value;
|
||||
// If selector is a data attribute, split attribute from value
|
||||
if (firstChar === '[') {
|
||||
selector = selector.substr(1, selector.length - 2);
|
||||
attribute = selector.split('=');
|
||||
if (attribute.length > 1) {
|
||||
value = true;
|
||||
attribute[1] = attribute[1].replace(/"/g, '').replace(/'/g, '');
|
||||
}
|
||||
}
|
||||
// Get closest match
|
||||
for (; elem && elem !== document && elem.nodeType === 1; elem = elem.parentNode) {
|
||||
// If selector is a class
|
||||
if (firstChar === '.') {
|
||||
if (supports) {
|
||||
if (elem.classList.contains(selector.substr(1))) {
|
||||
return elem;
|
||||
}
|
||||
} else {
|
||||
if (new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test(elem.className)) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If selector is an ID
|
||||
if (firstChar === '#') {
|
||||
if (elem.id === selector.substr(1)) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
// If selector is a data attribute
|
||||
if (firstChar === '[') {
|
||||
if (elem.hasAttribute(attribute[0])) {
|
||||
if (value) {
|
||||
if (elem.getAttribute(attribute[0]) === attribute[1]) {
|
||||
return elem;
|
||||
}
|
||||
} else {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If selector is a tag
|
||||
if (elem.tagName.toLowerCase() === selector) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all DOM element up the tree that contain a class, ID, or data attribute
|
||||
* @param {Node} elem The base element
|
||||
* @param {String} selector The class, id, data attribute, or tag to look for
|
||||
* @return {Array} Null if no match
|
||||
*/
|
||||
export function getParents(elem, selector) {
|
||||
const parents = [];
|
||||
let firstChar;
|
||||
if ( selector ) {
|
||||
firstChar = selector.charAt(0);
|
||||
}
|
||||
// Get matches
|
||||
for ( ; elem && elem !== document; elem = elem.parentNode ) {
|
||||
if ( selector ) {
|
||||
// If selector is a class
|
||||
if ( firstChar === '.' ) {
|
||||
if ( elem.classList.contains( selector.substr(1) ) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is an ID
|
||||
if ( firstChar === '#' ) {
|
||||
if ( elem.id === selector.substr(1) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is a data attribute
|
||||
if ( firstChar === '[' ) {
|
||||
if ( elem.hasAttribute( selector.substr(1, selector.length - 1) ) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is a tag
|
||||
if ( elem.tagName.toLowerCase() === selector ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
} else {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// Return parents if any exist
|
||||
if ( parents.length === 0 ) {
|
||||
return null;
|
||||
} else {
|
||||
return parents;
|
||||
}
|
||||
};
|
||||
|
||||
export function getParentsUntil(elem, parent, selector) {
|
||||
let parents = [];
|
||||
let parentType;
|
||||
let selectorType;
|
||||
if ( parent ) {
|
||||
parentType = parent.charAt(0);
|
||||
}
|
||||
if ( selector ) {
|
||||
selectorType = selector.charAt(0);
|
||||
}
|
||||
// Get matches
|
||||
for ( ; elem && elem !== document; elem = elem.parentNode ) {
|
||||
// Check if parent has been reached
|
||||
if ( parent ) {
|
||||
// If parent is a class
|
||||
if ( parentType === '.' ) {
|
||||
if ( elem.classList.contains( parent.substr(1) ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If parent is an ID
|
||||
if ( parentType === '#' ) {
|
||||
if ( elem.id === parent.substr(1) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If parent is a data attribute
|
||||
if ( parentType === '[' ) {
|
||||
if ( elem.hasAttribute( parent.substr(1, parent.length - 1) ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If parent is a tag
|
||||
if ( elem.tagName.toLowerCase() === parent ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( selector ) {
|
||||
// If selector is a class
|
||||
if ( selectorType === '.' ) {
|
||||
if ( elem.classList.contains( selector.substr(1) ) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is an ID
|
||||
if ( selectorType === '#' ) {
|
||||
if ( elem.id === selector.substr(1) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is a data attribute
|
||||
if ( selectorType === '[' ) {
|
||||
if ( elem.hasAttribute( selector.substr(1, selector.length - 1) ) ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// If selector is a tag
|
||||
if ( elem.tagName.toLowerCase() === selector ) {
|
||||
parents.push( elem );
|
||||
}
|
||||
} else {
|
||||
parents.push( elem );
|
||||
}
|
||||
}
|
||||
// Return parents if any exist
|
||||
if ( parents.length === 0 ) {
|
||||
return null;
|
||||
} else {
|
||||
return parents;
|
||||
}
|
||||
};
|
||||
@@ -223,7 +223,6 @@ export function jGraduateMethod (elem, options, okCallback, cancelCallback) {
|
||||
idref = '#' + $this.getAttribute('id') + ' ';
|
||||
// JFH !!!!!
|
||||
const $shadowRoot = elem.parentNode;
|
||||
// const $wc = (selector) => $($shadowRoot.querySelectorAll(selector));
|
||||
|
||||
if (!idref) {
|
||||
// eslint-disable-next-line no-alert
|
||||
|
||||
@@ -134,45 +134,3 @@ export class SEPalette extends HTMLElement {
|
||||
|
||||
// Register
|
||||
customElements.define('se-palette', SEPalette);
|
||||
|
||||
/* #palette_holder {
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
height: 16px;
|
||||
background: #f0f0f0;
|
||||
border-radius: 3px;
|
||||
z-index: 2;
|
||||
|
||||
#palette {
|
||||
float: left;
|
||||
width: 632px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
$('.palette_item').mousedown(function (evt) {
|
||||
// shift key or right click for stroke
|
||||
const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill';
|
||||
let color = $(this).data('rgb');
|
||||
let paint;
|
||||
|
||||
// Webkit-based browsers returned 'initial' here for no stroke
|
||||
if (color === 'none' || color === 'transparent' || color === 'initial') {
|
||||
color = 'none';
|
||||
paint = new $.jGraduate.Paint();
|
||||
} else {
|
||||
paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)});
|
||||
}
|
||||
|
||||
paintBox[picker].setPaint(paint);
|
||||
svgCanvas.setColor(picker, color);
|
||||
|
||||
if (color !== 'none' && svgCanvas.getPaintOpacity(picker) !== 1) {
|
||||
svgCanvas.setPaintOpacity(picker, 1.0);
|
||||
}
|
||||
updateToolButtonState();
|
||||
}).bind('contextmenu', function (e) { e.preventDefault(); });
|
||||
|
||||
*/
|
||||
|
||||
@@ -98,14 +98,17 @@ function exportPDF () {
|
||||
const frameBase = 'https://raw.githack.com/SVG-Edit/svgedit/master';
|
||||
// const frameBase = 'http://localhost:8001';
|
||||
const framePath = '/editor/xdomain-svg-editor-es.html?extensions=ext-xdomain-messaging.js';
|
||||
const iframe = $('<iframe width="900px" height="600px" id="svgedit" src="javascript:0"></iframe>');
|
||||
iframe[0].src = frameBase + framePath +
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = "svgedit";
|
||||
iframe.style.width = "900px";
|
||||
iframe.style.width = "600px";
|
||||
iframe.src = frameBase + framePath +
|
||||
(location.href.includes('?')
|
||||
// ? location.href.replace(/\?(?<search>.*)$/, '&$<search>')
|
||||
? location.href.replace(/\?(.*)$/, '&$1')
|
||||
: ''); // Append arguments to this file onto the iframe
|
||||
|
||||
iframe[0].addEventListener('load', function () {
|
||||
iframe.addEventListener('load', function () {
|
||||
svgCanvas = new EmbeddedSVGEdit(frame, [new URL(frameBase).origin]);
|
||||
// Hide main button, as we will be controlling new, load, save, etc. from the host document
|
||||
let doc;
|
||||
@@ -121,10 +124,10 @@ iframe[0].addEventListener('load', function () {
|
||||
}
|
||||
|
||||
// Add event handlers now that `svgCanvas` is ready
|
||||
$('#load').click(loadSvg);
|
||||
$('#save').click(saveSvg);
|
||||
$('#exportPNG').click(exportPNG);
|
||||
$('#exportPDF').click(exportPDF);
|
||||
$id('load').addEventListener('click', loadSvg);
|
||||
$id('save').addEventListener('click', saveSvg);
|
||||
$id('exportPNG').addEventListener('click', exportPNG);
|
||||
$id('exportPDF').addEventListener('click', exportPDF);
|
||||
});
|
||||
$('body').append(iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const frame = document.getElementById('svgedit');
|
||||
|
||||
@@ -89,7 +89,7 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
$('#arrow_panel').toggle(on);
|
||||
$id('arrow_panel').style.display = (on) ? 'block' : 'none';
|
||||
if (on) {
|
||||
const el = selElems[0];
|
||||
const end = el.getAttribute('marker-end');
|
||||
@@ -219,21 +219,22 @@ export default {
|
||||
const marker = getLinked(elem, 'marker-' + type);
|
||||
if (!marker) { return; }
|
||||
|
||||
const curColor = $(marker).children().attr('fill');
|
||||
const curD = $(marker).children().attr('d');
|
||||
const curColor = marker.children.getAttribute('fill');
|
||||
const curD = marker.children.getAttribute('d');
|
||||
if (curColor === color) { return; }
|
||||
|
||||
const allMarkers = $(defs).find('marker');
|
||||
const allMarkers = defs.querySelectorAll('marker');
|
||||
let newMarker = null;
|
||||
// Different color, check if already made
|
||||
allMarkers.each(function () {
|
||||
const attrs = $(this).children().attr(['fill', 'd']);
|
||||
if (attrs.fill === color && attrs.d === curD) {
|
||||
Array.from(allMarkers).forEach(function(marker) {
|
||||
const attrsFill = marker.children.getAttribute('fill');
|
||||
const attrsD = marker.children.getAttribute('d');
|
||||
if (attrsFill === color && attrsD === curD) {
|
||||
// Found another marker with this color and this path
|
||||
newMarker = this;
|
||||
newMarker = marker;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!newMarker) {
|
||||
// Create a new marker with this color
|
||||
const lastId = marker.id;
|
||||
@@ -241,17 +242,17 @@ export default {
|
||||
|
||||
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
|
||||
|
||||
$(newMarker).children().attr('fill', color);
|
||||
newMarker.children.setAttribute('fill', color);
|
||||
}
|
||||
|
||||
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
|
||||
elem.setAttribute('marker-' + type, 'url(#' + newMarker.id + ')');
|
||||
|
||||
// Check if last marker can be removed
|
||||
let remove = true;
|
||||
$(S.svgcontent).find('line, polyline, path, polygon').each(function () {
|
||||
const element = this;
|
||||
$.each(mtypes, function (j, mtype) {
|
||||
if ($(element).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
|
||||
const sElements = S.svgcontent.querySelectorAll('line, polyline, path, polygon');
|
||||
Array.prototype.forEach.call(sElements, function(element, i){
|
||||
mtypes.forEach(function(mtype, j){
|
||||
if (element.getAttribute('marker-' + mtype) === 'url(#' + marker.id + ')') {
|
||||
remove = false;
|
||||
return remove;
|
||||
}
|
||||
@@ -263,7 +264,7 @@ export default {
|
||||
|
||||
// Not found, so can safely remove
|
||||
if (remove) {
|
||||
$(marker).remove();
|
||||
marker.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -289,7 +290,7 @@ export default {
|
||||
$id("arrow_panel").style.display = 'none';
|
||||
|
||||
// Set ID so it can be translated in locale file
|
||||
$('#arrow_list option')[0].id = 'connector_no_arrow';
|
||||
$id('arrow_list option').setAttribute('id', 'connector_no_arrow');
|
||||
},
|
||||
async addLangData ({lang, importLocale}) {
|
||||
const {langList} = await importLocale();
|
||||
|
||||
@@ -38,7 +38,7 @@ export default {
|
||||
$id("showbutton").style.display = 'block';
|
||||
};
|
||||
const showPanel = function (on) {
|
||||
$('#closepath_panel').toggle(on);
|
||||
$id('closepath_panel').style.display = (on) ? 'block' : 'none';
|
||||
if (on) {
|
||||
const path = selElems[0];
|
||||
if (path) { updateButton(path); }
|
||||
|
||||
@@ -27,8 +27,7 @@ export default {
|
||||
const {getElem} = svgCanvas;
|
||||
const {$, svgroot} = S,
|
||||
addElem = svgCanvas.addSVGElementFromJson,
|
||||
selManager = S.selectorManager,
|
||||
elData = $.data;
|
||||
selManager = S.selectorManager;
|
||||
|
||||
let startX,
|
||||
startY,
|
||||
@@ -88,7 +87,6 @@ export default {
|
||||
*/
|
||||
function getOffset (side, line) {
|
||||
const giveOffset = line.getAttribute('marker-' + side);
|
||||
// const giveOffset = $(line).data(side+'_off');
|
||||
|
||||
// TODO: Make this number (5) be based on marker width/height
|
||||
const size = line.getAttribute('stroke-width') * 5;
|
||||
@@ -100,12 +98,14 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
let connRules = $('#connector_rules');
|
||||
if (!connRules.length) {
|
||||
connRules = $('<style id="connector_rules"></style>').appendTo('head');
|
||||
let connRules = $id('connector_rules');
|
||||
if (!connRules) {
|
||||
connRules = document.createElement('style');
|
||||
connRules.setAttribute('id', 'connector_rules');
|
||||
document.getElementsByTagName("head")[0].appendChild(connRules);
|
||||
}
|
||||
connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }');
|
||||
$('#connector_panel').toggle(on);
|
||||
connRules.textContent = (!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }');
|
||||
$id('connector_panel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,24 +161,24 @@ export default {
|
||||
// const sw = line.getAttribute('stroke-width') * 5;
|
||||
|
||||
// Update bbox for this element
|
||||
const bb = elData(line, pre + '_bb');
|
||||
const bb = dataStorage.get(line, pre + '_bb');
|
||||
bb.x = conn.start_x + diffX;
|
||||
bb.y = conn.start_y + diffY;
|
||||
elData(line, pre + '_bb', bb);
|
||||
dataStorage.put(line, pre + '_bb', bb);
|
||||
|
||||
const altPre = conn.is_start ? 'end' : 'start';
|
||||
|
||||
// Get center pt of connected element
|
||||
const bb2 = elData(line, altPre + '_bb');
|
||||
const bb2 = dataStorage.get(line, altPre + '_bb');
|
||||
const srcX = bb2.x + bb2.width / 2;
|
||||
const srcY = bb2.y + bb2.height / 2;
|
||||
|
||||
// Set point of element being moved
|
||||
const pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
|
||||
const 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
|
||||
const pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
|
||||
const pt2 = getBBintersect(pt.x, pt.y, dataStorage.get(line, altPre + '_bb'), getOffset(altPre, line));
|
||||
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
|
||||
}
|
||||
}
|
||||
@@ -189,54 +189,50 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function findConnectors (elems = selElems) {
|
||||
const connectors = $(svgcontent).find('.se_connector');
|
||||
// const connectors = svgcontent.querySelectorAll('.se_connector');
|
||||
const connectors = svgcontent.querySelectorAll('.se_connector');
|
||||
connections = [];
|
||||
|
||||
// Loop through connectors to see if one is connected to the element
|
||||
connectors.each(function () {
|
||||
Array.prototype.forEach.call(connectors, function(ethis, i){
|
||||
let addThis;
|
||||
/**
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function add () {
|
||||
if (elems.includes(this)) {
|
||||
// Pretend this element is selected
|
||||
addThis = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Grab the ends
|
||||
const parts = [];
|
||||
['start', 'end'].forEach(function (pos, i) {
|
||||
const key = 'c_' + pos;
|
||||
let part = elData(this, key);
|
||||
let part = dataStorage.get(ethis, key);
|
||||
if (part === null || part === undefined) { // Does this ever return nullish values?
|
||||
part = document.getElementById(
|
||||
this.attributes['se:connector'].value.split(' ')[i]
|
||||
ethis.attributes['se:connector'].value.split(' ')[i]
|
||||
);
|
||||
elData(this, 'c_' + pos, part.id);
|
||||
elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part]));
|
||||
dataStorage.put(ethis, 'c_' + pos, part.id);
|
||||
dataStorage.put(ethis, pos + '_bb', svgCanvas.getStrokedBBox([part]));
|
||||
} else part = document.getElementById(part);
|
||||
parts.push(part);
|
||||
}, this);
|
||||
}, ethis);
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const cElem = parts[i];
|
||||
|
||||
addThis = false;
|
||||
// The connected element might be part of a selected group
|
||||
$(cElem).parents().each(add);
|
||||
parents = svgCanvas.getParents(cElem.parentNode);
|
||||
Array.prototype.forEach.call(parents, function(el, i){
|
||||
if (elems.includes(el)) {
|
||||
// Pretend this element is selected
|
||||
addThis = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!cElem || !cElem.parentNode) {
|
||||
$(this).remove();
|
||||
ethis.remove();
|
||||
continue;
|
||||
}
|
||||
if (elems.includes(cElem) || addThis) {
|
||||
const bb = svgCanvas.getStrokedBBox([cElem]);
|
||||
connections.push({
|
||||
elem: cElem,
|
||||
connector: this,
|
||||
connector: ethis,
|
||||
is_start: (i === 0),
|
||||
start_x: bb.x,
|
||||
start_y: bb.y
|
||||
@@ -270,13 +266,13 @@ export default {
|
||||
const bb = svgCanvas.getStrokedBBox([elem]);
|
||||
bb.x = conn.start_x;
|
||||
bb.y = conn.start_y;
|
||||
elData(line, pre + '_bb', bb);
|
||||
/* const addOffset = */ elData(line, pre + '_off');
|
||||
dataStorage.put(line, pre + '_bb', bb);
|
||||
/* const addOffset = */ dataStorage.get(line, pre + '_off');
|
||||
|
||||
const altPre = conn.is_start ? 'end' : 'start';
|
||||
|
||||
// Get center pt of connected element
|
||||
const bb2 = elData(line, altPre + '_bb');
|
||||
const bb2 = dataStorage.get(line, altPre + '_bb');
|
||||
const srcX = bb2.x + bb2.width / 2;
|
||||
const srcY = bb2.y + bb2.height / 2;
|
||||
|
||||
@@ -285,7 +281,7 @@ export default {
|
||||
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
|
||||
|
||||
// Set point of connected element
|
||||
const pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
|
||||
const pt2 = getBBintersect(pt.x, pt.y, dataStorage.get(line, altPre + '_bb'), getOffset(altPre, line));
|
||||
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
|
||||
|
||||
// Update points attribute manually for webkit
|
||||
@@ -308,7 +304,8 @@ export default {
|
||||
const gse = svgCanvas.groupSelectedElements;
|
||||
|
||||
svgCanvas.groupSelectedElements = function (...args) {
|
||||
svgCanvas.removeFromSelection($('.se_connector').toArray());
|
||||
|
||||
svgCanvas.removeFromSelection(document.querySelectorAll('.se_connector'));
|
||||
return gse.apply(this, args);
|
||||
};
|
||||
|
||||
@@ -329,17 +326,18 @@ export default {
|
||||
*/
|
||||
function init () {
|
||||
// Make sure all connectors have data set
|
||||
$(svgcontent).find('*').each(function () {
|
||||
const conn = this.getAttributeNS(seNs, 'connector');
|
||||
const elements = svgcontent.querySelectorAll('*');
|
||||
elements.forEach(function (curthis) {
|
||||
const conn = curthis.getAttributeNS(seNs, 'connector');
|
||||
if (conn) {
|
||||
this.setAttribute('class', 'se_connector');
|
||||
curthis.setAttribute('class', 'se_connector');
|
||||
const connData = conn.split(' ');
|
||||
const sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]);
|
||||
const 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);
|
||||
dataStorage.put(curthis, 'c_start', connData[0]);
|
||||
dataStorage.put(curthis, 'c_end', connData[1]);
|
||||
dataStorage.put(curthis, 'start_bb', sbb);
|
||||
dataStorage.put(curthis, 'end_bb', ebb);
|
||||
svgCanvas.getEditorNS(true);
|
||||
}
|
||||
});
|
||||
@@ -379,13 +377,13 @@ export default {
|
||||
|
||||
const mouseTarget = e.target;
|
||||
|
||||
const parents = $(mouseTarget).parents();
|
||||
const parents = svgCanvas.getParents(mouseTarget.parentNode);
|
||||
|
||||
if ($.inArray(svgcontent, parents) !== -1) {
|
||||
// Connectable element
|
||||
|
||||
// If child of foreignObject, use parent
|
||||
const fo = $(mouseTarget).closest('foreignObject');
|
||||
const fo = svgCanvas.getClosest(mouseTarget.parentNode, 'foreignObject');
|
||||
startElem = fo.length ? fo[0] : mouseTarget;
|
||||
|
||||
// Get center of source element
|
||||
@@ -408,7 +406,7 @@ export default {
|
||||
style: 'pointer-events:none'
|
||||
}
|
||||
});
|
||||
elData(curLine, 'start_bb', bb);
|
||||
dataStorage.put(curLine, 'start_bb', bb);
|
||||
}
|
||||
return {
|
||||
started: true
|
||||
@@ -433,7 +431,7 @@ export default {
|
||||
if (mode === 'connector' && started) {
|
||||
// const sw = curLine.getAttribute('stroke-width') * 3;
|
||||
// Set start point (adjusts based on bb)
|
||||
const pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine));
|
||||
const pt = getBBintersect(x, y, dataStorage.get(curLine, 'start_bb'), getOffset('start', curLine));
|
||||
startX = pt.x;
|
||||
startY = pt.y;
|
||||
|
||||
@@ -446,7 +444,7 @@ export default {
|
||||
while (slen--) {
|
||||
const elem = selElems[slen];
|
||||
// Look for selected connector elements
|
||||
if (elem && elData(elem, 'c_start')) {
|
||||
if (elem && dataStorage.get(elem, 'c_start')) {
|
||||
// Remove the "translate" transform given to move
|
||||
svgCanvas.removeFromSelection([elem]);
|
||||
svgCanvas.getTransformList(elem).clear();
|
||||
@@ -467,10 +465,10 @@ export default {
|
||||
if (svgCanvas.getMode() !== 'connector') {
|
||||
return undefined;
|
||||
}
|
||||
const fo = $(mouseTarget).closest('foreignObject');
|
||||
const fo = svgCanvas.getClosest(mouseTarget.parentNode, 'foreignObject');
|
||||
if (fo.length) { mouseTarget = fo[0]; }
|
||||
|
||||
const parents = $(mouseTarget).parents();
|
||||
const parents = svgCanvas.getParents(mouseTarget.parentNode);
|
||||
|
||||
if (mouseTarget === startElem) {
|
||||
// Start line through click
|
||||
@@ -481,9 +479,9 @@ export default {
|
||||
started
|
||||
};
|
||||
}
|
||||
if ($.inArray(svgcontent, parents) === -1) {
|
||||
if (parents.indexOf(svgcontent) === -1) {
|
||||
// Not a valid target element, so remove line
|
||||
$(curLine).remove();
|
||||
curLine.remove();
|
||||
started = false;
|
||||
return {
|
||||
keep: false,
|
||||
@@ -498,13 +496,13 @@ export default {
|
||||
const connStr = startId + ' ' + endId;
|
||||
const altStr = endId + ' ' + startId;
|
||||
// Don't create connector if one already exists
|
||||
const dupe = $(svgcontent).find('.se_connector').filter(function () {
|
||||
const conn = this.getAttributeNS(seNs, 'connector');
|
||||
const dupe = Array.prototype.filter.call(svgcontent.querySelectorAll('.se_connector'), function (aThis, i) {
|
||||
const conn = aThis.getAttributeNS(seNs, 'connector');
|
||||
if (conn === connStr || conn === altStr) { return true; }
|
||||
return false;
|
||||
});
|
||||
if (dupe.length) {
|
||||
$(curLine).remove();
|
||||
curLine.remove();
|
||||
return {
|
||||
keep: false,
|
||||
element: null,
|
||||
@@ -516,10 +514,9 @@ export default {
|
||||
|
||||
const 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);
|
||||
dataStorage.put(curLine, 'c_start', startId);
|
||||
dataStorage.put(curLine, 'c_end', endId);
|
||||
dataStorage.put(curLine, 'end_bb', bb);
|
||||
seNs = svgCanvas.getEditorNS(true);
|
||||
curLine.setAttributeNS(seNs, 'se:connector', connStr);
|
||||
curLine.setAttribute('class', 'se_connector');
|
||||
@@ -536,7 +533,7 @@ export default {
|
||||
},
|
||||
selectedChanged (opts) {
|
||||
// TODO: Find better way to skip operations if no connectors are in use
|
||||
if (!$(svgcontent).find('.se_connector').length) { return; }
|
||||
if (!svgcontent.querySelectorAll('.se_connector').length) { return; }
|
||||
|
||||
if (svgCanvas.getMode() === 'connector') {
|
||||
svgCanvas.setMode('select');
|
||||
@@ -548,7 +545,7 @@ export default {
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
const elem = selElems[i];
|
||||
if (elem && elData(elem, 'c_start')) {
|
||||
if (elem && dataStorage.get(elem, 'c_start')) {
|
||||
selManager.requestSelector(elem).showGrips(false);
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
// TODO: Set up context tools and hide most regular line tools
|
||||
@@ -581,9 +578,8 @@ export default {
|
||||
const mid = elem.getAttribute('marker-mid');
|
||||
const end = elem.getAttribute('marker-end');
|
||||
curLine = elem;
|
||||
$(elem)
|
||||
.data('start_off', Boolean(start))
|
||||
.data('end_off', Boolean(end));
|
||||
dataStorage.put(elem, 'start_off', Boolean(start));
|
||||
dataStorage.put(elem, 'end_off', Boolean(end));
|
||||
|
||||
if (elem.tagName === 'line' && mid) {
|
||||
// Convert to polyline to accept mid-arrow
|
||||
@@ -606,7 +602,8 @@ export default {
|
||||
opacity: elem.getAttribute('opacity') || 1
|
||||
}
|
||||
});
|
||||
$(elem).after(pline).remove();
|
||||
elem.insertAdjacentElement('afterend', pline);
|
||||
elem.remove();
|
||||
svgCanvas.clearSelection();
|
||||
pline.id = id;
|
||||
svgCanvas.addToSelection([pline]);
|
||||
@@ -615,7 +612,7 @@ export default {
|
||||
}
|
||||
// Update line if it's a connector
|
||||
if (elem.getAttribute('class') === 'se_connector') {
|
||||
const start = getElem(elData(elem, 'c_start'));
|
||||
const start = getElem(dataStorage.get(elem, 'c_start'));
|
||||
updateConnectors([start]);
|
||||
} else {
|
||||
updateConnectors();
|
||||
|
||||
@@ -44,12 +44,14 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
let fcRules = $id('fc_rules');
|
||||
if (!fcRules) {
|
||||
fcRules = document.createElement('style');
|
||||
fcRules.setAttribute('id', 'fc_rules');
|
||||
document.getElementsByTagName("head")[0].appendChild(fcRules);
|
||||
}
|
||||
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
|
||||
$('#foreignObject_panel').toggle(on);
|
||||
fcRules.textContent = !on ? '' : ' #tool_topath { display: none !important; }';
|
||||
$id('foreignObject_panel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +59,10 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function toggleSourceButtons (on) {
|
||||
$('#tool_source_save, #tool_source_cancel').toggle(!on);
|
||||
$('#foreign_save, #foreign_cancel').toggle(on);
|
||||
$id('tool_source_save').style.display = (!on) ? 'block' : 'none';
|
||||
$id('tool_source_cancel').style.display = (!on) ? 'block' : 'none';
|
||||
$id('foreign_save').style.display = (on) ? 'block' : 'none';
|
||||
$id('foreign_cancel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
let selElems,
|
||||
@@ -75,7 +79,8 @@ export default {
|
||||
const elt = selElems[0]; // The parent `Element` to append to
|
||||
try {
|
||||
// convert string into XML document
|
||||
const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
|
||||
const oi = (xmlString.indexOf('xmlns:oi') !== -1) ? ' xmlns:oi="' + NS.OI + '"' : '';
|
||||
const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '" '+ oi +'>' + xmlString + '</svg>');
|
||||
// run it through our sanitizer to remove anything we do not support
|
||||
svgCanvas.sanitizeSvg(newDoc.documentElement);
|
||||
elt.replaceWith(svgdoc.importNode(newDoc.documentElement.firstChild, true));
|
||||
@@ -102,10 +107,10 @@ export default {
|
||||
elt.removeAttribute('fill');
|
||||
|
||||
const str = svgCanvas.svgToString(elt, 0);
|
||||
$('#svg_source_textarea').val(str);
|
||||
$('#svg_source_editor').fadeIn();
|
||||
$id('svg_source_textarea').value = str;
|
||||
$id('#svg_source_editor').style.display = 'block';
|
||||
properlySourceSizeTextArea();
|
||||
$('#svg_source_textarea').focus();
|
||||
$id('svg_source_textarea').focus();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,33 +193,45 @@ export default {
|
||||
const endChanges = function () {
|
||||
$id("svg_source_editor").style.display = 'none';
|
||||
editingforeign = false;
|
||||
$('#svg_source_textarea').blur();
|
||||
$id('svg_source_textarea').blur();
|
||||
toggleSourceButtons(false);
|
||||
};
|
||||
|
||||
// TODO: Needs to be done after orig icon loads
|
||||
setTimeout(function () {
|
||||
// Create source save/cancel buttons
|
||||
/* const save = */ $('#tool_source_save').clone()
|
||||
.hide().attr('id', 'foreign_save').unbind()
|
||||
.appendTo('#tool_source_back').click(function () {
|
||||
if (!editingforeign) { return; }
|
||||
const toolSourceSave = $id('tool_source_save').cloneNode(true);
|
||||
toolSourceSave.style.display = 'none';
|
||||
toolSourceSave.id = 'foreign_save';
|
||||
// unbind()
|
||||
// const oldElement = $id('tool_source_save');
|
||||
// oldElement.parentNode.replaceChild(toolSourceSave, oldElement);
|
||||
$id('tool_source_back').append(toolSourceSave);
|
||||
toolSourceSave.addEventListener('click', (e) => function () {
|
||||
if (!editingforeign) { return; }
|
||||
|
||||
if (!setForeignString($('#svg_source_textarea').val())) {
|
||||
const ok = seConfirm('Errors found. Revert to original?');
|
||||
if (!ok) { return; }
|
||||
endChanges();
|
||||
} else {
|
||||
endChanges();
|
||||
}
|
||||
// setSelectMode();
|
||||
});
|
||||
|
||||
/* const cancel = */ $('#tool_source_cancel').clone()
|
||||
.hide().attr('id', 'foreign_cancel').unbind()
|
||||
.appendTo('#tool_source_back').click(function () {
|
||||
if (!setForeignString($id('svg_source_textarea').value)) {
|
||||
const ok = seConfirm('Errors found. Revert to original?');
|
||||
if (!ok) { return; }
|
||||
endChanges();
|
||||
});
|
||||
} else {
|
||||
endChanges();
|
||||
}
|
||||
// setSelectMode();
|
||||
});
|
||||
|
||||
var oldToolSourceCancel = $id('tool_source_cancel');
|
||||
const toolSourceCancel = oldToolSourceCancel.cloneNode(true);
|
||||
toolSourceCancel.style.display = 'none';
|
||||
toolSourceCancel.id = 'foreign_cancel';
|
||||
$id('tool_source_back').append(toolSourceCancel);
|
||||
toolSourceCancel.addEventListener('click', (e) => function () {
|
||||
endChanges();
|
||||
});
|
||||
// unbind()
|
||||
// var oldToolSourceCancel = $id('tool_source_cancel');
|
||||
// oldToolSourceCancel.parentNode.replaceChild(toolSourceCancel, oldToolSourceCancel);
|
||||
|
||||
}, 3000);
|
||||
},
|
||||
mouseDown (opts) {
|
||||
@@ -256,7 +273,10 @@ export default {
|
||||
if (svgCanvas.getMode() !== 'foreign' || !started) {
|
||||
return undefined;
|
||||
}
|
||||
const attrs = $(newFO).attr(['width', 'height']);
|
||||
const attrs = {
|
||||
width: newFO.getAttribute('width'),
|
||||
height: newFO.getAttribute('height'),
|
||||
}
|
||||
const keep = (attrs.width !== '0' || attrs.height !== '0');
|
||||
svgCanvas.addToSelection([newFO], true);
|
||||
|
||||
@@ -274,9 +294,9 @@ export default {
|
||||
const 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'));
|
||||
$id('foreign_font_size').value = elem.getAttribute('font-size');
|
||||
$id('foreign_width').value = elem.getAttribute('width');
|
||||
$id('foreign_height').value = elem.getAttribute('height');
|
||||
showPanel(true);
|
||||
} else {
|
||||
showPanel(false);
|
||||
|
||||
@@ -25,15 +25,17 @@ export default {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
||||
{assignAttributes} = svgCanvas,
|
||||
hcanvas = document.createElement('canvas'),
|
||||
canvBG = $('#canvasBackground'),
|
||||
units = getTypeMap(), // Assumes prior `init()` call on `units.js` module
|
||||
intervals = [0.01, 0.1, 1, 10, 100, 1000];
|
||||
const {$id} = svgCanvas;
|
||||
const svgdoc = document.getElementById('svgcanvas').ownerDocument;
|
||||
const {assignAttributes} = svgCanvas;
|
||||
const hcanvas = document.createElement('canvas');
|
||||
const canvBG = $id('canvasBackground');
|
||||
const units = getTypeMap(); // Assumes prior `init()` call on `units.js` module
|
||||
const intervals = [0.01, 0.1, 1, 10, 100, 1000];
|
||||
let showGrid = svgEditor.configObj.curConfig.showGrid || false;
|
||||
|
||||
$(hcanvas).hide().appendTo('body');
|
||||
hcanvas.style.display = 'none';
|
||||
document.body.appendChild(hcanvas);
|
||||
|
||||
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
|
||||
assignAttributes(canvasGrid, {
|
||||
@@ -45,7 +47,7 @@ export default {
|
||||
overflow: 'visible',
|
||||
display: 'none'
|
||||
});
|
||||
canvBG.append(canvasGrid);
|
||||
canvBG.appendChild(canvasGrid);
|
||||
const gridDefs = svgdoc.createElementNS(NS.SVG, 'defs');
|
||||
// grid-pattern
|
||||
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
|
||||
@@ -67,7 +69,7 @@ export default {
|
||||
});
|
||||
gridPattern.append(gridimg);
|
||||
gridDefs.append(gridPattern);
|
||||
$('#canvasGrid').append(gridDefs);
|
||||
$id('canvasGrid').appendChild(gridDefs);
|
||||
|
||||
// grid-box
|
||||
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
|
||||
@@ -81,14 +83,14 @@ export default {
|
||||
fill: 'url(#gridpattern)',
|
||||
style: 'pointer-events: none; display:visible;'
|
||||
});
|
||||
$('#canvasGrid').append(gridBox);
|
||||
$id('canvasGrid').appendChild(gridBox);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Float} zoom
|
||||
* @returns {void}
|
||||
*/
|
||||
function updateGrid (zoom) {
|
||||
const updateGrid = (zoom) => {
|
||||
// TODO: Try this with <line> elements, then compare performance difference
|
||||
const unit = units[svgEditor.configObj.curConfig.baseUnit]; // 1 = 1px
|
||||
const uMulti = unit * zoom;
|
||||
@@ -141,11 +143,11 @@ export default {
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function gridUpdate () {
|
||||
const gridUpdate = () => {
|
||||
if (showGrid) {
|
||||
updateGrid(svgCanvas.getZoom());
|
||||
}
|
||||
$('#canvasGrid').toggle(showGrid);
|
||||
$id('canvasGrid').style.display = (showGrid) ? 'block' : 'none';
|
||||
document.getElementById('view_grid').pressed = showGrid;
|
||||
}
|
||||
return {
|
||||
@@ -154,15 +156,19 @@ export default {
|
||||
if (showGrid) { updateGrid(zoom); }
|
||||
},
|
||||
callback () {
|
||||
if (showGrid) {
|
||||
gridUpdate();
|
||||
}
|
||||
},
|
||||
events: {
|
||||
id: 'view_grid',
|
||||
click () {
|
||||
// Add the button and its handler(s)
|
||||
const buttonTemplate = document.createElement("template");
|
||||
buttonTemplate.innerHTML = `
|
||||
<se-button id="view_grid" title="Show grid" src="./images/grid.svg"></se-button>
|
||||
`
|
||||
$id('editor_panel').append(buttonTemplate.content.cloneNode(true));
|
||||
$id('view_grid').addEventListener("click", () => {
|
||||
svgEditor.configObj.curConfig.showGrid = showGrid = !showGrid;
|
||||
gridUpdate();
|
||||
});
|
||||
|
||||
if (showGrid) {
|
||||
gridUpdate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-unsanitized/property */
|
||||
/* globals seConfirm */
|
||||
/**
|
||||
* @file ext-imagelib.js
|
||||
@@ -188,8 +189,10 @@ export default {
|
||||
await seConfirm(message);
|
||||
transferStopped = true;
|
||||
} else {
|
||||
entry = $('<div>').text(message).data('id', curMeta.id);
|
||||
preview.append(entry);
|
||||
entry = document.createElement('div');
|
||||
entry.textContent = message;
|
||||
entry.dataset.id = curMeta.id;
|
||||
preview.appendChild(entry);
|
||||
curMeta.entry = entry;
|
||||
}
|
||||
|
||||
@@ -256,51 +259,54 @@ export default {
|
||||
// Try to find a title
|
||||
// `dropXMLInternalSubset` is to help prevent the billion laughs attack
|
||||
const xml = new DOMParser().parseFromString(dropXMLInternalSubset(response), 'text/xml').documentElement; // lgtm [js/xml-bomb]
|
||||
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
|
||||
title = xml.querySelector('title').textContent || '(SVG #' + response.length + ')';
|
||||
}
|
||||
if (curMeta) {
|
||||
$(preview).children().each(function () {
|
||||
if ($(this).data('id') === id) {
|
||||
Array.from(preview.children).forEach(function(element) {
|
||||
if (element.dataset.id === id) {
|
||||
if (curMeta.preview_url) {
|
||||
$(this).html(
|
||||
$('<span>').append(
|
||||
$('<img>').attr('src', curMeta.preview_url),
|
||||
title
|
||||
)
|
||||
);
|
||||
const img = document.createElement("img");
|
||||
img.src = curMeta.preview_url;
|
||||
const span = document.createElement("span");
|
||||
span.appendChild(img);
|
||||
element.append(span);
|
||||
} else {
|
||||
$(this).text(title);
|
||||
element.textContent = title;
|
||||
}
|
||||
submit.removeAttr('disabled');
|
||||
submit.removeAttribute('disabled');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
preview.append(
|
||||
$('<div>').text(title)
|
||||
);
|
||||
submit.removeAttr('disabled');
|
||||
const div = document.createElement("div");
|
||||
div.textContent = title;
|
||||
preview.appendChild(div);
|
||||
submit.removeAttribute('disabled');
|
||||
}
|
||||
} else {
|
||||
if (curMeta && curMeta.preview_url) {
|
||||
title = curMeta.name || '';
|
||||
entry = $('<span>').append(
|
||||
$('<img>').attr('src', curMeta.preview_url),
|
||||
title
|
||||
);
|
||||
entry = document.createElement('span');
|
||||
const img = document.createElement("img");
|
||||
img.src = curMeta.preview_url;
|
||||
entry.appendChild(img);
|
||||
entry.appendChild(document.createTextNode(title))
|
||||
} else {
|
||||
entry = $('<img>').attr('src', response);
|
||||
entry = document.createElement("img");
|
||||
entry.src = response;
|
||||
}
|
||||
|
||||
if (curMeta) {
|
||||
preview.children().each(function () {
|
||||
if ($(this).data('id') === id) {
|
||||
$(this).html(entry);
|
||||
submit.removeAttr('disabled');
|
||||
Array.from(preview.children).forEach(function(element) {
|
||||
if (element.dataset.id === id) {
|
||||
element.appendChild(entry);
|
||||
submit.removeAttribute('disabled');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
preview.append($('<div>').append(entry));
|
||||
submit.removeAttr('disabled');
|
||||
const div = document.createElement("div");
|
||||
div.appendChild(entry);
|
||||
preview.appendChild(div);
|
||||
submit.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -325,6 +331,23 @@ export default {
|
||||
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
|
||||
}
|
||||
|
||||
function toggleMultiLoop() {
|
||||
$.each(multiArr, function (i) {
|
||||
const type = this[0];
|
||||
const data = this[1];
|
||||
if (type === 'svg') {
|
||||
svgCanvas.importSvgString(data);
|
||||
} else {
|
||||
importImage(data);
|
||||
}
|
||||
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
|
||||
});
|
||||
while(preview.firstChild)
|
||||
preview.removeChild(preview.firstChild);
|
||||
multiArr = [];
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} show
|
||||
* @returns {void}
|
||||
@@ -339,56 +362,18 @@ export default {
|
||||
preview.setAttribute('style', `position: absolute;top: 45px;right: 10px;width: 180px;bottom: 45px;background: #fff;overflow: auto;`);
|
||||
insertAfter($id('lib_framewrap'), preview);
|
||||
|
||||
/* submit = document.createElement('button');
|
||||
submit = document.createElement('button');
|
||||
submit.setAttribute('content', 'Import selected');
|
||||
submit.setAttribute('disabled', true);
|
||||
submit.textContent = 'Import selected';
|
||||
submit.setAttribute('style', `position: absolute;bottom: 10px;right: -10px;`);
|
||||
$id('imgbrowse').appendChild(submit);
|
||||
submit.addEventListener('click', function () {
|
||||
$.each(multiArr, function (i) {
|
||||
const type = this[0];
|
||||
const data = this[1];
|
||||
if (type === 'svg') {
|
||||
svgCanvas.importSvgString(data);
|
||||
} else {
|
||||
importImage(data);
|
||||
}
|
||||
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
|
||||
});
|
||||
$(preview).empty();
|
||||
multiArr = [];
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
})
|
||||
submit.style.display = (show) ? 'block' : 'none';
|
||||
*/
|
||||
|
||||
|
||||
submit = $('<button disabled>Import selected</button>')
|
||||
.appendTo('#imgbrowse')
|
||||
.on('click touchend', function () {
|
||||
$.each(multiArr, function (i) {
|
||||
const type = this[0];
|
||||
const data = this[1];
|
||||
if (type === 'svg') {
|
||||
svgCanvas.importSvgString(data);
|
||||
} else {
|
||||
importImage(data);
|
||||
}
|
||||
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
|
||||
});
|
||||
$(preview).empty();
|
||||
multiArr = [];
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
}).css({
|
||||
position: 'absolute',
|
||||
bottom: 10,
|
||||
right: -10
|
||||
});
|
||||
submit.addEventListener('click', toggleMultiLoop);
|
||||
submit.addEventListener('touchend', toggleMultiLoop);
|
||||
}
|
||||
|
||||
submit.style.display = (show) ? 'block' : 'none';
|
||||
preview.style.display = (show) ? 'block' : 'none';
|
||||
submit.toggle(show);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,52 +381,79 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showBrowser () {
|
||||
let browser = $('#imgbrowse');
|
||||
if (!browser.length) {
|
||||
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
|
||||
'</div></div>').insertAfter('#svg_editor');
|
||||
browser = $('#imgbrowse');
|
||||
let browser = $id('imgbrowse');
|
||||
if (!browser) {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'imgbrowse_holder';
|
||||
div.innerHTML = '<div id=imgbrowse class=toolbar_button></div>';
|
||||
insertAfter($id('svg_editor'), div);
|
||||
browser = $id('imgbrowse');
|
||||
|
||||
const allLibs = imagelibStrings.select_lib;
|
||||
|
||||
const libOpts = $('<ul id=imglib_opts>').appendTo(browser);
|
||||
const frame = $('<iframe src="javascript:0"/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
|
||||
const divFrameWrap = document.createElement('div');
|
||||
divFrameWrap.id = 'lib_framewrap';
|
||||
|
||||
const header = $('<h1>').prependTo(browser).text(allLibs).css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%'
|
||||
const libOpts = document.createElement('ul');
|
||||
libOpts.id = 'imglib_opts';
|
||||
browser.append(libOpts);
|
||||
const frame = document.createElement('iframe');
|
||||
frame.src = "javascript:0";
|
||||
frame.style.display = 'none';
|
||||
divFrameWrap.append(frame);
|
||||
browser.prepend(divFrameWrap);
|
||||
|
||||
const header = document.createElement('h1');
|
||||
browser.prepend(header);
|
||||
header.textContent = allLibs;
|
||||
header.setAttribute('style', `position: absolute;top: 0;left: 0;width: 100%;`);
|
||||
|
||||
const button = document.createElement('button');
|
||||
// eslint-disable-next-line max-len
|
||||
button.innerHTML = '<img class="svg_icon" src="./images/cancel.svg" alt="icon" width="16" height="16" />' + uiStrings.common.cancel ;
|
||||
browser.appendChild(button);
|
||||
button.addEventListener('click', function () {
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
});
|
||||
button.addEventListener('touchend', function () {
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
});
|
||||
button.setAttribute('style', `position: absolute;top: 5;right: -10;`);
|
||||
|
||||
const leftBlock = document.createElement('span');
|
||||
leftBlock.setAttribute('style', `position: absolute;top: 5;left: 10;`);
|
||||
browser.appendChild(leftBlock);
|
||||
|
||||
const back = document.createElement('button');
|
||||
back.style.visibility = "hidden";
|
||||
// eslint-disable-next-line max-len
|
||||
$('<button><img class="svg_icon" src="./images/cancel.svg" alt="icon" width="16" height="16" />' + uiStrings.common.cancel + '</button>')
|
||||
.appendTo(browser)
|
||||
.on('click touchend', function () {
|
||||
$id("imgbrowse_holder").style.display = 'none';
|
||||
}).css({
|
||||
position: 'absolute',
|
||||
top: 5,
|
||||
right: -10
|
||||
});
|
||||
back.innerHTML = '<img class="svg_icon" src="./images/library.svg" alt="icon" width="16" height="16" />' + imagelibStrings.show_list;
|
||||
leftBlock.appendChild(back);
|
||||
back.addEventListener('click', function () {
|
||||
frame.setAttribute('src', 'about:blank');
|
||||
frame.style.display = 'none';
|
||||
libOpts.style.display = 'block';
|
||||
header.textContent = allLibs;
|
||||
back.style.display = 'none';
|
||||
});
|
||||
back.addEventListener('touchend', function () {
|
||||
frame.setAttribute('src', 'about:blank');
|
||||
frame.style.display = 'none';
|
||||
libOpts.style.display = 'block';
|
||||
header.textContent = allLibs;
|
||||
back.style.display = 'none';
|
||||
});
|
||||
back.setAttribute('style', `margin-right: 5px;`);
|
||||
back.style.display = 'none';
|
||||
|
||||
const leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
|
||||
// eslint-disable-next-line max-len
|
||||
const back = $('<button hidden><img class="svg_icon" src="./images/library.svg" alt="icon" width="16" height="16" />' + imagelibStrings.show_list + '</button>')
|
||||
.appendTo(leftBlock)
|
||||
.on('click touchend', function () {
|
||||
frame.attr('src', 'about:blank').hide();
|
||||
libOpts.show();
|
||||
header.text(allLibs);
|
||||
back.hide();
|
||||
}).css({
|
||||
'margin-right': 5
|
||||
}).hide();
|
||||
|
||||
/* const type = */ $('<select><option value=s>' +
|
||||
imagelibStrings.import_single + '</option><option value=m>' +
|
||||
imagelibStrings.import_multi + '</option><option value=o>' +
|
||||
imagelibStrings.open + '</option></select>').appendTo(leftBlock).change(function () {
|
||||
mode = $(this).val();
|
||||
const select = document.createElement('select');
|
||||
select.innerHTML = '<select><option value=s>' +
|
||||
imagelibStrings.import_single + '</option><option value=m>' +
|
||||
imagelibStrings.import_multi + '</option><option value=o>' +
|
||||
imagelibStrings.open + '</option>';
|
||||
leftBlock.appendChild(select);
|
||||
select.addEventListener('change', function () {
|
||||
mode = this.value;
|
||||
switch (mode) {
|
||||
case 's':
|
||||
case 'o':
|
||||
@@ -453,23 +465,30 @@ export default {
|
||||
toggleMulti(true);
|
||||
break;
|
||||
}
|
||||
}).css({
|
||||
'margin-top': 10
|
||||
});
|
||||
select.setAttribute('style', `margin-top: 10px;`);
|
||||
|
||||
imagelibStrings.imgLibs.forEach(function ({name, url, description}) {
|
||||
$('<li>')
|
||||
.appendTo(libOpts)
|
||||
.text(name)
|
||||
.on('click touchend', function () {
|
||||
frame.attr(
|
||||
'src',
|
||||
url
|
||||
).show();
|
||||
header.text(name);
|
||||
libOpts.hide();
|
||||
back.show();
|
||||
}).append(`<span>${description}</span>`);
|
||||
const li = document.createElement('li');
|
||||
libOpts.appendChild(li);
|
||||
li.textContent = name;
|
||||
li.addEventListener('click', function () {
|
||||
frame.setAttribute('src', url);
|
||||
frame.style.display = 'block';
|
||||
header.textContent = name;
|
||||
libOpts.style.display = 'none';
|
||||
back.style.display = 'block';
|
||||
});
|
||||
li.addEventListener('touchend', function () {
|
||||
frame.setAttribute('src', url);
|
||||
frame.style.display = 'block';
|
||||
header.textContent = name;
|
||||
libOpts.style.display = 'none';
|
||||
back.style.display = 'block';
|
||||
});
|
||||
var span = document.createElement("span");
|
||||
span.textContent = description;
|
||||
li.appendChild(span);
|
||||
});
|
||||
} else {
|
||||
$id("imgbrowse_holder").style.display = 'block';
|
||||
@@ -487,81 +506,81 @@ export default {
|
||||
svgicons: 'ext-imagelib.xml',
|
||||
events,
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#imgbrowse_holder {' +
|
||||
'position: absolute;' +
|
||||
'top: 0;' +
|
||||
'left: 0;' +
|
||||
'width: 100%;' +
|
||||
'height: 100%;' +
|
||||
'background-color: rgba(0, 0, 0, .5);' +
|
||||
'z-index: 5;' +
|
||||
'}' +
|
||||
'#imgbrowse {' +
|
||||
'position: absolute;' +
|
||||
'top: 25px;' +
|
||||
'left: 25px;' +
|
||||
'right: 25px;' +
|
||||
'bottom: 25px;' +
|
||||
'min-width: 300px;' +
|
||||
'min-height: 200px;' +
|
||||
'background: #B0B0B0;' +
|
||||
'border: 1px outset #777;' +
|
||||
'}' +
|
||||
'#imgbrowse h1 {' +
|
||||
'font-size: 20px;' +
|
||||
'margin: .4em;' +
|
||||
'text-align: center;' +
|
||||
'}' +
|
||||
'#lib_framewrap,' +
|
||||
'#imgbrowse > ul {' +
|
||||
'position: absolute;' +
|
||||
'top: 45px;' +
|
||||
'left: 10px;' +
|
||||
'right: 10px;' +
|
||||
'bottom: 10px;' +
|
||||
'background: white;' +
|
||||
'margin: 0;' +
|
||||
'padding: 0;' +
|
||||
'}' +
|
||||
'#imgbrowse > ul {' +
|
||||
'overflow: auto;' +
|
||||
'}' +
|
||||
'#imgbrowse > div {' +
|
||||
'border: 1px solid #666;' +
|
||||
'}' +
|
||||
'#imglib_preview > div {' +
|
||||
'padding: 5px;' +
|
||||
'font-size: 12px;' +
|
||||
'}' +
|
||||
'#imglib_preview img {' +
|
||||
'display: block;' +
|
||||
'margin: 0 auto;' +
|
||||
'max-height: 100px;' +
|
||||
'}' +
|
||||
'#imgbrowse li {' +
|
||||
'list-style: none;' +
|
||||
'padding: .5em;' +
|
||||
'background: #E8E8E8;' +
|
||||
'border-bottom: 1px solid #B0B0B0;' +
|
||||
'line-height: 1.2em;' +
|
||||
'font-style: sans-serif;' +
|
||||
'}' +
|
||||
'#imgbrowse li > span {' +
|
||||
'color: #666;' +
|
||||
'font-size: 15px;' +
|
||||
'display: block;' +
|
||||
'}' +
|
||||
'#imgbrowse li:hover {' +
|
||||
'background: #FFC;' +
|
||||
'cursor: pointer;' +
|
||||
'}' +
|
||||
'#imgbrowse iframe {' +
|
||||
'width: 100%;' +
|
||||
'height: 100%;' +
|
||||
'border: 0;' +
|
||||
'}'
|
||||
).appendTo('head');
|
||||
const style = document.createElement('style');
|
||||
style.textContent = '#imgbrowse_holder {' +
|
||||
'position: absolute;' +
|
||||
'top: 0;' +
|
||||
'left: 0;' +
|
||||
'width: 100%;' +
|
||||
'height: 100%;' +
|
||||
'background-color: rgba(0, 0, 0, .5);' +
|
||||
'z-index: 5;' +
|
||||
'}' +
|
||||
'#imgbrowse {' +
|
||||
'position: absolute;' +
|
||||
'top: 25px;' +
|
||||
'left: 25px;' +
|
||||
'right: 25px;' +
|
||||
'bottom: 25px;' +
|
||||
'min-width: 300px;' +
|
||||
'min-height: 200px;' +
|
||||
'background: #B0B0B0;' +
|
||||
'border: 1px outset #777;' +
|
||||
'}' +
|
||||
'#imgbrowse h1 {' +
|
||||
'font-size: 20px;' +
|
||||
'margin: .4em;' +
|
||||
'text-align: center;' +
|
||||
'}' +
|
||||
'#lib_framewrap,' +
|
||||
'#imgbrowse > ul {' +
|
||||
'position: absolute;' +
|
||||
'top: 45px;' +
|
||||
'left: 10px;' +
|
||||
'right: 10px;' +
|
||||
'bottom: 10px;' +
|
||||
'background: white;' +
|
||||
'margin: 0;' +
|
||||
'padding: 0;' +
|
||||
'}' +
|
||||
'#imgbrowse > ul {' +
|
||||
'overflow: auto;' +
|
||||
'}' +
|
||||
'#imgbrowse > div {' +
|
||||
'border: 1px solid #666;' +
|
||||
'}' +
|
||||
'#imglib_preview > div {' +
|
||||
'padding: 5px;' +
|
||||
'font-size: 12px;' +
|
||||
'}' +
|
||||
'#imglib_preview img {' +
|
||||
'display: block;' +
|
||||
'margin: 0 auto;' +
|
||||
'max-height: 100px;' +
|
||||
'}' +
|
||||
'#imgbrowse li {' +
|
||||
'list-style: none;' +
|
||||
'padding: .5em;' +
|
||||
'background: #E8E8E8;' +
|
||||
'border-bottom: 1px solid #B0B0B0;' +
|
||||
'line-height: 1.2em;' +
|
||||
'font-style: sans-serif;' +
|
||||
'}' +
|
||||
'#imgbrowse li > span {' +
|
||||
'color: #666;' +
|
||||
'font-size: 15px;' +
|
||||
'display: block;' +
|
||||
'}' +
|
||||
'#imgbrowse li:hover {' +
|
||||
'background: #FFC;' +
|
||||
'cursor: pointer;' +
|
||||
'}' +
|
||||
'#imgbrowse iframe {' +
|
||||
'width: 100%;' +
|
||||
'height: 100%;' +
|
||||
'border: 0;' +
|
||||
'}';
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,49 +1,52 @@
|
||||
/* globals jQuery */
|
||||
const $ = jQuery;
|
||||
$('a').click(function () {
|
||||
const {href} = this;
|
||||
const target = window.parent;
|
||||
const post = (message) => {
|
||||
// Todo: Make origin customizable as set by opening window
|
||||
// Todo: If dropping IE9, avoid stringifying
|
||||
target.postMessage(JSON.stringify({
|
||||
namespace: 'imagelib',
|
||||
...message
|
||||
}), '*');
|
||||
};
|
||||
// Convert Non-SVG images to data URL first
|
||||
// (this could also have been done server-side by the library)
|
||||
// Send metadata (also indicates file is about to be sent)
|
||||
post({
|
||||
name: $(this).text(),
|
||||
id: href
|
||||
});
|
||||
if (!href.includes('.svg')) {
|
||||
const img = new Image();
|
||||
img.addEventListener('load', function () {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = this.width;
|
||||
canvas.height = this.height;
|
||||
// load the raster image into the canvas
|
||||
canvas.getContext('2d').drawImage(this, 0, 0);
|
||||
// retrieve the data: URL
|
||||
let data;
|
||||
try {
|
||||
data = canvas.toDataURL();
|
||||
} catch (err) {
|
||||
// This fails in Firefox with `file:///` URLs :(
|
||||
// Todo: This could use a generic alert library instead
|
||||
alert('Data URL conversion failed: ' + err);
|
||||
data = '';
|
||||
}
|
||||
post({href, data});
|
||||
const atags = document.querySelectorAll('a');
|
||||
Array.prototype.forEach.call(atags, function (aEle, i) {
|
||||
aEle.addEventListener('click', function (event) {
|
||||
const { href } = event.currentTarget;
|
||||
const target = window.parent;
|
||||
const post = (message) => {
|
||||
// Todo: Make origin customizable as set by opening window
|
||||
// Todo: If dropping IE9, avoid stringifying
|
||||
target.postMessage(JSON.stringify({
|
||||
namespace: 'imagelib',
|
||||
...message
|
||||
}), '*');
|
||||
};
|
||||
// Convert Non-SVG images to data URL first
|
||||
// (this could also have been done server-side by the library)
|
||||
// Send metadata (also indicates file is about to be sent)
|
||||
post({
|
||||
name: event.currentTarget.textContent,
|
||||
id: href
|
||||
});
|
||||
img.src = href;
|
||||
} else {
|
||||
// Do ajax request for image's href value
|
||||
$.get(href, function (data) {
|
||||
post({href, data});
|
||||
}, 'html'); // 'html' is necessary to keep returned data as a string
|
||||
}
|
||||
return false;
|
||||
if (!href.includes('.svg')) {
|
||||
const img = new Image();
|
||||
img.addEventListener('load', function () {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = this.width;
|
||||
canvas.height = this.height;
|
||||
// load the raster image into the canvas
|
||||
canvas.getContext('2d').drawImage(this, 0, 0);
|
||||
// retrieve the data: URL
|
||||
let data;
|
||||
try {
|
||||
data = canvas.toDataURL();
|
||||
} catch (err) {
|
||||
// This fails in Firefox with `file:///` URLs :(
|
||||
// Todo: This could use a generic alert library instead
|
||||
alert('Data URL conversion failed: ' + err);
|
||||
data = '';
|
||||
}
|
||||
post({ href, data });
|
||||
});
|
||||
img.src = href;
|
||||
} else {
|
||||
// Do ajax request for image's href value
|
||||
$.get(href, function (data) {
|
||||
post({ href, data });
|
||||
}, 'html'); // 'html' is necessary to keep returned data as a string
|
||||
}
|
||||
return false;
|
||||
})
|
||||
});
|
||||
|
||||
@@ -121,9 +121,17 @@ export default {
|
||||
*/
|
||||
function setIcon (pos, id) {
|
||||
if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; }
|
||||
const ci = '#' + idPrefix + pos + '_' + id.substr(1);
|
||||
svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
|
||||
$(ci).addClass('current').siblings().removeClass('current');
|
||||
const ci = idPrefix + pos + '_' + id.substr(1);
|
||||
console.log(ci)
|
||||
console.log('cur_' + pos + '_marker_list')
|
||||
svgEditor.setIcon('cur_' + pos + '_marker_list', $id(ci).children);
|
||||
$id(ci).classList.add('current');
|
||||
const siblings = Array.prototype.filter.call($id(ci).parentNode.children, function(child){
|
||||
return child !== $id(ci);
|
||||
});
|
||||
Array.from(siblings).forEach(function(sibling) {
|
||||
sibling.classList.remove('current');
|
||||
});
|
||||
}
|
||||
|
||||
let selElems;
|
||||
@@ -134,7 +142,7 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
$('#marker_panel').toggle(on);
|
||||
$id('marker_panel').style.display = (on) ? 'block' : 'none';
|
||||
|
||||
if (on) {
|
||||
const el = selElems[0];
|
||||
@@ -142,11 +150,11 @@ export default {
|
||||
let val, ci;
|
||||
$.each(mtypes, function (i, pos) {
|
||||
const m = getLinked(el, 'marker-' + pos);
|
||||
const txtbox = $('#' + pos + '_marker');
|
||||
const txtbox = $id(pos + '_marker');
|
||||
if (!m) {
|
||||
val = '\\nomarker';
|
||||
ci = val;
|
||||
txtbox.hide(); // hide text box
|
||||
txtbox.style.display = 'none';
|
||||
} else {
|
||||
if (!m.attributes.se_type) { return; } // not created by this extension
|
||||
val = '\\' + m.attributes.se_type.textContent;
|
||||
@@ -155,10 +163,10 @@ export default {
|
||||
val = m.lastChild.textContent;
|
||||
// txtbox.show(); // show text box
|
||||
} else {
|
||||
txtbox.hide(); // hide text box
|
||||
txtbox.style.display = 'none';
|
||||
}
|
||||
}
|
||||
txtbox.val(val);
|
||||
txtbox.value = val;
|
||||
setIcon(pos, ci);
|
||||
});
|
||||
}
|
||||
@@ -302,7 +310,8 @@ export default {
|
||||
batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode));
|
||||
batchCmd.addSubCommand(new S.InsertElementCommand(pline));
|
||||
|
||||
$(elem).after(pline).remove();
|
||||
elem.insertAdjacentElement('afterend', pline);
|
||||
elem.remove();
|
||||
svgCanvas.clearSelection();
|
||||
pline.id = id;
|
||||
svgCanvas.addToSelection([pline]);
|
||||
@@ -320,7 +329,7 @@ export default {
|
||||
const markerName = 'marker-' + pos;
|
||||
const el = selElems[0];
|
||||
const marker = getLinked(el, markerName);
|
||||
if (marker) { $(marker).remove(); }
|
||||
if (marker) { marker.remove(); }
|
||||
el.removeAttribute(markerName);
|
||||
let val = this.value;
|
||||
if (val === '') { val = '\\nomarker'; }
|
||||
@@ -379,7 +388,7 @@ export default {
|
||||
const len = el.id.length;
|
||||
const linkid = url.substr(-len - 1, len);
|
||||
if (el.id !== linkid) {
|
||||
const val = $('#' + pos + '_marker').attr('value');
|
||||
const val = $id(pos + '_marker').getAttribute('value');
|
||||
addMarker(id, val);
|
||||
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
|
||||
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
|
||||
@@ -396,11 +405,8 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function triggerTextEntry (pos, val) {
|
||||
$('#' + pos + '_marker').val(val);
|
||||
$('#' + pos + '_marker').change();
|
||||
// const txtbox = $('#'+pos+'_marker');
|
||||
// if (val.substr(0,1)=='\\') {txtbox.hide();}
|
||||
// else {txtbox.show();}
|
||||
$id(pos + '_marker').value = val;
|
||||
$id(pos + '_marker').change();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,7 +414,7 @@ export default {
|
||||
* @returns {void} Resolves to `undefined`
|
||||
*/
|
||||
function showTextPrompt (pos) {
|
||||
let def = $('#' + pos + '_marker').val();
|
||||
let def = $id(pos + '_marker').value;
|
||||
if (def.substr(0, 1) === '\\') { def = ''; }
|
||||
// eslint-disable-next-line no-alert
|
||||
const txt = prompt('Enter text for ' + pos + ' marker', def);
|
||||
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function saveMath () {
|
||||
const code = $('#mathjax_code_textarea').val();
|
||||
const code = $id('mathjax_code_textarea').value;
|
||||
// displaystyle to force MathJax NOT to use the inline style. Because it is
|
||||
// less fancy!
|
||||
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
|
||||
@@ -145,37 +145,30 @@ export default {
|
||||
// Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
|
||||
// From this point on it is very probable that it will be needed, so load it.
|
||||
if (mathjaxLoaded === false) {
|
||||
$(
|
||||
'<div id="mathjax">' +
|
||||
'<!-- Here is where MathJax creates the math -->' +
|
||||
'<div id="mathjax_creator" class="tex2jax_process" style="display:none">' +
|
||||
'$${}$$' +
|
||||
'</div>' +
|
||||
'<div id="mathjax_overlay"></div>' +
|
||||
'<div id="mathjax_container">' +
|
||||
'<div id="tool_mathjax_back" class="toolbar_button">' +
|
||||
'<button id="tool_mathjax_save">OK</button>' +
|
||||
'<button id="tool_mathjax_cancel">Cancel</button>' +
|
||||
'</div>' +
|
||||
'<fieldset>' +
|
||||
'<legend id="mathjax_legend">Mathematics Editor</legend>' +
|
||||
'<label>' +
|
||||
'<span id="mathjax_explication">Please type your mathematics in ' +
|
||||
'<a href="https://en.wikipedia.org/wiki/Help:' +
|
||||
'Displaying_a_formula" target="_blank">TeX</a> code.' +
|
||||
'</span></label>' +
|
||||
'<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>' +
|
||||
'</fieldset>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
).insertAfter('#svg_prefs').hide();
|
||||
// Make the MathEditor draggable.
|
||||
// TODO: unable to reach this place
|
||||
/* $('#mathjax_container').draggable({
|
||||
cancel: 'button,fieldset',
|
||||
containment: 'window'
|
||||
}); */
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.id = 'mathjax';
|
||||
div.innerHTML = '<!-- Here is where MathJax creates the math -->' +
|
||||
'<div id="mathjax_creator" class="tex2jax_process" style="display:none">' +
|
||||
'$${}$$' +
|
||||
'</div>' +
|
||||
'<div id="mathjax_overlay"></div>' +
|
||||
'<div id="mathjax_container">' +
|
||||
'<div id="tool_mathjax_back" class="toolbar_button">' +
|
||||
'<button id="tool_mathjax_save">OK</button>' +
|
||||
'<button id="tool_mathjax_cancel">Cancel</button>' +
|
||||
'</div>' +
|
||||
'<fieldset>' +
|
||||
'<legend id="mathjax_legend">Mathematics Editor</legend>' +
|
||||
'<label>' +
|
||||
'<span id="mathjax_explication">Please type your mathematics in ' +
|
||||
'<a href="https://en.wikipedia.org/wiki/Help:' +
|
||||
'Displaying_a_formula" target="_blank">TeX</a> code.' +
|
||||
'</span></label>' +
|
||||
'<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>' +
|
||||
'</fieldset>' +
|
||||
'</div>';
|
||||
$id('svg_prefs').parentNode.insertBefore(div, $id('svg_prefs').nextSibling);
|
||||
div.style.display = 'none';
|
||||
// Add functionality and picture to cancel button.
|
||||
$('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
|
||||
.on('click touched', function () {
|
||||
@@ -238,59 +231,57 @@ export default {
|
||||
return undefined;
|
||||
},
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#mathjax fieldset{' +
|
||||
'padding: 5px;' +
|
||||
'margin: 5px;' +
|
||||
'border: 1px solid #DDD;' +
|
||||
'}' +
|
||||
'#mathjax label{' +
|
||||
'display: block;' +
|
||||
'margin: .5em;' +
|
||||
'}' +
|
||||
'#mathjax legend {' +
|
||||
'max-width:195px;' +
|
||||
'}' +
|
||||
'#mathjax_overlay {' +
|
||||
'position: absolute;' +
|
||||
'top: 0;' +
|
||||
'left: 0;' +
|
||||
'right: 0;' +
|
||||
'bottom: 0;' +
|
||||
'background-color: black;' +
|
||||
'opacity: 0.6;' +
|
||||
'z-index: 20000;' +
|
||||
'}' +
|
||||
'#mathjax_container {' +
|
||||
'position: absolute;' +
|
||||
'top: 50px;' +
|
||||
'padding: 10px;' +
|
||||
'background-color: #B0B0B0;' +
|
||||
'border: 1px outset #777;' +
|
||||
'opacity: 1.0;' +
|
||||
'font-family: Verdana, Helvetica, sans-serif;' +
|
||||
'font-size: .8em;' +
|
||||
'z-index: 20001;' +
|
||||
'}' +
|
||||
'#tool_mathjax_back {' +
|
||||
'margin-left: 1em;' +
|
||||
'overflow: auto;' +
|
||||
'}' +
|
||||
'#mathjax_legend{' +
|
||||
'font-weight: bold;' +
|
||||
'font-size:1.1em;' +
|
||||
'}' +
|
||||
'#mathjax_code_textarea {\\n' +
|
||||
'margin: 5px .7em;' +
|
||||
'overflow: hidden;' +
|
||||
'width: 416px;' +
|
||||
'display: block;' +
|
||||
'height: 100px;' +
|
||||
'}'
|
||||
).appendTo('head');
|
||||
|
||||
// Add the MathJax configuration.
|
||||
// $(mathjaxConfiguration).appendTo('head');
|
||||
const head = document.head || document.getElementsByTagName('head')[0],
|
||||
style = document.createElement('style');
|
||||
style.textContent = '#mathjax fieldset{' +
|
||||
'padding: 5px;' +
|
||||
'margin: 5px;' +
|
||||
'border: 1px solid #DDD;' +
|
||||
'}' +
|
||||
'#mathjax label{' +
|
||||
'display: block;' +
|
||||
'margin: .5em;' +
|
||||
'}' +
|
||||
'#mathjax legend {' +
|
||||
'max-width:195px;' +
|
||||
'}' +
|
||||
'#mathjax_overlay {' +
|
||||
'position: absolute;' +
|
||||
'top: 0;' +
|
||||
'left: 0;' +
|
||||
'right: 0;' +
|
||||
'bottom: 0;' +
|
||||
'background-color: black;' +
|
||||
'opacity: 0.6;' +
|
||||
'z-index: 20000;' +
|
||||
'}' +
|
||||
'#mathjax_container {' +
|
||||
'position: absolute;' +
|
||||
'top: 50px;' +
|
||||
'padding: 10px;' +
|
||||
'background-color: #B0B0B0;' +
|
||||
'border: 1px outset #777;' +
|
||||
'opacity: 1.0;' +
|
||||
'font-family: Verdana, Helvetica, sans-serif;' +
|
||||
'font-size: .8em;' +
|
||||
'z-index: 20001;' +
|
||||
'}' +
|
||||
'#tool_mathjax_back {' +
|
||||
'margin-left: 1em;' +
|
||||
'overflow: auto;' +
|
||||
'}' +
|
||||
'#mathjax_legend{' +
|
||||
'font-weight: bold;' +
|
||||
'font-size:1.1em;' +
|
||||
'}' +
|
||||
'#mathjax_code_textarea {\\n' +
|
||||
'margin: 5px .7em;' +
|
||||
'overflow: hidden;' +
|
||||
'width: 416px;' +
|
||||
'display: block;' +
|
||||
'height: 100px;' +
|
||||
'}';
|
||||
head.appendChild(style);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
$('#placemark_panel').toggle(on);
|
||||
$id('placemark_panel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,10 +104,11 @@ export default {
|
||||
const items = txt.split(';');
|
||||
selElems.forEach((elem) => {
|
||||
if (elem && elem.getAttribute('class').includes('placemark')) {
|
||||
$(elem).children().each((_, i) => {
|
||||
var elements = elem.children;
|
||||
Array.prototype.forEach.call(elements, function(i, _){
|
||||
const [, , type, n] = i.id.split('_');
|
||||
if (type === 'txt') {
|
||||
$(i).text(items[n]);
|
||||
t.textContent = items[n];
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -124,10 +125,11 @@ export default {
|
||||
font = font.join(' ');
|
||||
selElems.forEach((elem) => {
|
||||
if (elem && elem.getAttribute('class').includes('placemark')) {
|
||||
$(elem).children().each((_, i) => {
|
||||
var elements = elem.children;
|
||||
Array.prototype.forEach.call(elements, function(i, _){
|
||||
const [, , type] = i.id.split('_');
|
||||
if (type === 'txt') {
|
||||
$(i).attr({'font-family': font, 'font-size': fontSize});
|
||||
i.style.cssText = 'font-family:' + font + ';font-size:'+fontSize+';';
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -141,13 +143,12 @@ export default {
|
||||
function addMarker (id, val) {
|
||||
let marker = svgCanvas.getElem(id);
|
||||
if (marker) { return undefined; }
|
||||
// console.log(id);
|
||||
if (val === '' || val === 'nomarker') { return undefined; }
|
||||
const color = svgCanvas.getColor('stroke');
|
||||
// NOTE: Safari didn't like a negative value in viewBox
|
||||
// so we use a standardized 0 0 100 100
|
||||
// with 50 50 being mapped to the marker position
|
||||
const scale = 2;// parseFloat($('#marker_size').val());
|
||||
const scale = 2;
|
||||
const strokeWidth = 10;
|
||||
let refX = 50;
|
||||
const refY = 50;
|
||||
@@ -200,7 +201,7 @@ export default {
|
||||
function setMarker (el, val) {
|
||||
const markerName = 'marker-start';
|
||||
const marker = getLinked(el, markerName);
|
||||
if (marker) { $(marker).remove(); }
|
||||
if (marker) { marker.remove(); }
|
||||
el.removeAttribute(markerName);
|
||||
if (val === 'nomarker') {
|
||||
svgCanvas.call('changed', [el]);
|
||||
@@ -249,7 +250,7 @@ export default {
|
||||
const len = el.id.length;
|
||||
const linkid = url.substr(-len - 1, len);
|
||||
if (el.id !== linkid) {
|
||||
const val = $('#placemark_marker').attr('value') || 'leftarrow';
|
||||
const val = $id('placemark_marker').getAttribute('value') || 'leftarrow';
|
||||
addMarker(id, val);
|
||||
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
|
||||
svgCanvas.call('changed', selElems);
|
||||
@@ -264,7 +265,7 @@ export default {
|
||||
const parts = this.id.split('_');
|
||||
let val = parts[2];
|
||||
if (parts[3]) { val += '_' + parts[3]; }
|
||||
$('#placemark_marker').attr('value', val);
|
||||
$id('placemark_marker').setAttribute('value', val);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,8 +369,8 @@ export default {
|
||||
if (svgCanvas.getMode() === 'placemark') {
|
||||
started = true;
|
||||
const id = svgCanvas.getNextId();
|
||||
const items = $('#placemarkText').val().split(';');
|
||||
let font = $('#placemarkFont').val().split(' ');
|
||||
const items = $id('placemarkText').value.split(';');
|
||||
let font = $id('placemarkFont').value.split(' ');
|
||||
const fontSize = Number.parseInt(font.pop());
|
||||
font = font.join(' ');
|
||||
const x0 = opts.start_x + 10, y0 = opts.start_y + 10;
|
||||
@@ -453,7 +454,7 @@ export default {
|
||||
});
|
||||
setMarker(
|
||||
newPM.firstElementChild,
|
||||
$('#placemark_marker').attr('value') || 'leftarrow'
|
||||
$id('placemark_marker').getAttribute('value') || 'leftarrow'
|
||||
);
|
||||
return {
|
||||
started: true
|
||||
@@ -468,11 +469,16 @@ export default {
|
||||
if (svgCanvas.getMode() === 'placemark') {
|
||||
const x = opts.mouse_x / svgCanvas.getZoom();
|
||||
const y = opts.mouse_y / svgCanvas.getZoom();
|
||||
const {fontSize, maxlen, lines, px, py} = $(newPM).attr(
|
||||
['fontSize', 'maxlen', 'lines', 'px', 'py']
|
||||
);
|
||||
$(newPM).attr({x, y});
|
||||
$(newPM).children().each((_, i) => {
|
||||
const fontSize = newPM.getAttribute('fontSize');
|
||||
const maxlen = newPM.getAttribute('maxlen');
|
||||
const lines = newPM.getAttribute('lines');
|
||||
const px = newPM.getAttribute('px');
|
||||
const py = newPM.getAttribute('py');
|
||||
|
||||
newPM.setAttribute('x', x);
|
||||
newPM.setAttribute('y', y);
|
||||
const elements = newPM.children;
|
||||
Array.prototype.forEach.call(elements, function(i, _){
|
||||
const [, , type, n] = i.id.split('_');
|
||||
const y0 = y + (fontSize + 6) * n,
|
||||
x0 = x + maxlen * fontSize * 0.5 + fontSize;
|
||||
@@ -509,7 +515,10 @@ export default {
|
||||
},
|
||||
mouseUp () {
|
||||
if (svgCanvas.getMode() === 'placemark') {
|
||||
const {x, y, px, py} = $(newPM).attr(['x', 'y', 'px', 'py']);
|
||||
const x = newPM.getAttribute('x');
|
||||
const y = newPM.getAttribute('y');
|
||||
const px = newPM.getAttribute('px');
|
||||
const py = newPM.getAttribute('py');
|
||||
return {
|
||||
keep: (x != px && y != py), // eslint-disable-line eqeqeq
|
||||
element: newPM
|
||||
@@ -523,16 +532,17 @@ export default {
|
||||
selElems.forEach((elem) => {
|
||||
if (elem && elem.getAttribute('class').includes('placemark')) {
|
||||
const txt = [];
|
||||
$(elem).children().each((n, i) => {
|
||||
const elements = elem.children;
|
||||
Array.prototype.forEach.call(elements, function(i, n){
|
||||
const [, , type] = i.id.split('_');
|
||||
if (type === 'txt') {
|
||||
$('#placemarkFont').val(
|
||||
$id('placemarkFont').value = (
|
||||
i.getAttribute('font-family') + ' ' + i.getAttribute('font-size')
|
||||
);
|
||||
txt.push($(i).text());
|
||||
txt.push(i.textContent);
|
||||
}
|
||||
});
|
||||
$('#placemarkText').val(txt.join(';'));
|
||||
$id('placemarkText').value = txt.join(';');
|
||||
showPanel(true);
|
||||
} else {
|
||||
showPanel(false);
|
||||
|
||||
@@ -24,42 +24,26 @@ export default {
|
||||
const svgEditor = this;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const {$id} = svgCanvas;
|
||||
const {$} = S, // {svgcontent}
|
||||
// addElem = svgCanvas.addSVGElementFromJson,
|
||||
editingitex = false;
|
||||
const {$} = S;
|
||||
const editingitex = false;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
let selElems,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
|
||||
// edg = 0,
|
||||
// undoCommand = 'Not image';
|
||||
started, newFO;
|
||||
let selElems;
|
||||
let started;
|
||||
let newFO;
|
||||
/**
|
||||
* @param {boolean} on
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
}
|
||||
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
|
||||
$('#polygon_panel').toggle(on);
|
||||
}
|
||||
|
||||
/*
|
||||
function toggleSourceButtons(on){
|
||||
$('#tool_source_save, #tool_source_cancel').toggle(!on);
|
||||
$('#polygon_save, #polygon_cancel').toggle(on);
|
||||
}
|
||||
*/
|
||||
const showPanel = (on) => {
|
||||
$id('polygon_panel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} attr
|
||||
* @param {string|Float} val
|
||||
* @returns {void}
|
||||
*/
|
||||
function setAttr (attr, val) {
|
||||
const setAttr = (attr, val) => {
|
||||
svgCanvas.changeSelectedAttribute(attr, val);
|
||||
svgCanvas.call('changed', selElems);
|
||||
}
|
||||
@@ -68,88 +52,50 @@ export default {
|
||||
* @param {Float} n
|
||||
* @returns {Float}
|
||||
*/
|
||||
function cot (n) {
|
||||
return 1 / Math.tan(n);
|
||||
}
|
||||
const cot = (n) => (1 / Math.tan(n));
|
||||
|
||||
/**
|
||||
* @param {Float} n
|
||||
* @returns {Float}
|
||||
*/
|
||||
function sec (n) {
|
||||
return 1 / Math.cos(n);
|
||||
}
|
||||
const sec = (n) => (1 / Math.cos(n));
|
||||
|
||||
/**
|
||||
* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
|
||||
* This function sets the content of of the currently-selected foreignObject element,
|
||||
* based on the itex contained in string.
|
||||
* @param {string} tex The itex text.
|
||||
* @returns {boolean} This function returns false if the set was unsuccessful, true otherwise.
|
||||
*/
|
||||
const events = {
|
||||
id: 'tool_polygon',
|
||||
click () {
|
||||
svgCanvas.setMode('polygon');
|
||||
showPanel(true);
|
||||
}
|
||||
};
|
||||
const contextTools = [{
|
||||
type: 'input',
|
||||
panel: 'polygon_panel',
|
||||
id: 'polySides',
|
||||
size: 3,
|
||||
defval: 5,
|
||||
events: {
|
||||
change () {
|
||||
setAttr('sides', this.value);
|
||||
}
|
||||
}
|
||||
}];
|
||||
return {
|
||||
name: strings.name,
|
||||
events,
|
||||
context_tools: strings.contextTools.map((contextTool, i) => {
|
||||
return Object.assign(contextTools[i], contextTool);
|
||||
}),
|
||||
|
||||
// The callback should be used to load the DOM with the appropriate UI items
|
||||
callback () {
|
||||
if($id("polygon_panel") !== null) $id("polygon_panel").style.display = 'none';
|
||||
const endChanges = function () {
|
||||
// Todo: Missing?
|
||||
};
|
||||
// Add the button and its handler(s)
|
||||
// Note: the star extension may also add the same flying button so we check first
|
||||
if ($id('tools_polygon') === null) {
|
||||
const buttonTemplate = document.createElement("template");
|
||||
buttonTemplate.innerHTML = `
|
||||
<se-flyingbutton id="tools_polygon" title="Polygone/Star Tool">
|
||||
<se-button id="tool_polygon" title="Polygon Tool" src="./images/polygon.svg"></se-button>
|
||||
<se-button id="tool_star" title="Star Tool" src="./images/star.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
`
|
||||
$id('tools_left').append(buttonTemplate.content.cloneNode(true));
|
||||
}
|
||||
$id('tool_polygon').addEventListener("click", () => {
|
||||
if (this.leftPanel.updateLeftPanel('tool_polygon')) {
|
||||
svgCanvas.setMode('polygon');
|
||||
showPanel(true);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Needs to be done after orig icon loads
|
||||
setTimeout(function () {
|
||||
// Create source save/cancel buttons
|
||||
/* const save = */ $('#tool_source_save').clone().hide().attr(
|
||||
'id', 'polygon_save'
|
||||
).unbind().appendTo(
|
||||
'#tool_source_back'
|
||||
).click(function () {
|
||||
if (!editingitex) {
|
||||
return;
|
||||
}
|
||||
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
|
||||
/*
|
||||
if (!setItexString($('#svg_source_textarea').val())) {
|
||||
const ok = seConfirm('Errors found. Revert to original?', function (ok) {
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
endChanges();
|
||||
} else { */
|
||||
endChanges();
|
||||
// }
|
||||
// setSelectMode();
|
||||
});
|
||||
|
||||
/* const cancel = */ $('#tool_source_cancel').clone().hide().attr(
|
||||
'id', 'polygon_cancel'
|
||||
).unbind().appendTo('#tool_source_back').click(function () {
|
||||
endChanges();
|
||||
});
|
||||
}, 3000);
|
||||
// Add the context panel and its handler(s)
|
||||
const panelTemplate = document.createElement("template");
|
||||
panelTemplate.innerHTML = `
|
||||
<div id="polygon_panel">
|
||||
<se-spin-input size="3" id="polySides" min=1 step=1 value=5 label="sides">
|
||||
</se-spin-input>
|
||||
</div>
|
||||
`
|
||||
$id('tools_top').appendChild(panelTemplate.content.cloneNode(true));
|
||||
$id("polygon_panel").style.display = 'none';
|
||||
$id("polySides").addEventListener("change", (event) => {
|
||||
setAttr('sides', event.target.value);
|
||||
});
|
||||
},
|
||||
mouseDown (opts) {
|
||||
if (svgCanvas.getMode() !== 'polygon') {
|
||||
@@ -188,12 +134,18 @@ export default {
|
||||
if (!started || svgCanvas.getMode() !== 'polygon') {
|
||||
return undefined;
|
||||
}
|
||||
// const e = opts.event;
|
||||
const c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
|
||||
const cx = Number(newFO.getAttribute('cx'));
|
||||
const cy = Number(newFO.getAttribute('cy'));
|
||||
const sides = Number(newFO.getAttribute('sides'));
|
||||
const orient = newFO.getAttribute('orient');
|
||||
const fill = newFO.getAttribute('fill');
|
||||
const strokecolor = newFO.getAttribute('strokecolor');
|
||||
const strokeWidth = Number(newFO.getAttribute('strokeWidth'));
|
||||
|
||||
let x = opts.mouse_x;
|
||||
let y = opts.mouse_y;
|
||||
const {cx, cy, fill, strokecolor, strokeWidth, sides} = c, // {orient} = c,
|
||||
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
|
||||
|
||||
const edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
|
||||
newFO.setAttribute('edge', edg);
|
||||
|
||||
const inradius = (edg / 2) * cot(Math.PI / sides);
|
||||
@@ -212,10 +164,6 @@ export default {
|
||||
newFO.setAttribute('fill', fill);
|
||||
newFO.setAttribute('stroke', strokecolor);
|
||||
newFO.setAttribute('stroke-width', strokeWidth);
|
||||
// newFO.setAttribute('transform', 'rotate(-90)');
|
||||
// const shape = newFO.getAttribute('shape');
|
||||
// newFO.append(poly);
|
||||
// DrawPoly(cx, cy, sides, edg, orient);
|
||||
return {
|
||||
started: true
|
||||
};
|
||||
@@ -225,8 +173,8 @@ export default {
|
||||
if (svgCanvas.getMode() !== 'polygon') {
|
||||
return undefined;
|
||||
}
|
||||
const attrs = $(newFO).attr('edge');
|
||||
const keep = (attrs.edge !== '0');
|
||||
const edge = newFO.getAttribute('edge');
|
||||
const keep = (edge !== '0');
|
||||
// svgCanvas.addToSelection([newFO], true);
|
||||
return {
|
||||
keep,
|
||||
@@ -242,7 +190,7 @@ export default {
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.getAttribute('shape') === 'regularPoly') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
$('#polySides').val(elem.getAttribute('sides'));
|
||||
$id('polySides').value = elem.getAttribute('sides');
|
||||
|
||||
showPanel(true);
|
||||
} else {
|
||||
|
||||
@@ -27,15 +27,18 @@ export default {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const {$id} = svgCanvas;
|
||||
const saveSvgAction = '/+modify';
|
||||
|
||||
// Create upload target (hidden iframe)
|
||||
// Hiding by size instead of display to avoid FF console errors
|
||||
// with `getBBox` in browser.js `supportsPathBBox_`)
|
||||
/* const target = */ $(
|
||||
`<iframe name="output_frame" title="${strings.hiddenframe}"
|
||||
style="width: 0; height: 0;" src="data:text/html;base64,PGh0bWw+PC9odG1sPg=="/>`
|
||||
).appendTo('body');
|
||||
const iframe = document.createElement('IFRAME');
|
||||
iframe.src="data:text/html;base64,PGh0bWw+PC9odG1sPg==";
|
||||
document.body.append(iframe);
|
||||
iframe.name = "output_frame";
|
||||
iframe.contentWindow.document.title = strings.hiddenframe;
|
||||
iframe.style.cssText = "width:0;height:0;";
|
||||
|
||||
svgEditor.setCustomHandlers({
|
||||
async save (win, data) {
|
||||
@@ -43,27 +46,33 @@ export default {
|
||||
const {pathname} = new URL(location);
|
||||
const name = pathname.replace(/\/+get\//, '');
|
||||
const svgData = encode64(svg);
|
||||
if (!$('#export_canvas').length) {
|
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
|
||||
if (!$id('export_canvas')) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.setAttribute('id', 'export_canvas');
|
||||
canvas.style.display = 'none';
|
||||
document.body.appendChild(canvas);
|
||||
}
|
||||
const c = $('#export_canvas')[0];
|
||||
c.width = svgCanvas.contentW;
|
||||
c.height = svgCanvas.contentH;
|
||||
const c = $id('export_canvas');
|
||||
c.style.width = svgCanvas.contentW;
|
||||
c.style.height = svgCanvas.contentH;
|
||||
await canvg(c, svg);
|
||||
const datauri = c.toDataURL('image/png');
|
||||
// const {uiStrings} = svgEditor;
|
||||
const pngData = encode64(datauri); // Brett: This encoding seems unnecessary
|
||||
/* const form = */ $('<form>').attr({
|
||||
method: 'post',
|
||||
action: saveSvgAction + '/' + name,
|
||||
target: 'output_frame'
|
||||
}).append(`
|
||||
<input type="hidden" name="png_data" value="${pngData}">
|
||||
<input type="hidden" name="filepath" value="${svgData}">
|
||||
<input type="hidden" name="filename" value="drawing.svg">
|
||||
<input type="hidden" name="contenttype" value="application/x-svgdraw">
|
||||
`).appendTo('body')
|
||||
.submit().remove();
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.setAttribute('method', 'post');
|
||||
form.setAttribute('action', saveSvgAction + '/' + name);
|
||||
form.setAttribute('target', 'output_frame');
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
form.innerHTML = `<input type="hidden" name="png_data" value="${pngData}">
|
||||
<input type="hidden" name="filepath" value="${svgData}">
|
||||
<input type="hidden" name="filename" value="drawing.svg">
|
||||
<input type="hidden" name="contenttype" value="application/x-svgdraw">`;
|
||||
document.body.append(form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(strings.saved);
|
||||
top.window.location = '/' + name;
|
||||
|
||||
@@ -63,14 +63,16 @@ export default {
|
||||
if (avoidClientSide || avoidClientSideDownload) {
|
||||
return false;
|
||||
}
|
||||
const support = $('<a>')[0].download === '';
|
||||
const support = document.querySelector('a').download === '';
|
||||
let a;
|
||||
if (support) {
|
||||
a = $('<a>hidden</a>').attr({
|
||||
download: (filename || 'image') + suffix,
|
||||
href: uri
|
||||
}).css('display', 'none').appendTo('body');
|
||||
a[0].click();
|
||||
a = document.createElement("a");
|
||||
a.text = 'hidden';
|
||||
a.download = (filename || 'image') + suffix;
|
||||
a.href = uri;
|
||||
a.style.dispaly = 'none';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -84,10 +86,13 @@ export default {
|
||||
|
||||
// Hiding by size instead of display to avoid FF console errors
|
||||
// with `getBBox` in browser.js `supportsPathBBox_`)
|
||||
$(
|
||||
`<iframe name="output_frame" title="${strings.hiddenframe}"
|
||||
style="width: 0; height: 0;" src="data:text/html;base64,PGh0bWw+"/>`
|
||||
).appendTo('body');
|
||||
const iframe = document.createElement('IFRAME');
|
||||
iframe.src="data:text/html;base64,PGh0bWw+";
|
||||
document.body.append(iframe);
|
||||
iframe.name = "output_frame";
|
||||
iframe.contentWindow.document.title = strings.hiddenframe;
|
||||
iframe.style.cssText = "width:0;height:0;";
|
||||
|
||||
svgEditor.setCustomHandlers({
|
||||
save (win, data) {
|
||||
const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
|
||||
@@ -97,15 +102,16 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
$('<form>').attr({
|
||||
method: 'post',
|
||||
action: saveSvgAction,
|
||||
target: 'output_frame'
|
||||
}).append(`
|
||||
<input type="hidden" name="output_svg" value="${xhtmlEscape(svg)}">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">
|
||||
`).appendTo('body')
|
||||
.submit().remove();
|
||||
const form = document.createElement('form');
|
||||
form.setAttribute('method', 'post');
|
||||
form.setAttribute('action', saveSvgAction);
|
||||
form.setAttribute('target', 'output_frame');
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
form.innerHTML = `<input type="hidden" name="output_svg" value="${xhtmlEscape(svg)}">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">`;
|
||||
document.body.append(form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
},
|
||||
exportPDF (win, data) {
|
||||
const filename = getFileNameFromTitle(),
|
||||
@@ -113,28 +119,32 @@ export default {
|
||||
if (clientDownloadSupport(filename, '.pdf', datauri)) {
|
||||
return;
|
||||
}
|
||||
$('<form>').attr({
|
||||
method: 'post',
|
||||
action: saveImgAction,
|
||||
target: 'output_frame'
|
||||
}).append(`
|
||||
<input type="hidden" name="output_img" value="${datauri}">
|
||||
<input type="hidden" name="mime" value="application/pdf">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">
|
||||
`).appendTo('body')
|
||||
.submit().remove();
|
||||
const form = document.createElement('form');
|
||||
form.setAttribute('method', 'post');
|
||||
form.setAttribute('action', saveImgAction);
|
||||
form.setAttribute('target', 'output_frame');
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
form.innerHTML = `<input type="hidden" name="output_img" value="${datauri}">
|
||||
<input type="hidden" name="mime" value="application/pdf">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">`;
|
||||
document.body.append(form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
},
|
||||
// Todo: Integrate this extension with a new built-in exportWindowType, "download"
|
||||
async exportImage (win, data) {
|
||||
const {issues, mimeType, quality} = data;
|
||||
|
||||
if (!$('#export_canvas').length) {
|
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
|
||||
if (!$id('export_canvas')) {
|
||||
const canvasx = document.createElement("CANVAS");
|
||||
canvasx.id = 'export_canvas';
|
||||
canvasx.style.display = 'none';
|
||||
document.body.appendChild(canvasx);
|
||||
}
|
||||
const c = $('#export_canvas')[0];
|
||||
const c = $id('export_canvas');
|
||||
|
||||
c.width = svgCanvas.contentW;
|
||||
c.height = svgCanvas.contentH;
|
||||
c.style.width = svgCanvas.contentW;
|
||||
c.style.height = svgCanvas.contentH;
|
||||
await canvg(c, data.svg);
|
||||
const datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType);
|
||||
// {uiStrings} = svgEditor;
|
||||
@@ -158,16 +168,17 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
$('<form>').attr({
|
||||
method: 'post',
|
||||
action: saveImgAction,
|
||||
target: 'output_frame'
|
||||
}).append(`
|
||||
<input type="hidden" name="output_img" value="${datauri}">
|
||||
<input type="hidden" name="mime" value="${mimeType}">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">
|
||||
`).appendTo('body')
|
||||
.submit().remove();
|
||||
const form = document.createElement('form');
|
||||
form.setAttribute('method', 'post');
|
||||
form.setAttribute('action', saveImgAction);
|
||||
form.setAttribute('target', 'output_frame');
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
form.innerHTML = `<input type="hidden" name="output_img" value="${datauri}">
|
||||
<input type="hidden" name="mime" value="${mimeType}">
|
||||
<input type="hidden" name="filename" value="${xhtmlEscape(filename)}">`;
|
||||
document.body.append(form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -209,19 +220,21 @@ export default {
|
||||
};
|
||||
|
||||
// Create upload form
|
||||
const openSvgForm = $('<form>');
|
||||
openSvgForm.attr({
|
||||
enctype: 'multipart/form-data',
|
||||
method: 'post',
|
||||
action: openSvgAction,
|
||||
target: 'output_frame'
|
||||
});
|
||||
|
||||
const openSvgForm = document.createElement("FORM");
|
||||
openSvgForm.action = openSvgAction;
|
||||
openSvgForm.enctype = 'multipart/form-data';
|
||||
openSvgForm.method = 'post';
|
||||
openSvgForm.target = 'output_frame';
|
||||
|
||||
|
||||
// Create import form
|
||||
const importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
|
||||
const importSvgForm = openSvgForm.cloneNode(true);
|
||||
importSvgForm.action = importSvgAction;
|
||||
|
||||
// Create image form
|
||||
const importImgForm = openSvgForm.clone().attr('action', importImgAction);
|
||||
const importImgForm = openSvgForm.cloneNode(true);
|
||||
importImgForm.action = importImgAction;
|
||||
|
||||
// It appears necessary to rebuild this input every time a file is
|
||||
// selected so the same file can be picked and the change event can fire.
|
||||
@@ -233,7 +246,10 @@ export default {
|
||||
*/
|
||||
function rebuildInput (form) {
|
||||
form.empty();
|
||||
const inp = $('<input type="file" name="svg_file">').appendTo(form);
|
||||
const inp = document.createElement('input');
|
||||
inp.type = 'file';
|
||||
inp.name = 'svg_file';
|
||||
form.appendChild(inp);
|
||||
|
||||
/**
|
||||
* Submit the form, empty its contents for reuse and show
|
||||
@@ -276,8 +292,8 @@ export default {
|
||||
// Add forms to buttons
|
||||
$id("tool_open").style.display = 'block';
|
||||
$id("tool_import").style.display = 'block';
|
||||
$('#tool_open').prepend(openSvgForm);
|
||||
$('#tool_import').prepend(importSvgForm);
|
||||
$('#tool_image').prepend(importImgForm);
|
||||
$id('tool_open').insertBefore(openSvgForm, $id('tool_open').firstChild);
|
||||
$id('tool_import').insertBefore(importSvgForm, $id('tool_import').firstChild);
|
||||
$id('tool_image').insertBefore(importImgForm, $id('tool_image').firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,16 +25,9 @@ export default {
|
||||
const {svgCanvas} = svgEditor;
|
||||
const {$id} = svgCanvas;
|
||||
const {$} = S; // {svgcontent},
|
||||
let
|
||||
selElems,
|
||||
// editingitex = false,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
started,
|
||||
newFO;
|
||||
// edg = 0,
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
||||
// undoCommand = 'Not image',
|
||||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||
let selElems;
|
||||
let started;
|
||||
let newFO;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
|
||||
/**
|
||||
@@ -42,93 +35,73 @@ export default {
|
||||
* @param {boolean} on
|
||||
* @returns {void}
|
||||
*/
|
||||
function showPanel (on) {
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
}
|
||||
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
|
||||
$('#star_panel').toggle(on);
|
||||
const showPanel = (on) => {
|
||||
$id('star_panel').style.display = (on) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/*
|
||||
function toggleSourceButtons(on){
|
||||
$('#star_save, #star_cancel').toggle(on);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} attr
|
||||
* @param {string|Float} val
|
||||
* @returns {void}
|
||||
*/
|
||||
function setAttr (attr, val) {
|
||||
const setAttr = (attr, val) => {
|
||||
svgCanvas.changeSelectedAttribute(attr, val);
|
||||
svgCanvas.call('changed', selElems);
|
||||
}
|
||||
|
||||
/*
|
||||
function cot(n){
|
||||
return 1 / Math.tan(n);
|
||||
}
|
||||
|
||||
function sec(n){
|
||||
return 1 / Math.cos(n);
|
||||
}
|
||||
*/
|
||||
const events = {
|
||||
id: 'tool_star',
|
||||
click () {
|
||||
showPanel(true);
|
||||
svgCanvas.setMode('star');
|
||||
}
|
||||
};
|
||||
const contextTools = [{
|
||||
type: 'input',
|
||||
panel: 'star_panel',
|
||||
id: 'starNumPoints',
|
||||
size: 3,
|
||||
defval: 5,
|
||||
events: {
|
||||
change () {
|
||||
setAttr('point', this.value);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
type: 'input',
|
||||
panel: 'star_panel',
|
||||
id: 'starRadiusMulitplier',
|
||||
size: 3,
|
||||
defval: 2.5
|
||||
}, {
|
||||
type: 'input',
|
||||
panel: 'star_panel',
|
||||
id: 'radialShift',
|
||||
size: 3,
|
||||
defval: 0,
|
||||
events: {
|
||||
change () {
|
||||
setAttr('radialshift', this.value);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
return {
|
||||
name: strings.name,
|
||||
events,
|
||||
context_tools: strings.contextTools.map((contextTool, i) => {
|
||||
return Object.assign(contextTools[i], contextTool);
|
||||
}),
|
||||
// The callback should be used to load the DOM with the appropriate UI items
|
||||
callback () {
|
||||
if($id("star_panel") !== null) $id("star_panel").style.display = 'none';
|
||||
// const endChanges = function(){};
|
||||
// Add the button and its handler(s)
|
||||
// Note: the star extension may also add the same flying button so we check first
|
||||
if ($id('tools_polygon') === null) {
|
||||
const buttonTemplate = document.createElement("template");
|
||||
buttonTemplate.innerHTML = `
|
||||
<se-flyingbutton id="tools_polygon" title="Polygone/Star Tool">
|
||||
<se-button id="tool_polygon" title="Polygon Tool" src="./images/polygon.svg"></se-button>
|
||||
<se-button id="tool_star" title="Star Tool" src="./images/star.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
`
|
||||
$id('tools_left').append(buttonTemplate.content.cloneNode(true));
|
||||
}
|
||||
$id('tool_star').addEventListener("click", () => { showPanel(true);
|
||||
if (this.leftPanel.updateLeftPanel('tool_polygon')) {
|
||||
svgCanvas.setMode('star');
|
||||
showPanel(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Add the context panel and its handler(s)
|
||||
const panelTemplate = document.createElement("template");
|
||||
panelTemplate.innerHTML = `
|
||||
<div id="star_panel">
|
||||
<se-spin-input id="starNumPoints" label="points" min=1 step=1 value=5 title="Change rotation angle">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="RadiusMultiplier" label="Radis multiplier" min=1 step=2.5 value=5 title="Change rotation angle">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="radialShift" min=0 step=1 value=0 label="radial shift" title="Change rotation angle">
|
||||
</se-spin-input>
|
||||
</div>
|
||||
`
|
||||
//add handlers for the panel
|
||||
$id('tools_top').appendChild(panelTemplate.content.cloneNode(true));
|
||||
$id("starNumPoints").addEventListener("change", (event) => {
|
||||
setAttr('point', event.target.value);
|
||||
});
|
||||
$id("RadiusMultiplier").addEventListener("change", (event) => {
|
||||
setAttr('starRadiusMultiplier', event.target.value);
|
||||
});
|
||||
$id("radialShift").addEventListener("change", (event) => {
|
||||
setAttr('radialshift', event.target.value);
|
||||
});
|
||||
// don't display the star panel on start
|
||||
$id("star_panel").style.display = 'none';
|
||||
},
|
||||
mouseDown (opts) {
|
||||
const rgb = svgCanvas.getColor('fill');
|
||||
// const ccRgbEl = rgb.substring(1, rgb.length);
|
||||
const sRgb = svgCanvas.getColor('stroke');
|
||||
// const ccSRgbEl = sRgb.substring(1, rgb.length);
|
||||
const sWidth = svgCanvas.getStrokeWidth();
|
||||
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
@@ -162,13 +135,20 @@ export default {
|
||||
return undefined;
|
||||
}
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
const c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
|
||||
const cx = Number(newFO.getAttribute('cx'));
|
||||
const cy = Number(newFO.getAttribute('cy'));
|
||||
const point = Number(newFO.getAttribute('point'));
|
||||
const orient = newFO.getAttribute('orient');
|
||||
const fill = newFO.getAttribute('fill');
|
||||
const strokecolor = newFO.getAttribute('strokecolor');
|
||||
const strokeWidth = Number(newFO.getAttribute('strokeWidth'));
|
||||
const radialshift = Number(newFO.getAttribute('radialshift'));
|
||||
|
||||
let x = opts.mouse_x;
|
||||
let y = opts.mouse_y;
|
||||
const {cx, cy, fill, strokecolor, strokeWidth, radialshift, point, orient} = c,
|
||||
circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5,
|
||||
inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
|
||||
|
||||
const circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
|
||||
const inradius = circumradius / document.getElementById('RadiusMultiplier').value;
|
||||
newFO.setAttribute('r', circumradius);
|
||||
newFO.setAttribute('r2', inradius);
|
||||
|
||||
@@ -215,10 +195,9 @@ export default {
|
||||
},
|
||||
mouseUp () {
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
const attrs = $(newFO).attr(['r']);
|
||||
// svgCanvas.addToSelection([newFO], true);
|
||||
const r = newFO.getAttribute('r');
|
||||
return {
|
||||
keep: (attrs.r !== '0'),
|
||||
keep: (r !== '0'),
|
||||
element: newFO
|
||||
};
|
||||
}
|
||||
@@ -233,9 +212,8 @@ export default {
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.getAttribute('shape') === 'star') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
// $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
|
||||
$('#starNumPoints').val(elem.getAttribute('point'));
|
||||
$('#radialShift').val(elem.getAttribute('radialshift'));
|
||||
$id('starNumPoints').value = elem.getAttribute('point');
|
||||
$id('radialShift').value = elem.getAttribute('radialshift');
|
||||
showPanel(true);
|
||||
} else {
|
||||
showPanel(false);
|
||||
|
||||
@@ -57,10 +57,6 @@ export default {
|
||||
case 'view':
|
||||
// Populate the contents
|
||||
svgEditor.loadFromString(content);
|
||||
|
||||
/* if ($('#tool_save_file')) {
|
||||
$('#tool_save_file').disabled = false;
|
||||
} */
|
||||
break;
|
||||
case 'save-end':
|
||||
// eslint-disable-next-line no-alert
|
||||
|
||||
@@ -140,7 +140,6 @@ class BottomPanel {
|
||||
* @type {module}
|
||||
*/
|
||||
handleOpacity (evt) {
|
||||
// if ($(this).find('div').length) { return; }
|
||||
const val = Number.parseInt(evt.currentTarget.value.split('%')[0]);
|
||||
this.editor.svgCanvas.setOpacity(val / 100);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable no-alert */
|
||||
/* globals $ */
|
||||
import SvgCanvas from "../../svgcanvas/svgcanvas.js";
|
||||
|
||||
const SIDEPANEL_MAXWIDTH = 300;
|
||||
@@ -324,7 +323,6 @@ class LayersPanel {
|
||||
* @returns {void}
|
||||
*/
|
||||
layerRename() {
|
||||
// const curIndex = $('#layerlist tr.layersel').prevAll().length; // Currently unused
|
||||
const oldName = document.querySelector("#layerlist tr.layersel td.layername").textContent;
|
||||
const newName = prompt(this.uiStrings.notification.enterNewLayerName, "");
|
||||
if (!newName) {
|
||||
@@ -375,58 +373,73 @@ class LayersPanel {
|
||||
*/
|
||||
populateLayers() {
|
||||
this.editor.svgCanvas.clearSelection();
|
||||
const layerlist = $("#layerlist tbody").empty();
|
||||
const selLayerNames = $("#selLayerNames").empty();
|
||||
const self = this;
|
||||
const layerlist = $id("layerlist").querySelector('tbody');
|
||||
while(layerlist.firstChild)
|
||||
layerlist.removeChild(layerlist.firstChild);
|
||||
|
||||
const selLayerNames = $id("selLayerNames");
|
||||
// empty() ref: http://youmightnotneedjquery.com/#empty
|
||||
while(selLayerNames.firstChild)
|
||||
selLayerNames.removeChild(selLayerNames.firstChild);
|
||||
const drawing = this.editor.svgCanvas.getCurrentDrawing();
|
||||
const currentLayerName = drawing.getCurrentLayerName();
|
||||
let layer = this.editor.svgCanvas.getCurrentDrawing().getNumLayers();
|
||||
// we get the layers in the reverse z-order (the layer rendered on top is listed first)
|
||||
while (layer--) {
|
||||
const name = drawing.getLayerName(layer);
|
||||
const layerTr = $('<tr class="layer">').toggleClass(
|
||||
"layersel",
|
||||
name === currentLayerName
|
||||
);
|
||||
const layerVis = $('<td class="layervis">').toggleClass(
|
||||
"layerinvis",
|
||||
!drawing.getLayerVisibility(name)
|
||||
);
|
||||
const layerName = $('<td class="layername">' + name + "</td>");
|
||||
layerlist.append(layerTr.append(layerVis, layerName));
|
||||
selLayerNames.append(
|
||||
'<option value="' + name + '">' + name + "</option>"
|
||||
);
|
||||
const layerTr = document.createElement("tr");
|
||||
layerTr.className = (name === currentLayerName) ? 'layer layersel' : 'layer';
|
||||
const layerVis = document.createElement("td");
|
||||
layerVis.className = (!drawing.getLayerVisibility(name)) ? "layerinvis layervis" : 'layervis';
|
||||
const layerName = document.createElement("td");
|
||||
layerName.className = 'layername';
|
||||
layerName.textContent = name;
|
||||
layerTr.appendChild(layerVis);
|
||||
layerTr.appendChild(layerName);
|
||||
layerlist.appendChild(layerTr);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
selLayerNames.innerHTML += '<option value="' + name + '">' + name + '</option>';
|
||||
}
|
||||
// handle selection of layer
|
||||
$("#layerlist td.layername")
|
||||
.mouseup(evt => {
|
||||
$("#layerlist tr.layer").removeClass("layersel");
|
||||
$(evt.currentTarget.parentNode).addClass("layersel");
|
||||
this.editor.svgCanvas.setCurrentLayer(evt.currentTarget.textContent);
|
||||
evt.preventDefault();
|
||||
})
|
||||
.mouseover(evt => {
|
||||
this.toggleHighlightLayer(
|
||||
this.editor.svgCanvas,
|
||||
const nelements = $id('layerlist').querySelectorAll("td.layername");
|
||||
Array.from(nelements).forEach(function(element) {
|
||||
element.addEventListener('mouseup', function(evt) {
|
||||
const trElements = $id('layerlist').querySelectorAll("tr.layer");
|
||||
Array.from(trElements).forEach(function(element) {
|
||||
element.classList.remove("layersel");
|
||||
});
|
||||
evt.currentTarget.parentNode.classList.add("layersel");
|
||||
self.editor.svgCanvas.setCurrentLayer(evt.currentTarget.textContent);
|
||||
evt.preventDefault();
|
||||
});
|
||||
element.addEventListener('mouseup', function(evt) {
|
||||
self.toggleHighlightLayer(
|
||||
self.editor.svgCanvas,
|
||||
evt.currentTarget.textContent
|
||||
);
|
||||
})
|
||||
.mouseout(() => {
|
||||
this.toggleHighlightLayer(this.editor.svgCanvas);
|
||||
});
|
||||
$("#layerlist td.layervis").click(evt => {
|
||||
const row = $(evt.currentTarget.parentNode).prevAll().length;
|
||||
const name = $("#layerlist tr.layer:eq(" + row + ") td.layername").text();
|
||||
const vis = $(evt.currentTarget).hasClass("layerinvis");
|
||||
this.editor.svgCanvas.setLayerVisibility(name, vis);
|
||||
$(evt.currentTarget).toggleClass("layerinvis");
|
||||
element.addEventListener('mouseout', function(evt) {
|
||||
self.toggleHighlightLayer(self.editor.svgCanvas);
|
||||
});
|
||||
});
|
||||
const elements = $id('layerlist').querySelectorAll("td.layervis");
|
||||
Array.from(elements).forEach(function(element) {
|
||||
element.addEventListener('click', function(evt) {
|
||||
const name = evt.currentTarget.parentNode.querySelector("td.layername").textContent;
|
||||
const vis = evt.currentTarget.classList.contains("layerinvis");
|
||||
self.editor.svgCanvas.setLayerVisibility(name, vis);
|
||||
evt.currentTarget.classList.toggle("layerinvis");
|
||||
});
|
||||
});
|
||||
|
||||
// if there were too few rows, let's add a few to make it not so lonely
|
||||
let num = 5 - $("#layerlist tr.layer").size();
|
||||
let num = 5 - $id('layerlist').querySelectorAll("tr.layer").length;
|
||||
while (num-- > 0) {
|
||||
// TODO: there must a better way to do this
|
||||
layerlist.append('<tr><td style="color:white">_</td><td/></tr>');
|
||||
const tlayer = document.createElement("tr");
|
||||
tlayer.innerHTML = '<td style="color:white">_</td><td/>';
|
||||
layerlist.append(tlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,10 +214,6 @@ class LeftPanel {
|
||||
<se-button id="tool_circle" title="Square" src="./images/circle.svg"></se-button>
|
||||
<se-button id="tool_fhellipse" title="Free-Hand Rectangle" src="./images/fh_ellipse.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
<se-flyingbutton id="tools_polygon" title="Polygone/Star Tool">
|
||||
<se-button id="tool_polygon" title="Polygon Tool" src="./images/polygon.svg"></se-button>
|
||||
<se-button id="tool_star" title="Star Tool" src="./images/star.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
<se-button id="mode_connect" title="Connect two objects" src="./images/conn.svg"></se-button>
|
||||
<se-button id="tool_text" title="Text Tool" src="./images/text.svg" shortcut="T"></se-button>
|
||||
<se-button id="tool_image" title="Image Tool" src="./images/image.svg"></se-button>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* globals $ */
|
||||
import SvgCanvas from "../../svgcanvas/svgcanvas.js";
|
||||
import { isValidUnit, getTypeMap, convertUnit } from "../../common/units.js";
|
||||
|
||||
@@ -51,7 +50,13 @@ class TopPanel {
|
||||
if (changeElem) {
|
||||
this.svgCanvas.setStrokeAttr('stroke-' + pre, val);
|
||||
}
|
||||
$(opt).addClass('current').siblings().removeClass('current');
|
||||
opt.classList.add('current');
|
||||
const elements = Array.prototype.filter.call(opt.parentNode.children, function(child){
|
||||
return child !== opt;
|
||||
});
|
||||
Array.from(elements).forEach(function(element) {
|
||||
element.classList.remove('current');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +154,7 @@ class TopPanel {
|
||||
updateContextPanel() {
|
||||
const setInputWidth = elem => {
|
||||
const w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300);
|
||||
$(elem).width(w);
|
||||
elem.style.width = w + 'px';
|
||||
};
|
||||
|
||||
let elem = this.editor.selectedElement;
|
||||
@@ -182,14 +187,9 @@ class TopPanel {
|
||||
$id("a_panel").style.display = 'none';
|
||||
if (!isNullish(elem)) {
|
||||
const elname = elem.nodeName;
|
||||
// If this is a link with no transform and one child, pretend
|
||||
// its child is selected
|
||||
// if (elname === 'a') { // && !$(elem).attr('transform')) {
|
||||
// elem = elem.firstChild;
|
||||
// }
|
||||
|
||||
const angle = this.editor.svgCanvas.getRotationAngle(elem);
|
||||
$("#angle").val(angle);
|
||||
$id("angle").value = angle;
|
||||
|
||||
const blurval = this.editor.svgCanvas.getBlur(elem) * 10;
|
||||
$id("blur").value = blurval;
|
||||
@@ -227,8 +227,8 @@ class TopPanel {
|
||||
y = convertUnit(y);
|
||||
}
|
||||
|
||||
$("#selected_x").val(x || 0);
|
||||
$("#selected_y").val(y || 0);
|
||||
$id("selected_x").value = (x || 0);
|
||||
$id("selected_y").value = (y || 0);
|
||||
$id("xy_panel").style.display = 'block';
|
||||
}
|
||||
|
||||
@@ -242,32 +242,31 @@ class TopPanel {
|
||||
].includes(elname)
|
||||
? "none"
|
||||
: "block";
|
||||
$id("tool_reorient").style.display =
|
||||
elname === "path" ? "block" : "none";
|
||||
$id("tool_reorient").disabled = angle === 0;
|
||||
$id("tool_reorient").style.display = (elname === "path") ? "block" : "none";
|
||||
$id("tool_reorient").disabled = (angle === 0);
|
||||
} else {
|
||||
const point = this.path.getNodePoint();
|
||||
$("#tool_add_subpath").pressed = false;
|
||||
$("#tool_node_delete").toggleClass(
|
||||
"disabled",
|
||||
!this.path.canDeleteNodes
|
||||
);
|
||||
$id("tool_add_subpath").pressed = false;
|
||||
// eslint-disable-next-line max-len
|
||||
(!this.path.canDeleteNodes) ? $id("tool_node_delete").classList.add("disabled") : $id("tool_node_delete").classList.remove("disabled");
|
||||
|
||||
// Show open/close button based on selected point
|
||||
// setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path');
|
||||
|
||||
if (point) {
|
||||
const segType = $("#seg_type");
|
||||
const segType = $id("seg_type");
|
||||
if (unit) {
|
||||
point.x = convertUnit(point.x);
|
||||
point.y = convertUnit(point.y);
|
||||
}
|
||||
$("#path_node_x").val(point.x);
|
||||
$("#path_node_y").val(point.y);
|
||||
$id("path_node_x").value = (point.x);
|
||||
$id("path_node_y").value = (point.y);
|
||||
if (point.type) {
|
||||
segType.val(point.type).removeAttr("disabled");
|
||||
segType.value = (point.type);
|
||||
segType.removeAttribute("disabled");
|
||||
} else {
|
||||
segType.val(4).attr("disabled", "disabled");
|
||||
segType.value = 4;
|
||||
segType.setAttribute("disabled", "disabled");
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -288,23 +287,23 @@ class TopPanel {
|
||||
|
||||
const { tagName } = elem;
|
||||
|
||||
// if ($(elem).data('gsvg')) {
|
||||
// $('#g_panel').show();
|
||||
// }
|
||||
|
||||
let linkHref = null;
|
||||
if (tagName === "a") {
|
||||
linkHref = this.editor.svgCanvas.getHref(elem);
|
||||
$id("g_panel").style.display = 'block';
|
||||
}
|
||||
|
||||
if (elem.parentNode.tagName === "a" && !$(elem).siblings().length) {
|
||||
// siblings
|
||||
const selements = Array.prototype.filter.call(elem.parentNode.children, function(child){
|
||||
return child !== elem;
|
||||
});
|
||||
if (elem.parentNode.tagName === "a" && !selements.length) {
|
||||
$id("a_panel").style.display = 'block';
|
||||
linkHref = this.editor.svgCanvas.getHref(elem.parentNode);
|
||||
}
|
||||
|
||||
// Hide/show the make_link buttons
|
||||
$("#tool_make_link, #tool_make_link_multi").toggle(!linkHref);
|
||||
$id('tool_make_link').style.display = (!linkHref) ? 'block' : 'none';
|
||||
$id('tool_make_link_multi').style.display = (!linkHref) ? 'block' : 'none';
|
||||
|
||||
if (linkHref) {
|
||||
$id("link_url").value = linkHref;
|
||||
@@ -353,9 +352,8 @@ class TopPanel {
|
||||
if (this.editor.svgCanvas.addedNew) {
|
||||
// Timeout needed for IE9
|
||||
setTimeout(() => {
|
||||
$("#text")
|
||||
.focus()
|
||||
.select();
|
||||
$id("text").focus()
|
||||
$id("text").select();
|
||||
}, 100);
|
||||
}
|
||||
// text
|
||||
@@ -370,10 +368,10 @@ class TopPanel {
|
||||
} else if (tagName === "g" || tagName === "use") {
|
||||
$id("container_panel").style.display = 'block';
|
||||
const title = this.editor.svgCanvas.getTitle();
|
||||
const label = $("#g_title")[0];
|
||||
const label = $id("g_title");
|
||||
label.value = title;
|
||||
setInputWidth(label);
|
||||
$("#g_title").prop("disabled", tagName === "use");
|
||||
$id("g_title").disabled = (tagName === "use");
|
||||
}
|
||||
}
|
||||
menuItems.setAttribute(
|
||||
@@ -408,9 +406,8 @@ class TopPanel {
|
||||
|
||||
if ((elem && !isNode) || this.multiselected) {
|
||||
// update the selected elements' layer
|
||||
$("#selLayerNames")
|
||||
.removeAttr("disabled")
|
||||
.val(currentLayerName);
|
||||
$id("selLayerNames").removeAttribute("disabled")
|
||||
$id("selLayerNames").value = currentLayerName;
|
||||
|
||||
// Enable regular menu options
|
||||
const canCMenu = document.getElementById("se-cmenu_canvas");
|
||||
@@ -419,7 +416,7 @@ class TopPanel {
|
||||
"#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back"
|
||||
);
|
||||
} else {
|
||||
$("#selLayerNames").attr("disabled", "disabled");
|
||||
$id("selLayerNames").disabled = "disabled";
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -444,13 +441,14 @@ class TopPanel {
|
||||
$id("tool_wireframe").pressed = !$id("tool_wireframe").pressed;
|
||||
this.editor.workarea.classList.toggle("wireframe");
|
||||
|
||||
const wfRules = $("#wireframe_rules");
|
||||
if (!wfRules.length) {
|
||||
/* wfRules = */ $('<style id="wireframe_rules"></style>').appendTo(
|
||||
"head"
|
||||
);
|
||||
const wfRules = $id("wireframe_rules");
|
||||
if (!wfRules) {
|
||||
const fcRules = document.createElement('style');
|
||||
fcRules.setAttribute('id', 'wireframe_rules');
|
||||
document.getElementsByTagName("head")[0].appendChild(fcRules);
|
||||
} else {
|
||||
wfRules.empty();
|
||||
while(wfRules.firstChild)
|
||||
wfRules.removeChild(wfRules.firstChild);
|
||||
}
|
||||
this.editor.updateWireFrame();
|
||||
}
|
||||
@@ -496,10 +494,8 @@ class TopPanel {
|
||||
*/
|
||||
changeRotationAngle(e) {
|
||||
this.editor.svgCanvas.setRotationAngle(e.target.value);
|
||||
$("#tool_reorient").toggleClass(
|
||||
"disabled",
|
||||
Number.parseInt(e.target.value) === 0
|
||||
);
|
||||
// eslint-disable-next-line max-len
|
||||
(Number.parseInt(e.target.value) === 0) ? $id("tool_reorient").classList.add("disabled") : $id("tool_reorient").classList.remove("disabled");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,7 +540,7 @@ class TopPanel {
|
||||
* @returns {void}
|
||||
*/
|
||||
clickAlign(pos) {
|
||||
let value = $("#tool_align_relative").val();
|
||||
let value = $id("tool_align_relative").value;
|
||||
if (value === "") {
|
||||
value = "selected";
|
||||
}
|
||||
@@ -666,8 +662,8 @@ class TopPanel {
|
||||
* @returns {void}
|
||||
*/
|
||||
addSubPath() {
|
||||
const button = $("#tool_add_subpath");
|
||||
const sp = !button.hasClass("pressed");
|
||||
const button = $id("tool_add_subpath");
|
||||
const sp = !button.classList.contains("pressed");
|
||||
button.pressed = sp;
|
||||
// button.toggleClass('push_button_pressed tool_button');
|
||||
this.path.addSubPath(sp);
|
||||
@@ -752,7 +748,6 @@ class TopPanel {
|
||||
<div class="tool_sep"></div>
|
||||
<se-button id="tool_source" title="Edit Source" shortcut="U" src="./images/source.svg"></se-button>
|
||||
<se-button id="tool_wireframe" title="Wireframe Mode" shortcut="F" src="./images/wireframe.svg"></se-button>
|
||||
<se-button id="view_grid" title="Show grid" src="./images/grid.svg"></se-button>
|
||||
</div> <!-- editor_panel -->
|
||||
<div id="history_panel">
|
||||
<div class="tool_sep"></div>
|
||||
|
||||
@@ -24,20 +24,23 @@ export const init = function (clearContext) {
|
||||
export const clearSvgContentElementInit = function () {
|
||||
const curConfig = clearContext_.getCurConfig();
|
||||
const {dimensions} = curConfig;
|
||||
$(clearContext_.getSVGContent()).empty();
|
||||
const el = clearContext_.getSVGContent();
|
||||
// empty()
|
||||
while(el.firstChild)
|
||||
el.removeChild(el.firstChild);
|
||||
|
||||
// TODO: Clear out all other attributes first?
|
||||
$(clearContext_.getSVGContent()).attr({
|
||||
id: 'svgcontent',
|
||||
width: dimensions[0],
|
||||
height: dimensions[1],
|
||||
x: dimensions[0],
|
||||
y: dimensions[1],
|
||||
overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden',
|
||||
xmlns: NS.SVG,
|
||||
'xmlns:se': NS.SE,
|
||||
'xmlns:xlink': NS.XLINK
|
||||
}).appendTo(clearContext_.getSVGRoot());
|
||||
const pel = clearContext_.getSVGRoot();
|
||||
el.setAttribute('id', 'svgcontent');
|
||||
el.setAttribute('width', dimensions[0]);
|
||||
el.setAttribute('height', dimensions[1]);
|
||||
el.setAttribute('x', dimensions[0]);
|
||||
el.setAttribute('y', dimensions[1]);
|
||||
el.setAttribute('overflow', curConfig.show_outside_canvas ? 'visible' : 'hidden');
|
||||
el.setAttribute('xmlns', NS.SVG);
|
||||
el.setAttribute('xmlns:se', NS.SE);
|
||||
el.setAttribute('xmlns:xlink', NS.XLINK);
|
||||
pel.appendChild(el);
|
||||
|
||||
// TODO: make this string optional and set by the client
|
||||
const comment = clearContext_.getDOMDocument().createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit');
|
||||
|
||||
@@ -176,7 +176,7 @@ export const remapElement = function (selected, changes, m) {
|
||||
finishUp();
|
||||
break;
|
||||
} case 'g': {
|
||||
const gsvg = $(selected).data('gsvg');
|
||||
const gsvg = dataStorage.get(selected, 'gsvg');
|
||||
if (gsvg) {
|
||||
assignAttributes(gsvg, changes, 1000, true);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
/* globals jQuery */
|
||||
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import {isWebkit} from '../common/browser.js';
|
||||
import {convertPath} from './path.js';
|
||||
import {preventClickDefault} from './utilities.js';
|
||||
|
||||
// Constants
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
/**
|
||||
* Create a clone of an element, updating its ID and its children's IDs when needed.
|
||||
* @function module:utilities.copyElem
|
||||
@@ -18,10 +12,8 @@ const $ = jQueryPluginSVG(jQuery);
|
||||
export const copyElem = function (el, getNextId) {
|
||||
// manually create a copy of the element
|
||||
const newEl = document.createElementNS(el.namespaceURI, el.nodeName);
|
||||
$.each(el.attributes, function (i, attr) {
|
||||
if (attr.localName !== '-moz-math-font-style') {
|
||||
Object.values(el.attributes).forEach((attr) => {
|
||||
newEl.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value);
|
||||
}
|
||||
});
|
||||
// set the copied element's new id
|
||||
newEl.removeAttribute('id');
|
||||
@@ -35,7 +27,7 @@ export const copyElem = function (el, getNextId) {
|
||||
}
|
||||
|
||||
// now create copies of all children
|
||||
$.each(el.childNodes, function (i, child) {
|
||||
el.childNodes.forEach(function(child, i){
|
||||
switch (child.nodeType) {
|
||||
case 1: // element node
|
||||
newEl.append(copyElem(child, getNextId));
|
||||
@@ -48,11 +40,12 @@ export const copyElem = function (el, getNextId) {
|
||||
}
|
||||
});
|
||||
|
||||
if ($(el).data('gsvg')) {
|
||||
$(newEl).data('gsvg', newEl.firstChild);
|
||||
} else if ($(el).data('symbol')) {
|
||||
const ref = $(el).data('symbol');
|
||||
$(newEl).data('ref', ref).data('symbol', ref);
|
||||
if (el.dataset.gsvg) {
|
||||
newEl.dataset.gsvg = newEl.firstChild
|
||||
} else if (el.dataset.symbol) {
|
||||
const ref = el.dataset.symbol;
|
||||
newEl.dataset.ref = ref;
|
||||
newEl.dataset.symbol = ref;
|
||||
} else if (newEl.tagName === 'image') {
|
||||
preventClickDefault(newEl);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import {
|
||||
BatchCommand, RemoveElementCommand, MoveElementCommand, ChangeElementCommand
|
||||
} from './history.js';
|
||||
import {getParentsUntil} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
@@ -49,10 +50,10 @@ function historyRecordingService (hrService) {
|
||||
* @returns {string} The layer name or empty string.
|
||||
*/
|
||||
function findLayerNameInGroup (group) {
|
||||
return $('title', group).text() ||
|
||||
return group.querySelector('title').textContent ||
|
||||
(isOpera() && group.querySelectorAll
|
||||
// Hack for Opera 10.60
|
||||
? $(group.querySelectorAll('title')).text()
|
||||
? group.querySelector('title').textContent
|
||||
: '');
|
||||
}
|
||||
|
||||
@@ -158,7 +159,7 @@ export class Drawing {
|
||||
return this.svgElem_.querySelector('#' + id);
|
||||
}
|
||||
// jQuery lookup: twice as slow as xpath in FF
|
||||
return $(this.svgElem_).find('[id=' + id + ']')[0];
|
||||
return this.svgElem_.querySelector('[id=' + id + ']');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +392,7 @@ export class Drawing {
|
||||
*/
|
||||
mergeLayer (hrService) {
|
||||
const currentGroup = this.current_layer.getGroup();
|
||||
const prevGroup = $(currentGroup).prev()[0];
|
||||
const prevGroup = currentGroup.previousElementSibling;
|
||||
if (!prevGroup) { return; }
|
||||
|
||||
hrService.startBatchCommand('Merge Layer');
|
||||
@@ -710,7 +711,6 @@ export const randomizeIds = function (enableRandomization, currentDrawing) {
|
||||
/**
|
||||
* @interface module:draw.DrawCanvasInit
|
||||
* @property {module:path.pathActions} pathActions
|
||||
* @property {external:jQuery.data} elData
|
||||
* @property {module:history.UndoManager} undoMgr
|
||||
*/
|
||||
/**
|
||||
@@ -992,7 +992,7 @@ export const leaveContext = function () {
|
||||
if (len) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const elem = disabledElems[i];
|
||||
const orig = canvas_.elData(elem, 'orig_opac');
|
||||
const orig = dataStorage.get(elem, 'orig_opac');
|
||||
if (orig !== 1) {
|
||||
elem.setAttribute('opacity', orig);
|
||||
} else {
|
||||
@@ -1024,15 +1024,25 @@ export const setContext = function (elem) {
|
||||
canvas_.setCurrentGroup(elem);
|
||||
|
||||
// Disable other elements
|
||||
$(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function () {
|
||||
const opac = this.getAttribute('opacity') || 1;
|
||||
// Store the original's opacity
|
||||
canvas_.elData(this, 'orig_opac', opac);
|
||||
this.setAttribute('opacity', opac * 0.33);
|
||||
this.setAttribute('style', 'pointer-events: none');
|
||||
disabledElems.push(this);
|
||||
const parentsUntil = getParentsUntil(elem, '#svgcontent');
|
||||
let siblings = [];
|
||||
parentsUntil.forEach(function (parent) {
|
||||
const elements = Array.prototype.filter.call(parent.parentNode.children, function(child){
|
||||
return child !== parent;
|
||||
});
|
||||
elements.forEach(function (element) {
|
||||
siblings.push(element);
|
||||
});
|
||||
});
|
||||
|
||||
siblings.forEach(function (curthis) {
|
||||
const opac = curthis.getAttribute('opacity') || 1;
|
||||
// Store the original's opacity
|
||||
dataStorage.put(curthis, 'orig_opac', opac);
|
||||
curthis.setAttribute('opacity', opac * 0.33);
|
||||
curthis.setAttribute('style', 'pointer-events: none');
|
||||
disabledElems.push(curthis);
|
||||
});
|
||||
canvas_.clearSelection();
|
||||
canvas_.call('contextset', canvas_.getCurrentGroup());
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import {
|
||||
convertToNum
|
||||
} from '../common/units.js';
|
||||
import {getParents} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
@@ -62,7 +63,11 @@ export const getTitleMethod = function (elem) {
|
||||
const selectedElements = elemContext_.getSelectedElements();
|
||||
elem = elem || selectedElements[0];
|
||||
if (!elem) { return undefined; }
|
||||
elem = $(elem).data('gsvg') || $(elem).data('symbol') || elem;
|
||||
if(dataStorage.has(elem, 'gsvg')){
|
||||
elem = dataStorage.get(elem, 'gsvg');
|
||||
} else if(dataStorage.has(elem, 'symbol')) {
|
||||
elem = dataStorage.get(elem, 'symbol');
|
||||
}
|
||||
const childs = elem.childNodes;
|
||||
for (const child of childs) {
|
||||
if (child.nodeName === 'title') {
|
||||
@@ -82,9 +87,11 @@ export const getTitleMethod = function (elem) {
|
||||
export const setGroupTitleMethod = function (val) {
|
||||
const selectedElements = elemContext_.getSelectedElements();
|
||||
let elem = selectedElements[0];
|
||||
elem = $(elem).data('gsvg') || elem;
|
||||
if(dataStorage.has(elem, 'gsvg')){
|
||||
elem = dataStorage.get(elem, 'gsvg');
|
||||
}
|
||||
|
||||
const ts = $(elem).children('title');
|
||||
const ts = elem.querySelectorAll('title');
|
||||
|
||||
const batchCmd = new BatchCommand('Set Label');
|
||||
|
||||
@@ -103,7 +110,7 @@ export const setGroupTitleMethod = function (val) {
|
||||
// Add title element
|
||||
title = elemContext_.getDOMDocument().createElementNS(NS.SVG, 'title');
|
||||
title.textContent = val;
|
||||
$(elem).prepend(title);
|
||||
elem.insertBefore(title, elem.firstChild);
|
||||
batchCmd.addSubCommand(new InsertElementCommand(title));
|
||||
}
|
||||
|
||||
@@ -392,7 +399,7 @@ export const setGradientMethod = function (type) {
|
||||
*/
|
||||
export const findDuplicateGradient = function (grad) {
|
||||
const defs = findDefs();
|
||||
const existingGrads = $(defs).find('linearGradient, radialGradient');
|
||||
const existingGrads = defs.querySelectorAll('linearGradient, radialGradient');
|
||||
let i = existingGrads.length;
|
||||
const radAttrs = ['r', 'cx', 'cy', 'fx', 'fy'];
|
||||
while (i--) {
|
||||
@@ -406,11 +413,23 @@ export const findDuplicateGradient = function (grad) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
const gradAttrs = $(grad).attr(radAttrs);
|
||||
const ogAttrs = $(og).attr(radAttrs);
|
||||
const gradAttrs = {
|
||||
r: grad.getAttribute('r'),
|
||||
cx: grad.getAttribute('cx'),
|
||||
cy: grad.getAttribute('cy'),
|
||||
fx: grad.getAttribute('fx'),
|
||||
fy: grad.getAttribute('fy')
|
||||
};
|
||||
const ogAttrs = {
|
||||
r: og.getAttribute('r'),
|
||||
cx: og.getAttribute('cx'),
|
||||
cy: og.getAttribute('cy'),
|
||||
fx: og.getAttribute('fx'),
|
||||
fy: og.getAttribute('fy')
|
||||
};
|
||||
|
||||
let diff = false;
|
||||
$.each(radAttrs, function (j, attr) {
|
||||
radAttrs.forEach(function(attr, j){
|
||||
if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true; }
|
||||
});
|
||||
|
||||
@@ -728,7 +747,10 @@ export const setImageURLMethod = function (val) {
|
||||
const elem = selectedElements[0];
|
||||
if (!elem) { return; }
|
||||
|
||||
const attrs = $(elem).attr(['width', 'height']);
|
||||
const attrs = {
|
||||
width: elem.getAttribute('width'),
|
||||
height: elem.getAttribute('height'),
|
||||
};
|
||||
const setsize = (!attrs.width || !attrs.height);
|
||||
|
||||
const curHref = getHref(elem);
|
||||
@@ -744,21 +766,22 @@ export const setImageURLMethod = function (val) {
|
||||
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
|
||||
'#href': curHref
|
||||
}));
|
||||
|
||||
$(new Image()).load(function () {
|
||||
const changes = $(elem).attr(['width', 'height']);
|
||||
|
||||
$(elem).attr({
|
||||
width: this.width,
|
||||
height: this.height
|
||||
});
|
||||
const img = new Image();
|
||||
img.onload = function() {
|
||||
const changes = {
|
||||
width: elem.getAttribute('width'),
|
||||
height: elem.getAttribute('height'),
|
||||
};
|
||||
elem.setAttribute('width', this.width);
|
||||
elem.setAttribute('height', this.height);
|
||||
|
||||
elemContext_.getCanvas().selectorManager.requestSelector(elem).resize();
|
||||
|
||||
batchCmd.addSubCommand(new ChangeElementCommand(elem, changes));
|
||||
elemContext_.addCommandToHistory(batchCmd);
|
||||
elemContext_.call('changed', [elem]);
|
||||
}).attr('src', val);
|
||||
};
|
||||
img.src = val;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -773,7 +796,7 @@ export const setLinkURLMethod = function (val) {
|
||||
if (!elem) { return; }
|
||||
if (elem.tagName !== 'a') {
|
||||
// See if parent is an anchor
|
||||
const parentsA = $(elem).parents('a');
|
||||
const parentsA = getParents(elem.parentNode, 'a');
|
||||
if (parentsA.length) {
|
||||
elem = parentsA[0];
|
||||
} else {
|
||||
@@ -861,7 +884,7 @@ export const setSegTypeMethod = function (newType) {
|
||||
*/
|
||||
export const setBackgroundMethod = function (color, url) {
|
||||
const bg = getElem('canvasBackground');
|
||||
const border = $(bg).find('rect')[0];
|
||||
const border = bg.querySelector('rect');
|
||||
let bgImg = getElem('background_image');
|
||||
let bgPattern = getElem('background_pattern');
|
||||
border.setAttribute('fill', color === 'chessboard' ? '#fff' : color);
|
||||
|
||||
@@ -363,8 +363,8 @@ export const mouseMoveEvent = function (evt) {
|
||||
|
||||
break;
|
||||
} case 'circle': {
|
||||
c = $(shape).attr(['cx', 'cy']);
|
||||
({cx, cy} = c);
|
||||
cx = shape.getAttribute('cx');
|
||||
cy = shape.getAttribute('cy');
|
||||
let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
|
||||
if (eventContext_.getCurConfig().gridSnapping) {
|
||||
rad = snapToGrid(rad);
|
||||
@@ -372,8 +372,8 @@ export const mouseMoveEvent = function (evt) {
|
||||
shape.setAttribute('r', rad);
|
||||
break;
|
||||
} case 'ellipse': {
|
||||
c = $(shape).attr(['cx', 'cy']);
|
||||
({cx, cy} = c);
|
||||
cx = shape.getAttribute('cx');
|
||||
cy = shape.getAttribute('cy');
|
||||
if (eventContext_.getCurConfig().gridSnapping) {
|
||||
x = snapToGrid(x);
|
||||
cx = snapToGrid(cx);
|
||||
@@ -672,23 +672,28 @@ export const mouseUpEvent = function (evt) {
|
||||
}
|
||||
break;
|
||||
} case 'line':
|
||||
attrs = $(element).attr(['x1', 'x2', 'y1', 'y2']);
|
||||
keep = (attrs.x1 !== attrs.x2 || attrs.y1 !== attrs.y2);
|
||||
const x1 = element.getAttribute('x1');
|
||||
const y1 = element.getAttribute('y1');
|
||||
const x2 = element.getAttribute('x2');
|
||||
const y2 = element.getAttribute('y2');
|
||||
keep = (x1 !== x2 || y1 !== y2);
|
||||
break;
|
||||
case 'foreignObject':
|
||||
case 'square':
|
||||
case 'rect':
|
||||
case 'image':
|
||||
attrs = $(element).attr(['width', 'height']);
|
||||
const width = element.getAttribute('width');
|
||||
const height = element.getAttribute('height');
|
||||
// Image should be kept regardless of size (use inherit dimensions later)
|
||||
keep = (attrs.width || attrs.height) || eventContext_.getCurrentMode() === 'image';
|
||||
keep = (width || height) || eventContext_.getCurrentMode() === 'image';
|
||||
break;
|
||||
case 'circle':
|
||||
keep = (element.getAttribute('r') !== '0');
|
||||
break;
|
||||
case 'ellipse':
|
||||
attrs = $(element).attr(['rx', 'ry']);
|
||||
keep = (attrs.rx || attrs.ry);
|
||||
const rx = element.getAttribute('rx');
|
||||
const ry = element.getAttribute('ry');
|
||||
keep = (rx || ry);
|
||||
break;
|
||||
case 'fhellipse':
|
||||
if ((eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) > 0 &&
|
||||
@@ -829,13 +834,13 @@ t.id !== 'svgcanvas' && t.id !== 'svgroot'
|
||||
const curShape = eventContext_.getCanvas().getStyle();
|
||||
const opacAni = eventContext_.getOpacAni();
|
||||
if (opacAni.beginElement && Number.parseFloat(element.getAttribute('opacity')) !== curShape.opacity) {
|
||||
cAni = $(opacAni).clone().attr({
|
||||
to: curShape.opacity,
|
||||
dur: aniDur
|
||||
}).appendTo(element);
|
||||
cAni = opacAni.cloneNode(true);
|
||||
cAni.setAttribute('to', curShape.opacity);
|
||||
cAni.setAttribute('dur', aniDur);
|
||||
element.appendChild(cAni);
|
||||
try {
|
||||
// Fails in FF4 on foreignObject
|
||||
cAni[0].beginElement();
|
||||
cAni.beginElement();
|
||||
} catch (e) {/* empty fn */}
|
||||
} else {
|
||||
aniDur = 0;
|
||||
@@ -916,6 +921,8 @@ export const mouseDownEvent = function (evt) {
|
||||
const selectedElements = eventContext_.getSelectedElements();
|
||||
const currentZoom = eventContext_.getCurrentZoom();
|
||||
const curShape = eventContext_.getCanvas().getStyle();
|
||||
const svgCanvas = eventContext_.getCanvas();
|
||||
const {$id} = svgCanvas;
|
||||
if (eventContext_.getCanvas().spaceKey || evt.button === 1) { return; }
|
||||
|
||||
const rightClick = evt.button === 2;
|
||||
@@ -924,7 +931,7 @@ export const mouseDownEvent = function (evt) {
|
||||
eventContext_.getCanvas().cloneSelectedElements(0, 0);
|
||||
}
|
||||
|
||||
eventContext_.setRootSctm($('#svgcontent g')[0].getScreenCTM().inverse());
|
||||
eventContext_.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse());
|
||||
|
||||
const pt = transformPoint(evt.pageX, evt.pageY, eventContext_.getrootSctm()),
|
||||
mouseX = pt.x * currentZoom,
|
||||
@@ -937,11 +944,6 @@ export const mouseDownEvent = function (evt) {
|
||||
eventContext_.setLastClickPoint(pt);
|
||||
}
|
||||
|
||||
// This would seem to be unnecessary...
|
||||
// if (!['select', 'resize'].includes(currentMode)) {
|
||||
// setGradient();
|
||||
// }
|
||||
|
||||
let x = mouseX / currentZoom,
|
||||
y = mouseY / currentZoom;
|
||||
let mouseTarget = eventContext_.getCanvas().getMouseTarget(evt);
|
||||
@@ -970,14 +972,14 @@ export const mouseDownEvent = function (evt) {
|
||||
|
||||
if (mouseTarget === eventContext_.getCanvas().selectorManager.selectorParentGroup && !isNullish(selectedElements[0])) {
|
||||
const grip = evt.target;
|
||||
const griptype = eventContext_.elData(grip, 'type');
|
||||
const griptype = dataStorage.get(grip, 'type');
|
||||
// rotating
|
||||
if (griptype === 'rotate') {
|
||||
eventContext_.setCurrentMode('rotate');
|
||||
// resizing
|
||||
} else if (griptype === 'resize') {
|
||||
eventContext_.setCurrentMode('resize');
|
||||
eventContext_.setCurrentResizeMode(eventContext_.elData(grip, 'dir'));
|
||||
eventContext_.setCurrentResizeMode(dataStorage.get(grip, 'dir'));
|
||||
}
|
||||
mouseTarget = selectedElements[0];
|
||||
}
|
||||
@@ -1027,10 +1029,6 @@ export const mouseDownEvent = function (evt) {
|
||||
}
|
||||
eventContext_.setRStartX(eventContext_.getRStartX() * currentZoom);
|
||||
eventContext_.setRStartY(eventContext_.getRStartY() * currentZoom);
|
||||
// console.log('p',[evt.pageX, evt.pageY]);
|
||||
// console.log('c',[evt.clientX, evt.clientY]);
|
||||
// console.log('o',[evt.offsetX, evt.offsetY]);
|
||||
// console.log('s',[startX, startY]);
|
||||
|
||||
assignAttributes(eventContext_.getRubberBox(), {
|
||||
x: eventContext_.getRStartX(),
|
||||
@@ -1061,7 +1059,7 @@ export const mouseDownEvent = function (evt) {
|
||||
|
||||
// Getting the BBox from the selection box, since we know we
|
||||
// want to orient around it
|
||||
eventContext_.setInitBbox(utilsGetBBox($('#selectedBox0')[0]));
|
||||
eventContext_.setInitBbox(utilsGetBBox($id('selectedBox0')));
|
||||
const bb = {};
|
||||
$.each(eventContext_.getInitBbox(), function (key, val) {
|
||||
bb[key] = val / currentZoom;
|
||||
@@ -1307,12 +1305,14 @@ export const mouseDownEvent = function (evt) {
|
||||
*/
|
||||
export const DOMMouseScrollEvent = function (e) {
|
||||
const currentZoom = eventContext_.getCurrentZoom();
|
||||
const svgCanvas = eventContext_.getCanvas();
|
||||
const {$id} = svgCanvas;
|
||||
if (!e.shiftKey) { return; }
|
||||
|
||||
e.preventDefault();
|
||||
const evt = e.originalEvent;
|
||||
|
||||
eventContext_.setRootSctm($('#svgcontent g')[0].getScreenCTM().inverse());
|
||||
eventContext_.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse());
|
||||
|
||||
const workarea = document.getElementById('workarea');
|
||||
const scrbar = 15;
|
||||
|
||||
@@ -44,7 +44,7 @@ class Layer {
|
||||
layerTitle.textContent = name;
|
||||
this.group_.append(layerTitle);
|
||||
if (group) {
|
||||
$(group).after(this.group_);
|
||||
group.insertAdjacentElement('afterend', this.group_);
|
||||
} else {
|
||||
svgElem.append(this.group_);
|
||||
}
|
||||
@@ -172,7 +172,8 @@ class Layer {
|
||||
// now change the underlying title element contents
|
||||
const title = this.getTitleElement();
|
||||
if (title) {
|
||||
$(title).empty();
|
||||
while(title.firstChild)
|
||||
title.removeChild(title.firstChild);
|
||||
title.textContent = name;
|
||||
this.name_ = name;
|
||||
if (hrService) {
|
||||
|
||||
@@ -434,7 +434,7 @@ export const pathActionsMethod = (function () {
|
||||
keep = false;
|
||||
return keep;
|
||||
}
|
||||
$(stretchy).remove();
|
||||
stretchy.remove();
|
||||
|
||||
// This will signal to commit the path
|
||||
// const element = newpath; // Other event handlers define own `element`, so this was probably not meant to interact with them or one which shares state (as there were none); I therefore adding a missing `var` to avoid a global
|
||||
@@ -447,9 +447,9 @@ export const pathActionsMethod = (function () {
|
||||
}
|
||||
|
||||
const newD = newpath.getAttribute('d');
|
||||
const origD = $(path.elem).attr('d');
|
||||
$(path.elem).attr('d', origD + newD);
|
||||
$(newpath).remove();
|
||||
const origD = path.elem.getAttribute('d');
|
||||
path.elem.setAttribute('d', origD + newD);
|
||||
newpath.parentNode.removeChild(el);
|
||||
if (path.matrix) {
|
||||
pathActionsContext_.recalcRotatedPath();
|
||||
}
|
||||
@@ -865,9 +865,14 @@ export const pathActionsMethod = (function () {
|
||||
currentPath = null;
|
||||
if (drawnPath) {
|
||||
const elem = getElem(editorContext_.getId());
|
||||
$(getElem('path_stretch_line')).remove();
|
||||
$(elem).remove();
|
||||
$(getElem('pathpointgrip_container')).find('*').attr('display', 'none');
|
||||
const psl = getElem('path_stretch_line');
|
||||
psl.parentNode.removeChild(psl);
|
||||
elem.parentNode.removeChild(elem);
|
||||
const pathpointgripContainer = getElem('pathpointgrip_container');
|
||||
const elements = pathpointgripContainer.querySelectorAll('*');
|
||||
Array.prototype.forEach.call(elements, function(el, i){
|
||||
el.style.display = 'none';
|
||||
});
|
||||
firstCtrl = null;
|
||||
editorContext_.setDrawnPath(null);
|
||||
editorContext_.setStarted(false);
|
||||
@@ -1165,8 +1170,7 @@ export const pathActionsMethod = (function () {
|
||||
// TODO: Find right way to select point now
|
||||
// path.selectPt(selPt);
|
||||
if (window.opera) { // Opera repaints incorrectly
|
||||
const cp = $(path.elem);
|
||||
cp.attr('d', cp.attr('d'));
|
||||
path.elem.setAttribute('d', path.elem.getAttribute('d'));
|
||||
}
|
||||
path.endChanges('Delete path node(s)');
|
||||
},
|
||||
|
||||
@@ -174,8 +174,8 @@ export const addPointGripMethod = function (index, x, y) {
|
||||
assignAttributes(pointGrip, atts);
|
||||
pointGripContainer.append(pointGrip);
|
||||
|
||||
const grip = $('#pathpointgrip_' + index);
|
||||
grip.dblclick(function () {
|
||||
const grip = document.getElementById('pathpointgrip_' + index);
|
||||
grip.addEventListener("dblclick", (e) => {
|
||||
const path = pathMethodsContext_.getPathObj();
|
||||
if (path) {
|
||||
path.setSegType();
|
||||
@@ -429,8 +429,8 @@ export class Segment {
|
||||
* @returns {void}
|
||||
*/
|
||||
selectCtrls (y) {
|
||||
$('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2')
|
||||
.attr('fill', y ? '#0FF' : '#EEE');
|
||||
document.getElementById('ctrlpointgrip_' + this.index + 'c1').setAttribute('fill', y ? '#0FF' : '#EEE');
|
||||
document.getElementById('ctrlpointgrip_' + this.index + 'c2').setAttribute('fill', y ? '#0FF' : '#EEE')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -638,8 +638,10 @@ export class Path {
|
||||
// Hide all grips, etc
|
||||
|
||||
// fixed, needed to work on all found elements, not just first
|
||||
$(getGripContainerMethod()).find('*').each(function () {
|
||||
$(this).attr('display', 'none');
|
||||
const pointGripContainer = getGripContainerMethod();
|
||||
const elements = pointGripContainer.querySelectorAll('*');
|
||||
Array.prototype.forEach.call(elements, function(el, i){
|
||||
el.style.display = 'none';
|
||||
});
|
||||
|
||||
const segList = this.elem.pathSegList;
|
||||
|
||||
@@ -581,8 +581,9 @@ export const reorientGrads = function (elem, m) {
|
||||
};
|
||||
|
||||
const newgrad = grad.cloneNode(true);
|
||||
$(newgrad).attr(gCoords);
|
||||
|
||||
for (const [key, value] of Object.entries(gCoords)) {
|
||||
newgrad.setAttribute(key, value);
|
||||
}
|
||||
newgrad.id = editorContext_.getNextId();
|
||||
findDefs().append(newgrad);
|
||||
elem.setAttribute(type, 'url(#' + newgrad.id + ')');
|
||||
|
||||
@@ -177,8 +177,7 @@ export const recalculateDimensions = function (selected) {
|
||||
}
|
||||
|
||||
// Grouped SVG element
|
||||
const gsvg = $(selected).data('gsvg');
|
||||
|
||||
const gsvg = (dataStorage.has(selected, 'gsvg')) ? dataStorage.get(selected, 'gsvg') : undefined;
|
||||
// we know we have some transforms, so set up return variable
|
||||
const batchCmd = new BatchCommand('Transform');
|
||||
|
||||
@@ -226,15 +225,17 @@ export const recalculateDimensions = function (selected) {
|
||||
} // switch on element type to get initial values
|
||||
|
||||
if (attrs.length) {
|
||||
changes = $(selected).attr(attrs);
|
||||
$.each(changes, function (attr, val) {
|
||||
changes[attr] = convertToNum(attr, val);
|
||||
Array.prototype.forEach.call(attrs, function(attr, i){
|
||||
changes[attr] = selected.getAttribute(attr);
|
||||
});
|
||||
for (const [attr, val] of Object.entries(changes)) {
|
||||
changes[attr] = convertToNum(attr, val);
|
||||
}
|
||||
} else if (gsvg) {
|
||||
// GSVG exception
|
||||
changes = {
|
||||
x: $(gsvg).attr('x') || 0,
|
||||
y: $(gsvg).attr('y') || 0
|
||||
x: gsvg.getAttribute('x') || 0,
|
||||
y: gsvg.getAttribute('y') || 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -242,9 +243,9 @@ export const recalculateDimensions = function (selected) {
|
||||
// make a copy of initial values and include the transform
|
||||
if (isNullish(initial)) {
|
||||
initial = $.extend(true, {}, changes);
|
||||
$.each(initial, function (attr, val) {
|
||||
for (const [attr, val] of Object.entries(initial)) {
|
||||
initial[attr] = convertToNum(attr, val);
|
||||
});
|
||||
}
|
||||
}
|
||||
// save the start transform value too
|
||||
initial.transform = context_.getStartTransform() || '';
|
||||
@@ -701,7 +702,12 @@ export const recalculateDimensions = function (selected) {
|
||||
m = transformListToTransform(tlist).matrix;
|
||||
switch (selected.tagName) {
|
||||
case 'line':
|
||||
changes = $(selected).attr(['x1', 'y1', 'x2', 'y2']);
|
||||
changes = {
|
||||
x1: selected.getAttribute('x1'),
|
||||
y1: selected.getAttribute('y1'),
|
||||
x2: selected.getAttribute('x2'),
|
||||
y2: selected.getAttribute('y2'),
|
||||
}
|
||||
// Fallthrough
|
||||
case 'polyline':
|
||||
case 'polygon':
|
||||
@@ -776,8 +782,8 @@ export const recalculateDimensions = function (selected) {
|
||||
const child = children.item(c);
|
||||
if (child.tagName === 'tspan') {
|
||||
const tspanChanges = {
|
||||
x: $(child).attr('x') || 0,
|
||||
y: $(child).attr('y') || 0
|
||||
x: child.getAttribute('x') || 0,
|
||||
y: child.getAttribute('y') || 0
|
||||
};
|
||||
remapElement(child, tspanChanges, m);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,14 @@ const svgWhiteList_ = {
|
||||
style: ['type'],
|
||||
desc: [],
|
||||
ellipse: ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
|
||||
feBlend: ['in', 'in2'],
|
||||
feComposite: ['operator', 'result', 'in2'],
|
||||
feFlood: ['flood-color', 'in'],
|
||||
feGaussianBlur: ['class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation'],
|
||||
feMerge: [],
|
||||
feMergeNode: ['in'],
|
||||
feMorphology: ['class', 'in', 'operator', 'radius'],
|
||||
feOffset: ['dx', 'in', 'dy', 'result'],
|
||||
filter: ['class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
|
||||
foreignObject: ['class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y'],
|
||||
g: ['class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'],
|
||||
@@ -46,7 +52,7 @@ const svgWhiteList_ = {
|
||||
radialGradient: ['class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
|
||||
rect: ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y'],
|
||||
stop: ['class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage'],
|
||||
svg: ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y'],
|
||||
svg: ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'xmlns:oi', 'oi:animations', 'y'],
|
||||
switch: ['class', 'id', 'requiredFeatures', 'systemLanguage'],
|
||||
symbol: ['class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox'],
|
||||
text: ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y'],
|
||||
|
||||
@@ -139,7 +139,7 @@ export class Selector {
|
||||
}
|
||||
// TODO: getBBox (previous line) already knows to call getStrokedBBox when tagName === 'g'. Remove this?
|
||||
// TODO: getBBox doesn't exclude 'gsvg' and calls getStrokedBBox for any 'g'. Should getBBox be updated?
|
||||
if (tagName === 'g' && !$.data(selected, 'gsvg')) {
|
||||
if (tagName === 'g' && !dataStorage.has(selected, 'gsvg')) {
|
||||
// The bbox for a group does not include stroke vals, so we
|
||||
// get the bbox based on its children.
|
||||
const strokedBbox = getStrokedBBox([selected.childNodes]);
|
||||
@@ -339,8 +339,8 @@ export class SelectorManager {
|
||||
}
|
||||
});
|
||||
|
||||
$.data(grip, 'dir', dir);
|
||||
$.data(grip, 'type', 'resize');
|
||||
dataStorage.put(grip, 'dir', dir);
|
||||
dataStorage.put(grip, 'type', 'resize');
|
||||
this.selectorGrips[dir] = grip;
|
||||
this.selectorGripsGroup.append(grip);
|
||||
});
|
||||
@@ -370,9 +370,9 @@ export class SelectorManager {
|
||||
}
|
||||
});
|
||||
this.selectorGripsGroup.append(this.rotateGrip);
|
||||
$.data(this.rotateGrip, 'type', 'rotate');
|
||||
dataStorage.put(this.rotateGrip, 'type', 'rotate');
|
||||
|
||||
if ($('#canvasBackground').length) { return; }
|
||||
if (document.getElementById('canvasBackground')) { return; }
|
||||
|
||||
const [width, height] = config_.dimensions;
|
||||
const canvasbg = svgFactory_.createSVGElement({
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
import {
|
||||
isGecko
|
||||
} from '../common/browser.js'; // , supportsEditableText
|
||||
import {getParents} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const {
|
||||
MoveElementCommand, BatchCommand, InsertElementCommand, RemoveElementCommand, ChangeElementCommand
|
||||
@@ -115,17 +116,17 @@ export const moveUpDownSelected = function (dir) {
|
||||
// curBBoxes = [];
|
||||
let closest, foundCur;
|
||||
// jQuery sorts this list
|
||||
const list = $(elementContext_.getIntersectionList(getStrokedBBoxDefaultVisible([selected]))).toArray();
|
||||
const list = elementContext_.getIntersectionList(getStrokedBBoxDefaultVisible([selected]));
|
||||
if (dir === 'Down') { list.reverse(); }
|
||||
|
||||
$.each(list, function () {
|
||||
Array.prototype.forEach.call(list, function(el, i){
|
||||
if (!foundCur) {
|
||||
if (this === selected) {
|
||||
if (el === selected) {
|
||||
foundCur = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
closest = this;
|
||||
closest = el;
|
||||
return false;
|
||||
});
|
||||
if (!closest) { return; }
|
||||
@@ -133,7 +134,11 @@ export const moveUpDownSelected = function (dir) {
|
||||
const t = selected;
|
||||
const oldParent = t.parentNode;
|
||||
const oldNextSibling = t.nextSibling;
|
||||
$(closest)[dir === 'Down' ? 'before' : 'after'](t);
|
||||
if(dir === 'Down') {
|
||||
closest.insertAdjacentElement('beforebegin', t);
|
||||
} else {
|
||||
closest.insertAdjacentElement('afterend', t);
|
||||
}
|
||||
// If the element actually moved position, add the command and fire the changed
|
||||
// event handler.
|
||||
if (oldNextSibling !== t.nextSibling) {
|
||||
@@ -231,14 +236,24 @@ export const cloneSelectedElements = function (x, y) {
|
||||
const batchCmd = new BatchCommand('Clone Elements');
|
||||
// find all the elements selected (stop at first null)
|
||||
const len = selectedElements.length;
|
||||
|
||||
function index(el) {
|
||||
if (!el) return -1;
|
||||
var i = 0;
|
||||
do {
|
||||
i++;
|
||||
} while (el = el.previousElementSibling);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts an array numerically and ascending.
|
||||
* @param {Element} a
|
||||
* @param {Element} b
|
||||
* @returns {Integer}
|
||||
*/
|
||||
function sortfunction (a, b) {
|
||||
return ($(b).index() - $(a).index());
|
||||
function sortfunction (a, b) {
|
||||
return (index(b) - index(a));
|
||||
}
|
||||
selectedElements.sort(sortfunction);
|
||||
for (i = 0; i < len; ++i) {
|
||||
@@ -519,7 +534,10 @@ export const pushGroupProperty = function (g, undoable) {
|
||||
|
||||
const gangle = getRotationAngle(g);
|
||||
|
||||
const gattrs = $(g).attr(['filter', 'opacity']);
|
||||
const gattrs = {
|
||||
filter: g.getAttribute('filter'),
|
||||
opacity: g.getAttribute('opacity'),
|
||||
};
|
||||
let gfilter, gblur, changes;
|
||||
const drawing = elementContext_.getDrawing();
|
||||
|
||||
@@ -692,17 +710,19 @@ export const convertToGroup = function (elem) {
|
||||
if (!elem) {
|
||||
elem = selectedElements[0];
|
||||
}
|
||||
const $elem = $(elem);
|
||||
const $elem = elem;
|
||||
const batchCmd = new BatchCommand();
|
||||
let ts;
|
||||
|
||||
if ($elem.data('gsvg')) {
|
||||
if (dataStorage.has($elem, 'gsvg')) {
|
||||
// Use the gsvg as the new group
|
||||
const svg = elem.firstChild;
|
||||
const pt = $(svg).attr(['x', 'y']);
|
||||
const pt = {
|
||||
x: svg.getAttribute('x'),
|
||||
y: svg.getAttribute('y'),
|
||||
};
|
||||
|
||||
$(elem.firstChild.firstChild).unwrap();
|
||||
$(elem).removeData('gsvg');
|
||||
dataStorage.remove(elem, 'gsvg');
|
||||
|
||||
const tlist = getTransformList(elem);
|
||||
const xform = elementContext_.getSVGRoot().createSVGTransform();
|
||||
@@ -710,8 +730,8 @@ export const convertToGroup = function (elem) {
|
||||
tlist.appendItem(xform);
|
||||
recalculateDimensions(elem);
|
||||
elementContext_.call('selected', [elem]);
|
||||
} else if ($elem.data('symbol')) {
|
||||
elem = $elem.data('symbol');
|
||||
} else if (dataStorage.has($elem, 'symbol')) {
|
||||
elem = dataStorage.get($elem, 'symbol')
|
||||
|
||||
ts = $elem.attr('transform');
|
||||
const pos = $elem.attr(['x', 'y']);
|
||||
@@ -735,7 +755,7 @@ export const convertToGroup = function (elem) {
|
||||
|
||||
// See if other elements reference this symbol
|
||||
const svgcontent = elementContext_.getSVGContent();
|
||||
const hasMore = $(svgcontent).find('use:data(symbol)').length;
|
||||
const hasMore = svgcontent.querySelectorAll('use:data(symbol)').length;
|
||||
|
||||
const g = elementContext_.getDOMDocument().createElementNS(NS.SVG, 'g');
|
||||
const childs = elem.childNodes;
|
||||
@@ -747,8 +767,11 @@ export const convertToGroup = function (elem) {
|
||||
|
||||
// Duplicate the gradients for Gecko, since they weren't included in the <symbol>
|
||||
if (isGecko()) {
|
||||
const dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone();
|
||||
$(g).append(dupeGrads);
|
||||
const svgElement = findDefs();
|
||||
const gradients = svgElement.querySelectorAll('linearGradient,radialGradient,pattern');
|
||||
for (let i = 0, im = gradients.length; im > i; i++) {
|
||||
g.appendChild(gradients[i].cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
if (ts) {
|
||||
@@ -761,7 +784,11 @@ export const convertToGroup = function (elem) {
|
||||
|
||||
// Put the dupe gradients back into <defs> (after uniquifying them)
|
||||
if (isGecko()) {
|
||||
$(findDefs()).append($(g).find('linearGradient,radialGradient,pattern'));
|
||||
const svgElement = findDefs();
|
||||
const elements = g.querySelectorAll('linearGradient,radialGradient,pattern');
|
||||
for (let i = 0, im = elements.length; im > i; i++) {
|
||||
svgElement.appendChild(elements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// now give the g itself a new id
|
||||
@@ -798,8 +825,9 @@ export const convertToGroup = function (elem) {
|
||||
});
|
||||
|
||||
// Give ID for any visible element missing one
|
||||
$(g).find(elementContext_.getVisElems()).each(function () {
|
||||
if (!this.id) { this.id = elementContext_.getNextId(); }
|
||||
const visElems = g.querySelectorAll(elementContext_.getVisElems());
|
||||
Array.prototype.forEach.call(visElems, function(el, i){
|
||||
if (!el.id) { el.id = elementContext_.getNextId(); }
|
||||
});
|
||||
|
||||
elementContext_.selectOnly([g]);
|
||||
@@ -827,7 +855,7 @@ export const ungroupSelectedElement = function () {
|
||||
if (!g) {
|
||||
return;
|
||||
}
|
||||
if ($(g).data('gsvg') || $(g).data('symbol')) {
|
||||
if (dataStorage.has(g, 'gsvg') || dataStorage.has(g, 'symbol')) {
|
||||
// Is svg, so actually convert to group
|
||||
convertToGroup(g);
|
||||
return;
|
||||
@@ -835,11 +863,12 @@ export const ungroupSelectedElement = function () {
|
||||
if (g.tagName === 'use') {
|
||||
// Somehow doesn't have data set, so retrieve
|
||||
const symbol = getElem(getHref(g).substr(1));
|
||||
$(g).data('symbol', symbol).data('ref', symbol);
|
||||
dataStorage.put(g, 'symbol', symbol);
|
||||
dataStorage.put(g, 'ref', symbol);
|
||||
convertToGroup(g);
|
||||
return;
|
||||
}
|
||||
const parentsA = $(g).parents('a');
|
||||
const parentsA = getParents(g.parentNode, 'a');
|
||||
if (parentsA.length) {
|
||||
g = parentsA[0];
|
||||
}
|
||||
@@ -903,7 +932,7 @@ export const updateCanvas = function (w, h) {
|
||||
elementContext_.getSVGRoot().setAttribute('width', w);
|
||||
elementContext_.getSVGRoot().setAttribute('height', h);
|
||||
const currentZoom = elementContext_.getCurrentZoom();
|
||||
const bg = $('#canvasBackground')[0];
|
||||
const bg = document.getElementById('canvasBackground');
|
||||
const oldX = elementContext_.getSVGContent().getAttribute('x');
|
||||
const oldY = elementContext_.getSVGContent().getAttribute('y');
|
||||
const x = ((w - this.contentW * currentZoom) / 2);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
getTransformList
|
||||
} from './svgtransformlist.js';
|
||||
import * as hstry from './history.js';
|
||||
import {getClosest} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const {BatchCommand} = hstry;
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
@@ -157,10 +158,10 @@ mouseTarget.id !== 'svgcanvas'
|
||||
return selectionContext_.getSVGRoot();
|
||||
}
|
||||
|
||||
const $target = $(mouseTarget);
|
||||
const $target = mouseTarget;
|
||||
|
||||
// If it's a selection grip, return the grip parent
|
||||
if ($target.closest('#selectorParentGroup').length) {
|
||||
if (getClosest($target.parentNode, '#selectorParentGroup')) {
|
||||
// While we could instead have just returned mouseTarget,
|
||||
// this makes it easier to indentify as being a selector grip
|
||||
return selectionContext_.getCanvas().selectorManager.selectorParentGroup;
|
||||
@@ -237,10 +238,12 @@ export const runExtensionsMethod = function (action, vars, returnArray, nameFilt
|
||||
*/
|
||||
export const getVisibleElementsAndBBoxes = function (parent) {
|
||||
if (!parent) {
|
||||
parent = $(selectionContext_.getSVGContent()).children(); // Prevent layers from being included
|
||||
const svgcontent = selectionContext_.getSVGContent();
|
||||
parent = svgcontent.children; // Prevent layers from being included
|
||||
}
|
||||
const contentElems = [];
|
||||
$(parent).children().each(function (i, elem) {
|
||||
const elements = parent.children;
|
||||
Array.prototype.forEach.call(elements, function(elem, i){
|
||||
if (elem.getBBox) {
|
||||
contentElems.push({elem, bbox: getStrokedBBoxDefaultVisible([elem])});
|
||||
}
|
||||
@@ -323,7 +326,9 @@ export const getIntersectionListMethod = function (rect) {
|
||||
export const groupSvgElem = function (elem) {
|
||||
const g = document.createElementNS(NS.SVG, 'g');
|
||||
elem.replaceWith(g);
|
||||
$(g).append(elem).data('gsvg', elem)[0].id = selectionContext_.getCanvas().getNextId();
|
||||
g.appendChild(elem);
|
||||
dataStorage.put(g, 'gsvg', elem);
|
||||
g.id = selectionContext_.getCanvas().getNextId();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -342,12 +347,6 @@ export const prepareSvg = function (newDoc) {
|
||||
selectionContext_.getCanvas().pathActions.fixEnd(path);
|
||||
});
|
||||
};
|
||||
// `this.each` is deprecated, if any extension used this it can be recreated by doing this:
|
||||
// * @example $(canvas.getRootElem()).children().each(...)
|
||||
// * @function module:svgcanvas.SvgCanvas#each
|
||||
// this.each = function (cb) {
|
||||
// $(svgroot).children().each(cb);
|
||||
// };
|
||||
|
||||
/**
|
||||
* Removes any old rotations if present, prepends a new rotation at the
|
||||
|
||||
@@ -29,6 +29,7 @@ import * as draw from './draw.js';
|
||||
import {
|
||||
recalculateDimensions
|
||||
} from './recalculate.js';
|
||||
import {getParents, getClosest} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const {
|
||||
InsertElementCommand, RemoveElementCommand,
|
||||
@@ -38,6 +39,7 @@ const {
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
let svgContext_ = null;
|
||||
let $id = null;
|
||||
|
||||
/**
|
||||
* @function module:svg-exec.init
|
||||
@@ -46,6 +48,8 @@ let svgContext_ = null;
|
||||
*/
|
||||
export const init = function (svgContext) {
|
||||
svgContext_ = svgContext;
|
||||
const svgCanvas = svgContext_.getCanvas();
|
||||
$id = svgCanvas.$id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -60,7 +64,8 @@ export const svgCanvasToString = function () {
|
||||
svgContext_.getCanvas().pathActions.clear(true);
|
||||
|
||||
// Keep SVG-Edit comment on top
|
||||
$.each(svgContext_.getSVGContent().childNodes, function (i, node) {
|
||||
const childNodesElems = svgContext_.getSVGContent().childNodes;
|
||||
childNodesElems.forEach(function(node, i){
|
||||
if (i && node.nodeType === 8 && node.data.includes('Created with')) {
|
||||
svgContext_.getSVGContent().firstChild.before(node);
|
||||
}
|
||||
@@ -75,8 +80,9 @@ export const svgCanvasToString = function () {
|
||||
const nakedSvgs = [];
|
||||
|
||||
// Unwrap gsvg if it has no special attributes (only id and style)
|
||||
$(svgContext_.getSVGContent()).find('g[data-gsvg]').each(function () {
|
||||
const attrs = this.attributes;
|
||||
const gsvgElems = svgContext_.getSVGContent().querySelectorAll('g[data-gsvg]');
|
||||
Array.prototype.forEach.call(gsvgElems, function(element, i){
|
||||
const attrs = element.attributes;
|
||||
let len = attrs.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (attrs[i].nodeName === 'id' || attrs[i].nodeName === 'style') {
|
||||
@@ -85,17 +91,17 @@ export const svgCanvasToString = function () {
|
||||
}
|
||||
// No significant attributes, so ungroup
|
||||
if (len <= 0) {
|
||||
const svg = this.firstChild;
|
||||
const svg = element.firstChild;
|
||||
nakedSvgs.push(svg);
|
||||
$(this).replaceWith(svg);
|
||||
element.replaceWith(svg);
|
||||
}
|
||||
});
|
||||
const output = this.svgToString(svgContext_.getSVGContent(), 0);
|
||||
|
||||
// Rewrap gsvg
|
||||
if (nakedSvgs.length) {
|
||||
$(nakedSvgs).each(function () {
|
||||
svgContext_.getCanvas().groupSvgElem(this);
|
||||
Array.prototype.forEach.call(nakedSvgs, function(el, i){
|
||||
svgContext_.getCanvas().groupSvgElem(el);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -153,16 +159,17 @@ export const svgToString = function (elem, indent) {
|
||||
const nsuris = {};
|
||||
|
||||
// Check elements for namespaces, add if found
|
||||
$(elem).find('*').andSelf().each(function () {
|
||||
const cElements = elem.querySelectorAll('*');
|
||||
cElements.push(elem);
|
||||
Array.prototype.forEach.call(cElements, function(el, i){
|
||||
// const el = this;
|
||||
// for some elements have no attribute
|
||||
const uri = this.namespaceURI;
|
||||
const uri = el.namespaceURI;
|
||||
if (uri && !nsuris[uri] && nsMap[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml') {
|
||||
nsuris[uri] = true;
|
||||
out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"');
|
||||
}
|
||||
|
||||
$.each(this.attributes, function (i, attr) {
|
||||
el.attributes.forEach(function(attr, i){
|
||||
const u = attr.namespaceURI;
|
||||
if (u && !nsuris[u] && nsMap[u] !== 'xmlns' && nsMap[u] !== 'xml') {
|
||||
nsuris[u] = true;
|
||||
@@ -324,7 +331,7 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
}
|
||||
|
||||
svgContext_.getSVGRoot().append(svgContext_.getSVGContent());
|
||||
const content = $(svgContext_.getSVGContent());
|
||||
const content = svgContext_.getSVGContent();
|
||||
|
||||
svgContext_.getCanvas().current_drawing_ = new draw.Drawing(svgContext_.getSVGContent(), svgContext_.getIdPrefix());
|
||||
|
||||
@@ -337,8 +344,8 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
}
|
||||
|
||||
// change image href vals if possible
|
||||
content.find('image').each(function () {
|
||||
const image = this;
|
||||
const elements = content.querySelectorAll('image');
|
||||
Array.prototype.forEach.call(elements, function(image, i){
|
||||
preventClickDefault(image);
|
||||
const val = svgContext_.getCanvas().getHref(this);
|
||||
if (val) {
|
||||
@@ -349,9 +356,11 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
if (m) {
|
||||
const url = decodeURIComponent(m[1]);
|
||||
// const url = decodeURIComponent(m.groups.url);
|
||||
$(new Image()).load(function () {
|
||||
const iimg = new Image();
|
||||
iimg.addEventListener("load", (e) => {
|
||||
image.setAttributeNS(NS.XLINK, 'xlink:href', url);
|
||||
}).attr('src', url);
|
||||
});
|
||||
iimg.src = url;
|
||||
}
|
||||
}
|
||||
// Add to encodableImages if it loads
|
||||
@@ -360,25 +369,30 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
});
|
||||
|
||||
// Wrap child SVGs in group elements
|
||||
content.find('svg').each(function () {
|
||||
const svgElements = content.querySelectorAll('svg');
|
||||
Array.prototype.forEach.call(svgElements, function(element, i){
|
||||
// Skip if it's in a <defs>
|
||||
if ($(this).closest('defs').length) { return; }
|
||||
if (getClosest(element.parentNode, 'defs')) { return; }
|
||||
|
||||
svgContext_.getCanvas().uniquifyElems(this);
|
||||
svgContext_.getCanvas().uniquifyElems(element);
|
||||
|
||||
// Check if it already has a gsvg group
|
||||
const pa = this.parentNode;
|
||||
const pa = element.parentNode;
|
||||
if (pa.childNodes.length === 1 && pa.nodeName === 'g') {
|
||||
$(pa).data('gsvg', this);
|
||||
dataStorage.put(pa, 'gsvg', element);
|
||||
pa.id = pa.id || svgContext_.getCanvas().getNextId();
|
||||
} else {
|
||||
svgContext_.getCanvas().groupSvgElem(this);
|
||||
svgContext_.getCanvas().groupSvgElem(element);
|
||||
}
|
||||
});
|
||||
|
||||
// For Firefox: Put all paint elems in defs
|
||||
if (isGecko()) {
|
||||
content.find('linearGradient, radialGradient, pattern').appendTo(findDefs());
|
||||
const svgDefs = findDefs();
|
||||
const findElems = content.querySelectorAll('linearGradient, radialGradient, pattern');
|
||||
Array.prototype.forEach.call(findElems, function(ele, i){
|
||||
svgDefs.appendChild(ele);
|
||||
});
|
||||
}
|
||||
|
||||
// Set ref element for <use> elements
|
||||
@@ -386,7 +400,7 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
// TODO: This should also be done if the object is re-added through "redo"
|
||||
svgContext_.getCanvas().setUseData(content);
|
||||
|
||||
svgContext_.getCanvas().convertGradients(content[0]);
|
||||
svgContext_.getCanvas().convertGradients(content);
|
||||
|
||||
const attrs = {
|
||||
id: 'svgcontent',
|
||||
@@ -396,16 +410,16 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
let percs = false;
|
||||
|
||||
// determine proper size
|
||||
if (content.attr('viewBox')) {
|
||||
const vb = content.attr('viewBox').split(' ');
|
||||
if (content.getAttribute('viewBox')) {
|
||||
const viBox = content.getAttribute('viewBox');
|
||||
const vb = viBox.split(' ');
|
||||
attrs.width = vb[2];
|
||||
attrs.height = vb[3];
|
||||
// handle content that doesn't have a viewBox
|
||||
} else {
|
||||
$.each(['width', 'height'], function (i, dim) {
|
||||
['width', 'height'].forEach(function(dim, i){
|
||||
// Set to 100 if not given
|
||||
const val = content.attr(dim) || '100%';
|
||||
|
||||
const val = content.getAttribute(dim) || '100%';
|
||||
if (String(val).substr(-1) === '%') {
|
||||
// Use user units if percentage given
|
||||
percs = true;
|
||||
@@ -419,8 +433,12 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
draw.identifyLayers();
|
||||
|
||||
// Give ID for any visible layer children missing one
|
||||
content.children().find(svgContext_.getVisElems()).each(function () {
|
||||
if (!this.id) { this.id = svgContext_.getCanvas().getNextId(); }
|
||||
const chiElems = content.children;
|
||||
Array.prototype.forEach.call(chiElems, function(chiElem, i){
|
||||
const visElems = chiElem.querySelectorAll(svgContext_.getVisElems());
|
||||
Array.prototype.forEach.call(visElems, function(elem, i){
|
||||
if (!elem.id) { elem.id = svgContext_.getCanvas().getNextId(); }
|
||||
});
|
||||
});
|
||||
|
||||
// Percentage width/height, so let's base it on visible elements
|
||||
@@ -435,13 +453,17 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
if (attrs.width <= 0) { attrs.width = 100; }
|
||||
if (attrs.height <= 0) { attrs.height = 100; }
|
||||
|
||||
content.attr(attrs);
|
||||
for (const [key, value] of Object.entries(attrs)) {
|
||||
content.setAttribute(key, value);
|
||||
}
|
||||
this.contentW = attrs.width;
|
||||
this.contentH = attrs.height;
|
||||
|
||||
batchCmd.addSubCommand(new InsertElementCommand(svgContext_.getSVGContent()));
|
||||
// update root to the correct size
|
||||
const changes = content.attr(['width', 'height']);
|
||||
const width = content.getAttribute('width');
|
||||
const height = content.getAttribute('height');
|
||||
const changes = {width: width, height: height};
|
||||
batchCmd.addSubCommand(new ChangeElementCommand(svgContext_.getSVGRoot(), changes));
|
||||
|
||||
// reset zoom
|
||||
@@ -478,6 +500,7 @@ export const setSvgString = function (xmlString, preventUndo) {
|
||||
* was obtained
|
||||
*/
|
||||
export const importSvgString = function (xmlString) {
|
||||
console.log('importSvgString --> ', xmlString);
|
||||
let j, ts, useEl;
|
||||
try {
|
||||
// Get unique ID
|
||||
@@ -485,8 +508,11 @@ export const importSvgString = function (xmlString) {
|
||||
|
||||
let useExisting = false;
|
||||
// Look for symbol and make sure symbol exists in image
|
||||
if (svgContext_.getImportIds(uid) && $(svgContext_.getImportIds(uid).symbol).parents('#svgroot').length) {
|
||||
useExisting = true;
|
||||
if (svgContext_.getImportIds(uid) && svgContext_.getImportIds(uid).symbol) {
|
||||
const parents = getParents(svgContext_.getImportIds(uid).symbol, '#svgroot');
|
||||
if(parents.length){
|
||||
useExisting = true;
|
||||
}
|
||||
}
|
||||
|
||||
const batchCmd = new BatchCommand('Import Image');
|
||||
@@ -534,7 +560,10 @@ export const importSvgString = function (xmlString) {
|
||||
// Move all gradients into root for Firefox, workaround for this bug:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=353575
|
||||
// TODO: Make this properly undo-able.
|
||||
$(svg).find('linearGradient, radialGradient, pattern').appendTo(defs);
|
||||
const elements = svg.querySelectorAll('linearGradient, radialGradient, pattern');
|
||||
Array.prototype.forEach.call(elements, function(el, i){
|
||||
defs.appendChild(el);
|
||||
});
|
||||
}
|
||||
|
||||
while (svg.firstChild) {
|
||||
@@ -567,7 +596,8 @@ export const importSvgString = function (xmlString) {
|
||||
|
||||
useEl.setAttribute('transform', ts);
|
||||
recalculateDimensions(useEl);
|
||||
$(useEl).data('symbol', symbol).data('ref', symbol);
|
||||
dataStorage.put(useEl, 'symbol', symbol);
|
||||
dataStorage.put(useEl, 'ref', symbol);
|
||||
svgContext_.getCanvas().addToSelection([useEl]);
|
||||
|
||||
// TODO: Find way to add this in a recalculateDimensions-parsable way
|
||||
@@ -600,17 +630,14 @@ export const embedImage = function (src) {
|
||||
// Todo: Remove this Promise in favor of making an async/await `Image.load` utility
|
||||
return new Promise(function (resolve, reject) {
|
||||
// load in the image and once it's loaded, get the dimensions
|
||||
$(new Image()).load(function (response, status, xhr) {
|
||||
if (status === 'error') {
|
||||
reject(new Error('Error loading image: ' + xhr.status + ' ' + xhr.statusText));
|
||||
return;
|
||||
}
|
||||
const imgI = new Image();
|
||||
imgI.addEventListener("load", (e) => {
|
||||
// create a canvas the same size as the raster image
|
||||
const cvs = document.createElement('canvas');
|
||||
cvs.width = this.width;
|
||||
cvs.height = this.height;
|
||||
cvs.width = e.currentTarget.width;
|
||||
cvs.height = e.currentTarget.height;
|
||||
// load the raster image into the canvas
|
||||
cvs.getContext('2d').drawImage(this, 0, 0);
|
||||
cvs.getContext('2d').drawImage(e.currentTarget, 0, 0);
|
||||
// retrieve the data: URL
|
||||
try {
|
||||
let urldata = ';svgedit_url=' + encodeURIComponent(src);
|
||||
@@ -621,7 +648,11 @@ export const embedImage = function (src) {
|
||||
}
|
||||
svgContext_.getCanvas().setGoodImage(src);
|
||||
resolve(svgContext_.getEncodableImages(src));
|
||||
}).attr('src', src);
|
||||
});
|
||||
imgI.addEventListener("error", (e) => {
|
||||
reject(new Error('Error loading image: '));
|
||||
});
|
||||
imgI.attr('src', src);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -670,19 +701,19 @@ function getIssues () {
|
||||
foreignObject: uiStrings.exportNoforeignObject,
|
||||
'[stroke-dasharray]': uiStrings.exportNoDashArray
|
||||
};
|
||||
const content = $(svgContext_.getSVGContent());
|
||||
const content = svgContext_.getSVGContent();
|
||||
|
||||
// Add font/text check if Canvas Text API is not implemented
|
||||
if (!('font' in $('<canvas>')[0].getContext('2d'))) {
|
||||
if (!('font' in document.querySelector('CANVAS').getContext('2d'))) {
|
||||
issueList.text = uiStrings.exportNoText;
|
||||
}
|
||||
|
||||
$.each(issueList, function (sel, descr) {
|
||||
if (content.find(sel).length) {
|
||||
for (const [sel, descr] of Object.entries(issueList)) {
|
||||
if (content.querySelectorAll(sel).length) {
|
||||
issueCodes.push(sel);
|
||||
issues.push(descr);
|
||||
}
|
||||
});
|
||||
}
|
||||
return {issues, issueCodes};
|
||||
}
|
||||
/**
|
||||
@@ -718,12 +749,15 @@ export const rasterExport = async function (imgType, quality, exportWindowName,
|
||||
const {issues, issueCodes} = getIssues();
|
||||
const svg = this.svgCanvasToString();
|
||||
|
||||
if (!$('#export_canvas').length) {
|
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
|
||||
if (!$id('export_canvas')) {
|
||||
const canvasEx = document.createElement('CANVAS');
|
||||
canvasEx.id = 'export_canvas';
|
||||
canvasEx.style.display = 'none';
|
||||
document.body.appendChild(canvasEx);
|
||||
}
|
||||
const c = $('#export_canvas')[0];
|
||||
c.width = svgContext_.getCanvas().contentW;
|
||||
c.height = svgContext_.getCanvas().contentH;
|
||||
const c = $id('export_canvas');
|
||||
c.style.width = svgContext_.getCanvas().contentW + "px";;
|
||||
c.style.height = svgContext_.getCanvas().contentH + "px";;
|
||||
const canvg = svgContext_.getcanvg();
|
||||
const ctx = c.getContext('2d');
|
||||
const v = canvg.fromString(ctx, svg);
|
||||
@@ -933,19 +967,21 @@ export const uniquifyElemsMethod = function (g) {
|
||||
* @returns {void}
|
||||
*/
|
||||
export const setUseDataMethod = function (parent) {
|
||||
let elems = $(parent);
|
||||
let elems = parent;
|
||||
|
||||
if (parent.tagName !== 'use') {
|
||||
elems = elems.find('use');
|
||||
// elems = elems.find('use');
|
||||
elems = elems.querySelectorAll('use');
|
||||
}
|
||||
|
||||
elems.each(function () {
|
||||
const id = svgContext_.getCanvas().getHref(this).substr(1);
|
||||
Array.prototype.forEach.call(elems, function(el, _){
|
||||
const id = svgContext_.getCanvas().getHref(el).substr(1);
|
||||
const refElem = svgContext_.getCanvas().getElem(id);
|
||||
if (!refElem) { return; }
|
||||
$(this).data('ref', refElem);
|
||||
dataStorage.put(el, 'ref', refElem);
|
||||
if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') {
|
||||
$(this).data('symbol', refElem).data('ref', refElem);
|
||||
dataStorage.put(el, 'symbol', refElem);
|
||||
dataStorage.put(el, 'ref', refElem);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -987,7 +1023,7 @@ export const removeUnusedDefElemsMethod = function () {
|
||||
}
|
||||
}
|
||||
|
||||
const defelems = $(defs).find('linearGradient, radialGradient, filter, marker, svg, symbol');
|
||||
const defelems = defs.querySelectorAll('linearGradient, radialGradient, filter, marker, svg, symbol');
|
||||
i = defelems.length;
|
||||
while (i--) {
|
||||
const defelem = defelems[i];
|
||||
@@ -1009,20 +1045,19 @@ export const removeUnusedDefElemsMethod = function () {
|
||||
* @returns {void}
|
||||
*/
|
||||
export const convertGradientsMethod = function (elem) {
|
||||
let elems = $(elem).find('linearGradient, radialGradient');
|
||||
let elems = elem.querySelectorAll('linearGradient, radialGradient');
|
||||
if (!elems.length && isWebkit()) {
|
||||
// Bug in webkit prevents regular *Gradient selector search
|
||||
elems = $(elem).find('*').filter(function () {
|
||||
return (this.tagName.includes('Gradient'));
|
||||
elems = Array.prototype.filter.call(elem.querySelectorAll('*'), function (curThis, i) {
|
||||
return (curThis.tagName.includes('Gradient'));
|
||||
});
|
||||
}
|
||||
|
||||
elems.each(function () {
|
||||
const grad = this;
|
||||
if ($(grad).attr('gradientUnits') === 'userSpaceOnUse') {
|
||||
Array.prototype.forEach.call(elems, function(grad, i){
|
||||
if (grad.getAttribute('gradientUnits') === 'userSpaceOnUse') {
|
||||
const svgcontent = svgContext_.getSVGContent();
|
||||
// TODO: Support more than one element with this ref by duplicating parent grad
|
||||
const fillStrokeElems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]');
|
||||
const fillStrokeElems = svgcontent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]');
|
||||
if (!fillStrokeElems.length) { return; }
|
||||
|
||||
// get object's bounding box
|
||||
@@ -1033,7 +1068,12 @@ export const convertGradientsMethod = function (elem) {
|
||||
if (!bb) { return; }
|
||||
|
||||
if (grad.tagName === 'linearGradient') {
|
||||
const gCoords = $(grad).attr(['x1', 'y1', 'x2', 'y2']);
|
||||
const gCoords = {
|
||||
x1: grad.getAttribute('x1'),
|
||||
y1: grad.getAttribute('y1'),
|
||||
x2: grad.getAttribute('x2'),
|
||||
y2: grad.getAttribute('y2'),
|
||||
};
|
||||
|
||||
// If has transform, convert
|
||||
const tlist = grad.gradientTransform.baseVal;
|
||||
@@ -1048,35 +1088,12 @@ export const convertGradientsMethod = function (elem) {
|
||||
gCoords.y2 = pt2.y;
|
||||
grad.removeAttribute('gradientTransform');
|
||||
}
|
||||
|
||||
$(grad).attr({
|
||||
x1: (gCoords.x1 - bb.x) / bb.width,
|
||||
y1: (gCoords.y1 - bb.y) / bb.height,
|
||||
x2: (gCoords.x2 - bb.x) / bb.width,
|
||||
y2: (gCoords.y2 - bb.y) / bb.height
|
||||
});
|
||||
grad.setAttribute('x1', (gCoords.x1 - bb.x) / bb.width);
|
||||
grad.setAttribute('y1', (gCoords.y1 - bb.y) / bb.height);
|
||||
grad.setAttribute('x2', (gCoords.x2 - bb.x) / bb.width);
|
||||
grad.setAttribute('y2', (gCoords.y2 - bb.y) / bb.height);
|
||||
grad.removeAttribute('gradientUnits');
|
||||
}
|
||||
// else {
|
||||
// Note: radialGradient elements cannot be easily converted
|
||||
// because userSpaceOnUse will keep circular gradients, while
|
||||
// objectBoundingBox will x/y scale the gradient according to
|
||||
// its bbox.
|
||||
//
|
||||
// For now we'll do nothing, though we should probably have
|
||||
// the gradient be updated as the element is moved, as
|
||||
// inkscape/illustrator do.
|
||||
//
|
||||
// const gCoords = $(grad).attr(['cx', 'cy', 'r']);
|
||||
//
|
||||
// $(grad).attr({
|
||||
// cx: (gCoords.cx - bb.x) / bb.width,
|
||||
// cy: (gCoords.cy - bb.y) / bb.height,
|
||||
// r: gCoords.r
|
||||
// });
|
||||
//
|
||||
// grad.removeAttribute('gradientUnits');
|
||||
// }
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* Dependencies:
|
||||
1. Also expects jQuery UI for `svgCanvasToString` and
|
||||
`convertToGroup` use of `:data()` selector
|
||||
*/
|
||||
|
||||
import {Canvg as canvg} from 'canvg';
|
||||
import 'pathseg';
|
||||
|
||||
@@ -115,6 +110,9 @@ import {
|
||||
clearSvgContentElementInit,
|
||||
init as clearInit
|
||||
} from './clear.js';
|
||||
import {
|
||||
getClosest, getParents
|
||||
} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
const {
|
||||
@@ -193,6 +191,8 @@ class SvgCanvas {
|
||||
this.$id = $id;
|
||||
this.$qq = $qq;
|
||||
this.$qa = $qa;
|
||||
this.getClosest = getClosest;
|
||||
this.getParents = getParents;
|
||||
|
||||
this.isLayer = draw.Layer.isLayer;
|
||||
|
||||
@@ -528,7 +528,10 @@ class SvgCanvas {
|
||||
|
||||
const restoreRefElems = function (elem) {
|
||||
// Look for missing reference elements, restore any found
|
||||
const attrs = $(elem).attr(refAttrs);
|
||||
let attrs = {};
|
||||
refAttrs.forEach(function(item, _){
|
||||
attrs[item] = elem.getAttribute(item);
|
||||
});
|
||||
Object.values(attrs).forEach((val) => {
|
||||
if (val && val.startsWith('url(')) {
|
||||
const id = getUrlFromAttr(val).substr(1);
|
||||
@@ -731,16 +734,13 @@ class SvgCanvas {
|
||||
// Interface strings, usually for title elements
|
||||
const uiStrings = {};
|
||||
|
||||
const elData = $.data;
|
||||
|
||||
// Animation element to change the opacity of any newly created element
|
||||
const opacAni = document.createElementNS(NS.SVG, 'animate');
|
||||
$(opacAni).attr({
|
||||
attributeName: 'opacity',
|
||||
begin: 'indefinite',
|
||||
dur: 1,
|
||||
fill: 'freeze'
|
||||
}).appendTo(svgroot);
|
||||
opacAni.setAttribute('attributeName', 'opacity');
|
||||
opacAni.setAttribute('begin', 'indefinite');
|
||||
opacAni.setAttribute('dur', 1);
|
||||
opacAni.setAttribute('fill', 'freeze');
|
||||
svgroot.appendChild(opacAni);
|
||||
|
||||
// (function () {
|
||||
// TODO For Issue 208: this is a start on a thumbnail
|
||||
@@ -1140,7 +1140,11 @@ class SvgCanvas {
|
||||
const currentLayer = getCurrentDrawing().getCurrentLayer();
|
||||
if (currentLayer) {
|
||||
currentMode = 'select';
|
||||
selectOnly($(currentGroup || currentLayer).children());
|
||||
if(currentGroup){
|
||||
selectOnly(currentGroup.children);
|
||||
} else {
|
||||
selectOnly(currentLayer.children);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1251,7 +1255,6 @@ class SvgCanvas {
|
||||
getSVGRoot,
|
||||
getSVGContent,
|
||||
call,
|
||||
elData,
|
||||
getIntersectionList
|
||||
}
|
||||
);
|
||||
@@ -1304,11 +1307,16 @@ class SvgCanvas {
|
||||
|
||||
// Added mouseup to the container here.
|
||||
// TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored.
|
||||
$(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp);
|
||||
// $(window).mouseup(mouseUp);
|
||||
container.addEventListener('mousedown', mouseDown);
|
||||
container.addEventListener('mousemove', mouseMove);
|
||||
container.addEventListener('click', handleLinkInCanvas);
|
||||
container.addEventListener('dblclick', dblClick);
|
||||
container.addEventListener('mouseup', mouseUp);
|
||||
|
||||
// TODO(rafaelcastrocouto): User preference for shift key and zoom factor
|
||||
$(container).bind('mousewheel DOMMouseScroll', DOMMouseScrollEvent);
|
||||
container.addEventListener('mousewheel', DOMMouseScrollEvent);
|
||||
container.addEventListener('DOMMouseScroll', DOMMouseScrollEvent);
|
||||
|
||||
}());
|
||||
|
||||
textActionsInit(
|
||||
@@ -1620,7 +1628,6 @@ class SvgCanvas {
|
||||
getSelectedElements,
|
||||
getSVGContent,
|
||||
undoMgr,
|
||||
elData,
|
||||
getCurrentDrawing,
|
||||
clearSelection,
|
||||
call,
|
||||
@@ -1823,7 +1830,7 @@ class SvgCanvas {
|
||||
* position in the editor's canvas.
|
||||
*/
|
||||
this.getOffset = function () {
|
||||
return $(svgcontent).attr(['x', 'y']);
|
||||
return {x: svgcontent.getAttribute('x'), y: svgcontent.getAttribute('y')};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2753,6 +2760,8 @@ SvgCanvas.decode64 = decode64;
|
||||
SvgCanvas.$id = $id;
|
||||
SvgCanvas.$qq = $qq;
|
||||
SvgCanvas.$qa = $qa;
|
||||
SvgCanvas.getClosest = getClosest;
|
||||
SvgCanvas.getParents = getParents;
|
||||
SvgCanvas.blankPageObjectURL = blankPageObjectURL;
|
||||
|
||||
export default SvgCanvas;
|
||||
|
||||
@@ -56,7 +56,7 @@ export const textActionsMethod = (function () {
|
||||
*/
|
||||
function setCursor (index) {
|
||||
const empty = (textinput.value === '');
|
||||
$(textinput).focus();
|
||||
textinput.focus();
|
||||
|
||||
if (!arguments.length) {
|
||||
if (empty) {
|
||||
@@ -268,7 +268,7 @@ export const textActionsMethod = (function () {
|
||||
*/
|
||||
function selectAll (evt) {
|
||||
setSelection(0, curtext.textContent.length);
|
||||
$(this).unbind(evt);
|
||||
evt.target.removeEventListener('click', selectAll);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,9 +292,10 @@ export const textActionsMethod = (function () {
|
||||
setSelection(first, last);
|
||||
|
||||
// Set tripleclick
|
||||
$(evt.target).click(selectAll);
|
||||
evt.target.addEventListener('click', selectAll);
|
||||
|
||||
setTimeout(function () {
|
||||
$(evt.target).unbind('click', selectAll);
|
||||
evt.target.removeEventListener('click', selectAll);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
@@ -418,8 +419,8 @@ export const textActionsMethod = (function () {
|
||||
textActionsContext_.setCurrentMode('select');
|
||||
clearInterval(blinker);
|
||||
blinker = null;
|
||||
if (selblock) { $(selblock).attr('display', 'none'); }
|
||||
if (cursor) { $(cursor).attr('visibility', 'hidden'); }
|
||||
if (selblock) { selblock.setAttribute('display', 'none'); }
|
||||
if (cursor) { cursor.setAttribute('visibility', 'hidden'); }
|
||||
curtext.style.cursor = 'move';
|
||||
|
||||
if (selectElem) {
|
||||
@@ -434,7 +435,7 @@ export const textActionsMethod = (function () {
|
||||
textActionsContext_.getCanvas().deleteSelectedElements();
|
||||
}
|
||||
|
||||
$(textinput).blur();
|
||||
textinput.blur();
|
||||
|
||||
curtext = false;
|
||||
|
||||
@@ -448,7 +449,6 @@ export const textActionsMethod = (function () {
|
||||
*/
|
||||
setInputElem (elem) {
|
||||
textinput = elem;
|
||||
// $(textinput).blur(hideCursor);
|
||||
},
|
||||
/**
|
||||
* @returns {void}
|
||||
@@ -490,7 +490,8 @@ export const textActionsMethod = (function () {
|
||||
chardata.length = len;
|
||||
textinput.focus();
|
||||
|
||||
$(curtext).unbind('dblclick', selectWord).dblclick(selectWord);
|
||||
curtext.removeEventListener("dblclick", selectWord);
|
||||
curtext.addEventListener("dblclick", selectWord);
|
||||
|
||||
if (!len) {
|
||||
end = {x: textbb.x + (textbb.width / 2), width: 0};
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
isWebkit, supportsHVLineContainerBBox, supportsPathBBox, supportsXpath,
|
||||
supportsSelectors
|
||||
} from '../common/browser.js';
|
||||
import {getClosest} from '../editor/components/jgraduate/Util.js';
|
||||
|
||||
// Constants
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
@@ -138,7 +139,10 @@ export const toXml = function (str) {
|
||||
* @returns {string} The converted string
|
||||
*/
|
||||
export function fromXml (str) {
|
||||
return $('<p/>').html(str).text();
|
||||
const p = document.createElement('p');
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
p.innerHTML = str;
|
||||
return p.textContent;
|
||||
}
|
||||
|
||||
// This code was written by Tyler Akins and has been placed in the
|
||||
@@ -571,28 +575,36 @@ function groupBBFix (selected) {
|
||||
if (supportsHVLineContainerBBox()) {
|
||||
try { return selected.getBBox(); } catch (e) {/* empty */}
|
||||
}
|
||||
const ref = $.data(selected, 'ref');
|
||||
const ref = dataStorage.get(selected, 'ref');
|
||||
let matched = null;
|
||||
let ret, copy;
|
||||
|
||||
if (ref) {
|
||||
copy = $(ref).children().clone().attr('visibility', 'hidden');
|
||||
$(svgroot_).append(copy);
|
||||
matched = copy.filter('line, path');
|
||||
let elements = [];
|
||||
Array.prototype.forEach.call(ref.children, function(el, i){
|
||||
const elem = el.cloneNode(true);
|
||||
elem.setAttribute('visibility', 'hidden');
|
||||
svgroot_.appendChild(elem);
|
||||
copy.push(elem);
|
||||
if(['line', 'path'].indexOf(elem.tagName) !== -1){
|
||||
elements.push(elem);
|
||||
}
|
||||
});
|
||||
matched = (elements.length) ? elements : null;
|
||||
} else {
|
||||
matched = $(selected).find('line, path');
|
||||
matched = selected.querySelectorAll('line, path');
|
||||
}
|
||||
|
||||
let issue = false;
|
||||
if (matched.length) {
|
||||
matched.each(function () {
|
||||
const bb = this.getBBox();
|
||||
Array.prototype.forEach.call(matched, function(match, i){
|
||||
const bb = match.getBBox();
|
||||
if (!bb.width || !bb.height) {
|
||||
issue = true;
|
||||
}
|
||||
});
|
||||
if (issue) {
|
||||
const elems = ref ? copy : $(selected).children();
|
||||
const elems = ref ? copy : selected.children;
|
||||
ret = getStrokedBBox(elems);
|
||||
} else {
|
||||
ret = selected.getBBox();
|
||||
@@ -678,7 +690,7 @@ export const getBBox = function (elem) {
|
||||
}
|
||||
} else {
|
||||
// Check if element is child of a foreignObject
|
||||
const fo = $(selected).closest('foreignObject');
|
||||
const fo = getClosest(selected.parentNode, 'foreignObject');
|
||||
if (fo.length && fo[0].getBBox) {
|
||||
ret = fo[0].getBBox();
|
||||
}
|
||||
@@ -733,11 +745,12 @@ export const getPathDFromElement = function (elem) {
|
||||
switch (elem.tagName) {
|
||||
case 'ellipse':
|
||||
case 'circle': {
|
||||
a = $(elem).attr(['rx', 'ry', 'cx', 'cy']);
|
||||
const {cx, cy} = a;
|
||||
({rx, ry} = a);
|
||||
const rx = elem.getAttribute('rx');
|
||||
const ry = elem.getAttribute('ry');
|
||||
const cx = elem.getAttribute('cx');
|
||||
const cy = elem.getAttribute('cy');
|
||||
if (elem.tagName === 'circle') {
|
||||
ry = $(elem).attr('r');
|
||||
ry = elem.getAttribute('r');
|
||||
rx = ry;
|
||||
}
|
||||
|
||||
@@ -754,8 +767,11 @@ export const getPathDFromElement = function (elem) {
|
||||
d = elem.getAttribute('d');
|
||||
break;
|
||||
case 'line':
|
||||
a = $(elem).attr(['x1', 'y1', 'x2', 'y2']);
|
||||
d = 'M' + a.x1 + ',' + a.y1 + 'L' + a.x2 + ',' + a.y2;
|
||||
const x1 = elem.getAttribute('x1');
|
||||
const y1 = elem.getAttribute('y1');
|
||||
const x2 = elem.getAttribute('x2');
|
||||
const y2 = elem.getAttribute('y2');
|
||||
d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
|
||||
break;
|
||||
case 'polyline':
|
||||
d = 'M' + elem.getAttribute('points');
|
||||
@@ -764,8 +780,8 @@ export const getPathDFromElement = function (elem) {
|
||||
d = 'M' + elem.getAttribute('points') + ' Z';
|
||||
break;
|
||||
case 'rect': {
|
||||
const r = $(elem).attr(['rx', 'ry']);
|
||||
({rx, ry} = r);
|
||||
const rx = elem.getAttribute('rx');
|
||||
const ry = elem.getAttribute('ry');
|
||||
const b = elem.getBBox();
|
||||
const {x, y} = b,
|
||||
w = b.width,
|
||||
@@ -1119,11 +1135,13 @@ export const getStrokedBBox = function (elems, addSVGElementFromJson, pathAction
|
||||
*/
|
||||
export const getVisibleElements = function (parentElement) {
|
||||
if (!parentElement) {
|
||||
parentElement = $(editorContext_.getSVGContent()).children(); // Prevent layers from being included
|
||||
const svgcontent = editorContext_.getSVGContent();
|
||||
parentElement = svgcontent.children; // Prevent layers from being included
|
||||
}
|
||||
|
||||
const contentElems = [];
|
||||
$(parentElement).children().each(function (i, elem) {
|
||||
const childrens = parentElement.children
|
||||
Array.prototype.forEach.call(childrens, function(elem, i){
|
||||
if (elem.getBBox) {
|
||||
contentElems.push(elem);
|
||||
}
|
||||
@@ -1213,7 +1231,7 @@ export const getElem = (supportsSelectors())
|
||||
}
|
||||
: function (id) {
|
||||
// jQuery lookup: twice as slow as xpath in FF
|
||||
return $(svgroot_).find(`[id=${id}]`)[0];
|
||||
return svgroot_.querySelector('[id=${id}]');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1305,7 +1323,12 @@ export const snapToGrid = function (value) {
|
||||
* @returns {void}
|
||||
*/
|
||||
export const preventClickDefault = function (img) {
|
||||
$(img).click(function (e) { e.preventDefault(); });
|
||||
const elements = document.querySelectorAll("img");
|
||||
Array.from(elements).forEach(function(element) {
|
||||
element.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user