@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user