From d2f48b95d52bf91f2a16d3e9c9eaa38e2a1f728e Mon Sep 17 00:00:00 2001
From: JFH <20402845+jfhenon@users.noreply.github.com>
Date: Sun, 27 Dec 2020 00:56:12 +0100
Subject: [PATCH] refactor(panels)
---
src/editor/panels/BottomPanelHandlers.js | 181 +++
src/editor/{ => panels}/LayersPanel.js | 134 +-
src/editor/panels/LeftPanelHandlers.js | 216 ++++
src/editor/panels/TopPanelHandlers.js | 632 ++++++++++
src/editor/svgedit.js | 1445 +++-------------------
5 files changed, 1301 insertions(+), 1307 deletions(-)
create mode 100644 src/editor/panels/BottomPanelHandlers.js
rename src/editor/{ => panels}/LayersPanel.js (60%)
create mode 100644 src/editor/panels/LeftPanelHandlers.js
create mode 100644 src/editor/panels/TopPanelHandlers.js
diff --git a/src/editor/panels/BottomPanelHandlers.js b/src/editor/panels/BottomPanelHandlers.js
new file mode 100644
index 00000000..0051aa77
--- /dev/null
+++ b/src/editor/panels/BottomPanelHandlers.js
@@ -0,0 +1,181 @@
+/* globals $ */
+import SvgCanvas from '../../svgcanvas/svgcanvas.js';
+
+const {$id} = SvgCanvas;
+
+/*
+ * register actions for left panel
+ */
+/**
+ *
+ */
+class BottomPanelHandlers {
+ /**
+ * @param {PlainObject} editor svgedit handler
+ */
+ constructor (editor) {
+ this.editor = editor;
+ this.svgCanvas = editor.canvas;
+ }
+
+ /**
+ * @type {module}
+ */
+ changeStrokeWidth (e) {
+ let val = e.target.value;
+ if (val === 0 && this.editor.selectedElement && ['line', 'polyline'].includes(this.editor.selectedElement.nodeName)) {
+ val = 1;
+ }
+ this.svgCanvas.setStrokeWidth(val);
+ }
+
+ /**
+ * @type {module}
+ */
+ changeZoom (value) {
+ switch (value) {
+ case 'canvas':
+ case 'selection':
+ case 'layer':
+ case 'content':
+ this.editor.zoomChanged(window, value);
+ break;
+ default:
+ {
+ const zoomlevel = Number(value) / 100;
+ if (zoomlevel < 0.001) {
+ value = 0.1;
+ return;
+ }
+ const zoom = this.svgCanvas.getZoom();
+ const wArea = this.editor.workarea;
+
+ this.editor.zoomChanged(window, {
+ width: 0,
+ height: 0,
+ // center pt of scroll position
+ x: (wArea[0].scrollLeft + wArea.width() / 2) / zoom,
+ y: (wArea[0].scrollTop + wArea.height() / 2) / zoom,
+ zoom: zoomlevel
+ }, true);
+ }
+ }
+ }
+ /**
+ * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate
+ * @returns {void}
+ */
+ updateToolButtonState () {
+ const bNoFill = (this.svgCanvas.getColor('fill') === 'none');
+ const bNoStroke = (this.svgCanvas.getColor('stroke') === 'none');
+ const buttonsNeedingStroke = ['tool_fhpath', 'tool_line'];
+ const buttonsNeedingFillAndStroke = [
+ 'tools_rect', 'tools_ellipse',
+ 'tool_text', 'tool_path'
+ ];
+
+ if (bNoStroke) {
+ buttonsNeedingStroke.forEach((btn) => {
+ // if btn is pressed, change to select button
+ if ($id(btn).pressed) {
+ this.editor.leftPanelHandlers.clickSelect();
+ }
+ $(btn).disabled = true;
+ });
+ } else {
+ buttonsNeedingStroke.forEach((btn) => {
+ $id(btn).disabled = false;
+ });
+ }
+
+ if (bNoStroke && bNoFill) {
+ buttonsNeedingFillAndStroke.forEach((btn) => {
+ // if btn is pressed, change to select button
+ if ($id(btn).pressed) {
+ this.editor.leftPanelHandlers.clickSelect();
+ }
+ $(btn).disabled = true;
+ });
+ } else {
+ buttonsNeedingFillAndStroke.forEach((btn) => {
+ $id(btn).disabled = false;
+ });
+ }
+
+ this.svgCanvas.runExtensions(
+ 'toolButtonStateUpdate',
+ /** @type {module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate} */ {
+ nofill: bNoFill,
+ nostroke: bNoStroke
+ }
+ );
+ }
+ /**
+ * @type {module}
+ */
+ updateColorpickers (apply) {
+ $id('fill_color').update(this.svgCanvas, this.selectedElement, apply);
+ $id('stroke_color').update(this.svgCanvas, this.selectedElement, apply);
+ }
+
+ /**
+ * @type {module}
+ */
+ handleColorPicker (type, evt) {
+ const {paint} = evt.detail;
+ this.svgCanvas.setPaint(type, paint);
+ this.updateToolButtonState();
+ }
+ /**
+ * @type {module}
+ */
+ handleStrokeAttr (type, evt) {
+ this.svgCanvas.setStrokeAttr(type, evt.currentTarget.value);
+ }
+ /**
+ * @type {module}
+ */
+ handleOpacity (evt) {
+ // if ($(this).find('div').length) { return; }
+ const val = Number.parseInt(evt.currentTarget.value.split('%')[0]);
+ this.svgCanvas.setOpacity(val / 100);
+ }
+ /**
+ * @type {module}
+ */
+ handlePalette (e) {
+ e.preventDefault();
+ // shift key or right click for stroke
+ const {picker, color} = e.detail;
+ // Webkit-based browsers returned 'initial' here for no stroke
+ const paint = color === 'none' ? new $.jGraduate.Paint() : new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)});
+ if (picker === 'fill') {
+ $id('fill_color').setPaint(paint);
+ } else {
+ $id('stroke_color').setPaint(paint);
+ }
+ this.svgCanvas.setColor(picker, color);
+ if (color !== 'none' && this.svgCanvas.getPaintOpacity(picker) !== 1) {
+ this.svgCanvas.setPaintOpacity(picker, 1.0);
+ }
+ this.updateToolButtonState();
+ }
+
+ /**
+ * @type {module}
+ */
+ init () {
+ // register actions for bottom panel
+ $id('zoom').addEventListener('change', (e) => this.changeZoom(e.detail.value).bind(this));
+ $id('stroke_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('stroke', evt));
+ $id('fill_color').addEventListener('change', (evt) => this.handleColorPicker.bind(this)('fill', evt));
+ $id('stroke_width').addEventListener('change', this.changeStrokeWidth.bind(this));
+ $id('stroke_style').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-dasharray', evt));
+ $id('stroke_linejoin').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linejoin', evt));
+ $id('stroke_linecap').addEventListener('change', (evt) => this.handleStrokeAttr.bind(this)('stroke-linecap', evt));
+ $id('opacity_dropdown').addEventListener('change', this.handleOpacity.bind(this));
+ $id('palette').addEventListener('change', this.handlePalette.bind(this));
+ }
+}
+
+export default BottomPanelHandlers;
diff --git a/src/editor/LayersPanel.js b/src/editor/panels/LayersPanel.js
similarity index 60%
rename from src/editor/LayersPanel.js
rename to src/editor/panels/LayersPanel.js
index 1e8d08d1..1b32e4de 100644
--- a/src/editor/LayersPanel.js
+++ b/src/editor/panels/LayersPanel.js
@@ -1,29 +1,147 @@
/* eslint-disable no-alert */
/* globals $ */
+import SvgCanvas from '../../svgcanvas/svgcanvas.js';
+
+const SIDEPANEL_MAXWIDTH = 300;
+const SIDEPANEL_OPENWIDTH = 150;
+const {$id} = SvgCanvas;
/**
*
*/
class LayersPanel {
/**
- * @param {PlainObject} svgCanvas svgCanvas
- * @param {PlainObject} uiStrings uiStrings
- * @param {GenericCallBack} updateContextPanel updateContextPanel
+ * @param {PlainObject} editor
*/
- constructor (svgCanvas, uiStrings, updateContextPanel) {
- this.svgCanvas = svgCanvas;
- this.uiStrings = uiStrings;
- this.updateContextPanel = updateContextPanel;
+ constructor (editor) {
+ this.svgCanvas = editor.canvas;
+ this.uiStrings = editor.uiStrings;
+ this.updateContextPanel = editor.topPanelHandlers.updateContextPanel;
+ this.sidedrag = -1;
+ this.sidedragging = false;
+ this.allowmove = false;
+ this.editor = editor;
+ }
+
+ /**
+ * @param {Float} delta
+ * @fires module:svgcanvas.SvgCanvas#event:ext_workareaResized
+ * @returns {void}
+ */
+ changeSidePanelWidth (delta) {
+ const rulerX = $('#ruler_x');
+ $('#sidepanels').width('+=' + delta);
+ $('#layerpanel').width('+=' + delta);
+ rulerX.css('right', Number.parseInt(rulerX.css('right')) + delta);
+ this.editor.workarea.css('right', Number.parseInt(this.editor.workarea.css('right')) + delta);
+ this.svgCanvas.runExtensions('workareaResized');
+ }
+
+ /**
+ * @param {Event} evt
+ * @returns {void}
+ */
+ resizeSidePanel (evt) {
+ if (!this.allowmove) { return; }
+ if (this.sidedrag === -1) { return; }
+ this.sidedragging = true;
+ let deltaX = this.sidedrag - evt.pageX;
+ const sideWidth = $('#sidepanels').width();
+ if (sideWidth + deltaX > SIDEPANEL_MAXWIDTH) {
+ deltaX = SIDEPANEL_MAXWIDTH - sideWidth;
+ // sideWidth = SIDEPANEL_MAXWIDTH;
+ } else if (sideWidth + deltaX < 2) {
+ deltaX = 2 - sideWidth;
+ // sideWidth = 2;
+ }
+ if (deltaX === 0) { return; }
+ this.sidedrag -= deltaX;
+ this.changeSidePanelWidth(deltaX);
+ }
+
+ /**
+ * If width is non-zero, then fully close it; otherwise fully open it.
+ * @param {boolean} close Forces the side panel closed
+ * @returns {void}
+ */
+ toggleSidePanel (close) {
+ const dpr = window.devicePixelRatio || 1;
+ const w = $('#sidepanels').width();
+ const isOpened = (dpr < 1 ? w : w / dpr) > 2;
+ const zoomAdjustedSidepanelWidth = (dpr < 1 ? 1 : dpr) * SIDEPANEL_OPENWIDTH;
+ const deltaX = (isOpened || close ? 0 : zoomAdjustedSidepanelWidth) - w;
+ this.changeSidePanelWidth(deltaX);
+ }
+ /**
+ * @param {PlainObject} e event
+ * @returns {void}
+ */
+ lmenuFunc (e) {
+ const action = e?.detail?.trigger;
+ switch (action) {
+ case 'dupe':
+ this.cloneLayer();
+ break;
+ case 'delete':
+ this.deleteLayer();
+ break;
+ case 'merge_down':
+ this.mergeLayer();
+ break;
+ case 'merge_all':
+ this.svgCanvas.mergeAllLayers();
+ this.updateContextPanel();
+ this.populateLayers();
+ break;
+ }
}
/**
* @returns {void}
*/
- addEvents () {
+ init () {
+ // layer menu added to DOM
+ const menuMore = document.createElement('se-cmenu-layers');
+ menuMore.setAttribute('id', 'se-cmenu-layers-more');
+ menuMore.value = 'layer_moreopts';
+ menuMore.setAttribute('leftclick', true);
+ document.body.append(menuMore);
+ const menuLayerBox = document.createElement('se-cmenu-layers');
+ menuLayerBox.setAttribute('id', 'se-cmenu-layers-list');
+ menuLayerBox.value = 'layerlist';
+ menuLayerBox.setAttribute('leftclick', false);
+ document.body.append(menuLayerBox);
document.getElementById('layer_new').addEventListener('click', this.newLayer.bind(this));
document.getElementById('layer_delete').addEventListener('click', this.deleteLayer.bind(this));
document.getElementById('layer_up').addEventListener('click', () => this.moveLayer.bind(this)(-1));
document.getElementById('layer_down').addEventListener('click', () => this.moveLayer.bind(this)(1));
document.getElementById('layer_rename').addEventListener('click', this.layerRename.bind(this));
+ $id('se-cmenu-layers-more').addEventListener('change', this.lmenuFunc.bind(this));
+ $id('se-cmenu-layers-list').addEventListener('change', (e) => {
+ this.lmenuFunc.bind(this)(e?.detail?.trigger, e?.detail?.source);
+ });
+ $id('sidepanel_handle').addEventListener('click', this.toggleSidePanel.bind(this));
+ if (this.editor.curConfig.showlayers) {
+ this.toggleSidePanel();
+ }
+ $id('sidepanel_handle').addEventListener('mousedown', (evt) => {
+ this.sidedrag = evt.pageX;
+ window.addEventListener('mousemove', this.resizeSidePanel.bind(this));
+ this.allowmove = false;
+ // Silly hack for Chrome, which always runs mousemove right after mousedown
+ setTimeout(() => {
+ this.allowmove = true;
+ }, 20);
+ });
+ $id('sidepanel_handle').addEventListener('mouseup', (evt) => {
+ if (!this.sidedragging) { this.toggleSidePanel(); }
+ this.sidedrag = -1;
+ this.sidedragging = false;
+ });
+ window.addEventListener('mouseup', (evt) => {
+ this.sidedrag = -1;
+ this.sidedragging = false;
+ $id('svg_editor').removeEventListener('mousemove', this.resizeSidePanel.bind(this));
+ });
}
/**
* @returns {void}
diff --git a/src/editor/panels/LeftPanelHandlers.js b/src/editor/panels/LeftPanelHandlers.js
new file mode 100644
index 00000000..82c5e247
--- /dev/null
+++ b/src/editor/panels/LeftPanelHandlers.js
@@ -0,0 +1,216 @@
+import SvgCanvas from '../../svgcanvas/svgcanvas.js';
+
+const {$id, $qa} = SvgCanvas;
+
+/*
+ * register actions for left panel
+ */
+/**
+ * @type {module}
+*/
+class LeftPanelHandlers {
+ /**
+ * @param {PlainObject} editor svgedit handler
+ */
+ constructor (editor) {
+ this.editor = editor;
+ this.svgCanvas = editor.canvas;
+ }
+ /**
+ * This is a common function used when a tool has been clicked (chosen).
+ * It does several common things:
+ * - Removes the pressed button from whatever tool currently has it.
+ * - Adds the the pressed button to the button passed in.
+ * @function this.updateLeftPanel
+ * @param {string|Element} button The DOM element or string selector representing the toolbar button
+ * @returns {boolean} Whether the button was disabled or not
+ */
+ // eslint-disable-next-line class-methods-use-this
+ updateLeftPanel (button) {
+ if (button.disabled) return false;
+ // remove the pressed state on other(s) button(s)
+ $qa('#tools_left *[pressed]').forEach((b) => { b.pressed = false; });
+ // pressed state for the clicked button
+ $id(button).pressed = true;
+ return true;
+ }
+
+ /**
+ * Unless the select toolbar button is disabled, sets the button
+ * and sets the select mode and cursor styles.
+ * @function module:SVGEditor.clickSelect
+ * @returns {void}
+ */
+ clickSelect () {
+ if (this.updateLeftPanel('tool_select')) {
+ this.editor.workarea.css('cursor', 'auto');
+ this.svgCanvas.setMode('select');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickFHPath () {
+ if (this.updateLeftPanel('tool_fhpath')) {
+ this.svgCanvas.setMode('fhpath');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickLine () {
+ if (this.updateLeftPanel('tool_line')) {
+ this.svgCanvas.setMode('line');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickSquare () {
+ if (this.updateLeftPanel('tool_square')) {
+ this.svgCanvas.setMode('square');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickRect () {
+ if (this.updateLeftPanel('tool_rect')) {
+ this.svgCanvas.setMode('rect');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickFHRect () {
+ if (this.updateLeftPanel('tool_fhrect')) {
+ this.svgCanvas.setMode('fhrect');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickCircle () {
+ if (this.updateLeftPanel('tool_circle')) {
+ this.svgCanvas.setMode('circle');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickEllipse () {
+ if (this.updateLeftPanel('tool_ellipse')) {
+ this.svgCanvas.setMode('ellipse');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickFHEllipse () {
+ if (this.updateLeftPanel('tool_fhellipse')) {
+ this.svgCanvas.setMode('fhellipse');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickImage () {
+ if (this.updateLeftPanel('tool_image')) {
+ this.svgCanvas.setMode('image');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickZoom () {
+ if (this.updateLeftPanel('tool_zoom')) {
+ this.svgCanvas.setMode('zoom');
+ this.editor.workarea.css('cursor', this.editor.zoomInIcon);
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ dblclickZoom () {
+ if (this.updateLeftPanel('tool_zoom')) {
+ this.editor.zoomImage();
+ this.clickSelect();
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickText () {
+ if (this.updateLeftPanel('tool_text')) {
+ this.svgCanvas.setMode('text');
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickPath () {
+ if (this.updateLeftPanel('tool_path')) {
+ this.svgCanvas.setMode('path');
+ }
+ }
+ /**
+ * @type {module}
+ */
+ add (id, handler) {
+ $id(id).addEventListener('click', () => {
+ if (this.updateLeftPanel(id)) {
+ handler();
+ }
+ });
+ }
+ /**
+ * @type {module}
+ */
+ init () {
+ // register actions for left panel
+ $id('tool_select').addEventListener('click', this.clickSelect.bind(this));
+ $id('tool_fhpath').addEventListener('click', this.clickFHPath.bind(this));
+ $id('tool_text').addEventListener('click', this.clickText.bind(this));
+ $id('tool_image').addEventListener('click', this.clickImage.bind(this));
+ $id('tool_zoom').addEventListener('click', this.clickZoom.bind(this));
+ $id('tool_zoom').addEventListener('dblclick', this.dblclickZoom.bind(this));
+ $id('tool_path').addEventListener('click', this.clickPath.bind(this));
+ $id('tool_line').addEventListener('click', this.clickLine.bind(this));
+
+ // flyout
+ $id('tool_rect').addEventListener('click', this.clickRect.bind(this));
+ $id('tool_square').addEventListener('click', this.clickSquare.bind(this));
+ $id('tool_fhrect').addEventListener('click', this.clickFHRect.bind(this));
+ $id('tool_ellipse').addEventListener('click', this.clickEllipse.bind(this));
+ $id('tool_circle').addEventListener('click', this.clickCircle.bind(this));
+ $id('tool_fhellipse').addEventListener('click', this.clickFHEllipse.bind(this));
+ }
+}
+
+export default LeftPanelHandlers;
diff --git a/src/editor/panels/TopPanelHandlers.js b/src/editor/panels/TopPanelHandlers.js
new file mode 100644
index 00000000..896294f6
--- /dev/null
+++ b/src/editor/panels/TopPanelHandlers.js
@@ -0,0 +1,632 @@
+/* globals $ */
+import SvgCanvas from '../../svgcanvas/svgcanvas.js';
+import {isValidUnit, getTypeMap, convertUnit} from '../../common/units.js';
+
+const {$id, isNullish} = SvgCanvas;
+
+/*
+ * register actions for left panel
+ */
+/**
+ *
+ */
+class TopPanelHandlers {
+ /**
+ * @param {PlainObject} editor svgedit handler
+ */
+ constructor (editor) {
+ this.editor = editor;
+ this.svgCanvas = editor.canvas;
+ this.uiStrings = editor.uiStrings;
+ }
+ /**
+ * @type {module}
+ */
+ get selectedElement () {
+ return this.editor.selectedElement;
+ }
+ /**
+ * @type {module}
+ */
+ get multiselected () {
+ return this.editor.multiselected;
+ }
+ /**
+ * @type {module}
+ */
+ get path () {
+ return this.svgCanvas.pathActions;
+ }
+ /**
+ * @param {PlainObject} [opts={}]
+ * @param {boolean} [opts.cancelDeletes=false]
+ * @returns {void} Resolves to `undefined`
+ */
+ promptImgURL ({cancelDeletes = false} = {}) {
+ let curhref = this.svgCanvas.getHref(this.selectedElement);
+ curhref = curhref.startsWith('data:') ? '' : curhref;
+ // eslint-disable-next-line no-alert
+ const url = prompt(this.editor.uiStrings.notification.enterNewImgURL, curhref);
+ if (url) {
+ this.editor.setImageURL(url);
+ } else if (cancelDeletes) {
+ this.svgCanvas.deleteSelectedElements();
+ }
+ }
+ /**
+ * Updates the context panel tools based on the selected element.
+ * @returns {void}
+ */
+ updateContextPanel () {
+ const setInputWidth = (elem) => {
+ const w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300);
+ $(elem).width(w);
+ };
+
+ let elem = this.selectedElement;
+ // If element has just been deleted, consider it null
+ if (!isNullish(elem) && !elem.parentNode) { elem = null; }
+ const currentLayerName = this.svgCanvas.getCurrentDrawing().getCurrentLayerName();
+ const currentMode = this.svgCanvas.getMode();
+ const unit = this.editor.configObj.curConfig.baseUnit !== 'px' ? this.editor.configObj.curConfig.baseUnit : null;
+
+ const isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false;
+ const menuItems = document.getElementById('se-cmenu_canvas');
+ $('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,' +
+ '#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel,' +
+ ' #use_panel, #a_panel').hide();
+ 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.svgCanvas.getRotationAngle(elem);
+ $('#angle').val(angle);
+
+ const blurval = this.svgCanvas.getBlur(elem) * 10;
+ $id('blur').value = blurval;
+
+ if (this.svgCanvas.addedNew &&
+ elname === 'image' &&
+ this.svgCanvas.getMode() === 'image' &&
+ !this.svgCanvas.getHref(elem).startsWith('data:')) {
+ /* await */ this.promptImgURL({cancelDeletes: true});
+ }
+
+ if (!isNode && currentMode !== 'pathedit') {
+ $('#selected_panel').show();
+ // Elements in this array already have coord fields
+ if (['line', 'circle', 'ellipse'].includes(elname)) {
+ $('#xy_panel').hide();
+ } else {
+ let x, y;
+
+ // Get BBox vals for g, polyline and path
+ if (['g', 'polyline', 'path'].includes(elname)) {
+ const bb = this.svgCanvas.getStrokedBBox([elem]);
+ if (bb) {
+ ({x, y} = bb);
+ }
+ } else {
+ x = elem.getAttribute('x');
+ y = elem.getAttribute('y');
+ }
+
+ if (unit) {
+ x = convertUnit(x);
+ y = convertUnit(y);
+ }
+
+ $('#selected_x').val(x || 0);
+ $('#selected_y').val(y || 0);
+ $('#xy_panel').show();
+ }
+
+ // Elements in this array cannot be converted to a path
+ $id('tool_topath').style.display = ['image', 'text', 'path', 'g', 'use'].includes(elname) ? 'none' : 'block';
+ $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);
+
+ // 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');
+ if (unit) {
+ point.x = convertUnit(point.x);
+ point.y = convertUnit(point.y);
+ }
+ $('#path_node_x').val(point.x);
+ $('#path_node_y').val(point.y);
+ if (point.type) {
+ segType.val(point.type).removeAttr('disabled');
+ } else {
+ segType.val(4).attr('disabled', 'disabled');
+ }
+ }
+ return;
+ }
+
+ // update contextual tools here
+ const panels = {
+ g: [],
+ a: [],
+ rect: ['rx', 'width', 'height'],
+ image: ['width', 'height'],
+ circle: ['cx', 'cy', 'r'],
+ ellipse: ['cx', 'cy', 'rx', 'ry'],
+ line: ['x1', 'y1', 'x2', 'y2'],
+ text: [],
+ use: []
+ };
+
+ const {tagName} = elem;
+
+ // if ($(elem).data('gsvg')) {
+ // $('#g_panel').show();
+ // }
+
+ let linkHref = null;
+ if (tagName === 'a') {
+ linkHref = this.svgCanvas.getHref(elem);
+ $('#g_panel').show();
+ }
+
+ if (elem.parentNode.tagName === 'a' && !$(elem).siblings().length) {
+ $('#a_panel').show();
+ linkHref = this.svgCanvas.getHref(elem.parentNode);
+ }
+
+ // Hide/show the make_link buttons
+ $('#tool_make_link, #tool_make_link_multi').toggle(!linkHref);
+
+ if (linkHref) {
+ $('#link_url').val(linkHref);
+ }
+
+ if (panels[tagName]) {
+ const curPanel = panels[tagName];
+
+ $('#' + tagName + '_panel').show();
+
+ curPanel.forEach((item) => {
+ let attrVal = elem.getAttribute(item);
+ if (this.editor.curConfig.baseUnit !== 'px' && elem[item]) {
+ const bv = elem[item].baseVal.value;
+ attrVal = convertUnit(bv);
+ }
+ $id(`${tagName}_${item}`).value = attrVal || 0;
+ });
+
+ if (tagName === 'text') {
+ $('#text_panel').css('display', 'inline');
+ $('#tool_font_size').css('display', 'inline');
+ $id('tool_italic').pressed = this.svgCanvas.getItalic();
+ $id('tool_bold').pressed = this.svgCanvas.getBold();
+ $('#font_family').val(elem.getAttribute('font-family'));
+ $('#font_size').val(elem.getAttribute('font-size'));
+ $('#text').val(elem.textContent);
+ const textAnchorStart = $id('tool_text_anchor_start');
+ const textAnchorMiddle = $id('tool_text_anchor_middle');
+ const textAnchorEnd = $id('tool_text_anchor_end');
+ switch (elem.getAttribute('text-anchor')) {
+ case 'start':
+ textAnchorStart.pressed = true;
+ textAnchorMiddle.pressed = false;
+ textAnchorEnd.pressed = false;
+ break;
+ case 'middle':
+ textAnchorStart.pressed = false;
+ textAnchorMiddle.pressed = true;
+ textAnchorEnd.pressed = false;
+ break;
+ case 'end':
+ textAnchorStart.pressed = false;
+ textAnchorMiddle.pressed = false;
+ textAnchorEnd.pressed = true;
+ break;
+ }
+ if (this.svgCanvas.addedNew) {
+ // Timeout needed for IE9
+ setTimeout(() => {
+ $('#text').focus().select();
+ }, 100);
+ }
+ // text
+ } else if (tagName === 'image' && this.svgCanvas.getMode() === 'image') {
+ this.svgCanvas.setImageURL(this.svgCanvas.getHref(elem));
+ // image
+ } else if (tagName === 'g' || tagName === 'use') {
+ $('#container_panel').show();
+ const title = this.svgCanvas.getTitle();
+ const label = $('#g_title')[0];
+ label.value = title;
+ setInputWidth(label);
+ $('#g_title').prop('disabled', tagName === 'use');
+ }
+ }
+ menuItems.setAttribute((tagName === 'g' ? 'en' : 'dis') + 'ablemenuitems', '#ungroup');
+ menuItems.setAttribute(((tagName === 'g' || !this.multiselected) ? 'dis' : 'en') + 'ablemenuitems', '#group');
+
+ // if (!isNullish(elem))
+ } else if (this.multiselected) {
+ $('#multiselected_panel').show();
+ menuItems.setAttribute('enablemenuitems', '#group');
+ menuItems.setAttribute('disablemenuitems', '#ungroup');
+ } else {
+ menuItems.setAttribute('disablemenuitems', '#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back');
+ }
+
+ // update history buttons
+ $id('tool_undo').disabled = (this.editor.canvas.undoMgr.getUndoStackSize() === 0);
+ $id('tool_redo').disabled = (this.editor.canvas.undoMgr.getRedoStackSize() === 0);
+
+ this.svgCanvas.addedNew = false;
+
+ if ((elem && !isNode) || this.multiselected) {
+ // update the selected elements' layer
+ $('#selLayerNames').removeAttr('disabled').val(currentLayerName);
+
+ // Enable regular menu options
+ const canCMenu = document.getElementById('se-cmenu_canvas');
+ canCMenu.setAttribute('enablemenuitems', '#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back');
+ } else {
+ $('#selLayerNames').attr('disabled', 'disabled');
+ }
+ }
+ /**
+ * @param {Event} [e] Not used.
+ * @param {boolean} forSaving
+ * @returns {void}
+ */
+ showSourceEditor (e, forSaving) {
+ const $editorDialog = document.getElementById('se-svg-editor-dialog');
+ if ($editorDialog.getAttribute('dialog') === 'open') return;
+ const origSource = this.svgCanvas.getSvgString();
+ $editorDialog.setAttribute('dialog', 'open');
+ $editorDialog.setAttribute('value', origSource);
+ $editorDialog.setAttribute('copysec', Boolean(forSaving));
+ $editorDialog.setAttribute('applysec', !forSaving);
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ clickWireframe () {
+ $id('tool_wireframe').pressed = !$id('tool_wireframe').pressed;
+ this.editor.workarea.toggleClass('wireframe');
+
+ const wfRules = $('#wireframe_rules');
+ if (!wfRules.length) {
+ /* wfRules = */ $('').appendTo('head');
+ } else {
+ wfRules.empty();
+ }
+ this.editor.updateWireFrame();
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ clickUndo () {
+ const {undoMgr} = this.editor;
+ if (undoMgr.getUndoStackSize() > 0) {
+ undoMgr.undo();
+ this.editor.layersPanel.populateLayers();
+ }
+ }
+
+ /**
+ *
+ * @returns {void}
+ */
+ clickRedo () {
+ const {undoMgr} = this.editor.canvas;
+ if (undoMgr.getRedoStackSize() > 0) {
+ undoMgr.redo();
+ this.editor.layersPanel.populateLayers();
+ }
+ }
+ /**
+ * @type {module}
+ */
+ changeRectRadius (e) {
+ this.svgCanvas.setRectRadius(e.target.value);
+ }
+
+ /**
+* @type {module}
+*/
+ changeFontSize (e) {
+ this.svgCanvas.setFontSize(e.target.value);
+ }
+
+ /**
+* @type {module}
+*/
+ changeRotationAngle (e) {
+ this.svgCanvas.setRotationAngle(e.target.value);
+ $('#tool_reorient').toggleClass('disabled', Number.parseInt(e.target.value) === 0);
+ }
+
+ /**
+* @param {PlainObject} e
+* @returns {void}
+*/
+ changeBlur (e) {
+ this.svgCanvas.setBlur(e.target.value / 10, true);
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ clickGroup () {
+ // group
+ if (this.editor.multiselected) {
+ this.svgCanvas.groupSelectedElements();
+ // ungroup
+ } else if (this.editor.selectedElement) {
+ this.svgCanvas.ungroupSelectedElement();
+ }
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ clickClone () {
+ this.svgCanvas.cloneSelectedElements(20, 20);
+ }
+
+ /**
+* @param {string} pos indicate the alignment relative to top, bottom, middle etc..
+* @returns {void}
+*/
+ clickAlign (pos) {
+ this.svgCanvas.alignSelectedElements(pos, $('#align_relative_to').val());
+ }
+ /**
+*
+* @type {module}
+*/
+ attrChanger (e) {
+ const attr = e.target.getAttribute('data-attr');
+ let val = e.target.value;
+ const valid = isValidUnit(attr, val, this.selectedElement);
+
+ if (!valid) {
+ e.target.value = this.selectedElement().getAttribute(attr);
+ // eslint-disable-next-line no-alert
+ alert(this.uiStrings.notification.invalidAttrValGiven);
+ return false;
+ }
+
+ if (attr !== 'id' && attr !== 'class') {
+ if (isNaN(val)) {
+ val = this.svgCanvas.convertToNum(attr, val);
+ } else if (this.configObj.curConfig.baseUnit !== 'px') {
+ // Convert unitless value to one with given unit
+
+ const unitData = getTypeMap();
+
+ if (this.selectedElement[attr] || this.svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
+ val *= unitData[this.configObj.curConfig.baseUnit];
+ }
+ }
+ }
+
+ // if the user is changing the id, then de-select the element first
+ // change the ID, then re-select it with the new ID
+ if (attr === 'id') {
+ const elem = this.selectedElement;
+ this.svgCanvas.clearSelection();
+ elem.id = val;
+ this.svgCanvas.addToSelection([elem], true);
+ } else {
+ this.svgCanvas.changeSelectedAttribute(attr, val);
+ }
+ return true;
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ convertToPath () {
+ if (!isNullish(this.selectedElement)) {
+ this.svgCanvas.convertToPath();
+ }
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ reorientPath () {
+ if (!isNullish(this.selectedElement)) {
+ this.path.reorient();
+ }
+ }
+ /**
+ *
+ * @returns {void} Resolves to `undefined`
+ */
+ makeHyperlink () {
+ if (!isNullish(this.selectedElement) || this.multiselected) {
+ // eslint-disable-next-line no-alert
+ const url = prompt(this.uiStrings.notification.enterNewLinkURL, 'http://');
+ if (url) {
+ this.svgCanvas.makeHyperlink(url);
+ }
+ }
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ linkControlPoints () {
+ const linked = $id('tool_node_link').pressed;
+ $id('tool_node_link').pressed = !linked;
+ this.path.linkControlPoints(linked);
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ clonePathNode () {
+ if (this.path.getNodePoint()) {
+ this.path.clonePathNode();
+ }
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ deletePathNode () {
+ if (this.path.getNodePoint()) {
+ this.path.deletePathNode();
+ }
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ addSubPath () {
+ const button = $('#tool_add_subpath');
+ const sp = !button.hasClass('pressed');
+ button.pressed = sp;
+ // button.toggleClass('push_button_pressed tool_button');
+ this.path.addSubPath(sp);
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ opencloseSubPath () {
+ this.path.opencloseSubPath();
+ }
+ /**
+ * Delete is a contextual tool that only appears in the ribbon if
+ * an element has been selected.
+ * @returns {void}
+ */
+ deleteSelected () {
+ if (!isNullish(this.selectedElement) || this.multiselected) {
+ this.svgCanvas.deleteSelectedElements();
+ }
+ }
+ /**
+ *
+ * @returns {void}
+ */
+ moveToTopSelected () {
+ if (!isNullish(this.selectedElement)) {
+ this.svgCanvas.moveToTopSelectedElement();
+ }
+ }
+
+ /**
+*
+* @returns {void}
+*/
+ moveToBottomSelected () {
+ if (!isNullish(this.selectedElement)) {
+ this.svgCanvas.moveToBottomSelectedElement();
+ }
+ }
+ /**
+ *
+ * @returns {false}
+ */
+ clickBold () {
+ this.svgCanvas.setBold(!this.svgCanvas.getBold());
+ this.updateContextPanel();
+ return false;
+ }
+
+ /**
+*
+* @returns {false}
+*/
+ clickItalic () {
+ this.svgCanvas.setItalic(!this.svgCanvas.getItalic());
+ this.updateContextPanel();
+ return false;
+ }
+
+ /**
+ *
+ * @param {string} value "start","end" or "middle"
+ * @returns {false}
+ */
+ clickTextAnchor (value) {
+ this.svgCanvas.setTextAnchor(value);
+ this.updateContextPanel();
+ return false;
+ }
+
+ /**
+ * @type {module}
+ */
+ init () {
+ // svg editor source dialoag added to DOM
+ const newSeEditorDialog = document.createElement('se-svg-source-editor-dialog');
+ newSeEditorDialog.setAttribute('id', 'se-svg-editor-dialog');
+ document.body.append(newSeEditorDialog);
+ // register action to top panel buttons
+ $id('tool_source').addEventListener('click', this.showSourceEditor.bind(this));
+ $id('tool_wireframe').addEventListener('click', this.clickWireframe.bind(this));
+ $id('tool_undo').addEventListener('click', this.clickUndo.bind(this));
+ $id('tool_redo').addEventListener('click', this.clickRedo.bind(this));
+ $id('tool_clone').addEventListener('click', this.clickClone.bind(this));
+ $id('tool_clone_multi').addEventListener('click', this.clickClone.bind(this));
+ $id('tool_delete').addEventListener('click', this.deleteSelected.bind(this));
+ $id('tool_delete_multi').addEventListener('click', this.deleteSelected.bind(this));
+ $id('tool_move_top').addEventListener('click', this.moveToTopSelected.bind(this));
+ $id('tool_move_bottom').addEventListener('click', this.moveToBottomSelected.bind(this));
+ $id('tool_topath').addEventListener('click', this.convertToPath.bind(this));
+ $id('tool_make_link').addEventListener('click', this.makeHyperlink.bind(this));
+ $id('tool_make_link_multi').addEventListener('click', this.makeHyperlink.bind(this));
+ $id('tool_reorient').addEventListener('click', this.reorientPath.bind(this));
+ $id('tool_group_elements').addEventListener('click', this.clickGroup.bind(this));
+ $id('tool_align_left').addEventListener('click', () => this.clickAlign.bind(this)('left'));
+ $id('tool_align_right').addEventListener('click', () => this.clickAlign.bind(this)('right'));
+ $id('tool_align_center').addEventListener('click', () => this.clickAlign.bind(this)('center'));
+ $id('tool_align_top').addEventListener('click', () => this.clickAlign.bind(this)('top'));
+ $id('tool_align_bottom').addEventListener('click', () => this.clickAlign.bind(this)('bottom'));
+ $id('tool_align_middle').addEventListener('click', () => this.clickAlign.bind(this)('middle'));
+ $id('tool_node_clone').addEventListener('click', this.clonePathNode.bind(this));
+ $id('tool_node_delete').addEventListener('click', this.deletePathNode.bind(this));
+ $id('tool_openclose_path').addEventListener('click', this.opencloseSubPath.bind(this));
+ $id('tool_add_subpath').addEventListener('click', this.addSubPath.bind(this));
+ $id('tool_node_link').addEventListener('click', this.linkControlPoints.bind(this));
+ $id('angle').addEventListener('change', this.changeRotationAngle.bind(this));
+ $id('blur').addEventListener('change', this.changeBlur.bind(this));
+ $id('rect_rx').addEventListener('change', this.changeRectRadius.bind(this));
+ $id('font_size').addEventListener('change', this.changeFontSize.bind(this));
+ $id('tool_ungroup').addEventListener('click', this.clickGroup.bind(this));
+ $id('tool_bold').addEventListener('click', this.clickBold.bind(this));
+ $id('tool_italic').addEventListener('click', this.clickItalic.bind(this));
+ $id('tool_text_anchor_start').addEventListener('click', () => this.clickTextAnchor.bind(this)('start'));
+ $id('tool_text_anchor_middle').addEventListener('click', () => this.clickTextAnchor.bind(this)('middle'));
+ $id('tool_text_anchor_end').addEventListener('click', () => this.clickTextAnchor.bind(this)('end'));
+ $id('tool_unlink_use').addEventListener('click', this.clickGroup.bind(this));
+ $id('change_image_url').addEventListener('click', this.promptImgURL.bind(this));
+ // all top panel attributes
+ ['elem_id', 'elem_class', 'circle_cx', 'circle_cy', 'circle_r', 'ellipse_cx',
+ 'ellipse_cy', 'ellipse_rx', 'ellipse_ry', 'selected_x', 'selected_y', 'rect_width',
+ 'rect_height', 'line_x1', 'line_x2', 'line_y2', 'image_width', 'image_height', 'path_node_x',
+ 'path_node_y'].forEach((attrId) => $id(attrId).addEventListener('change', this.attrChanger.bind(this)));
+ }
+}
+
+export default TopPanelHandlers;
diff --git a/src/editor/svgedit.js b/src/editor/svgedit.js
index 08c661a4..a6faf737 100644
--- a/src/editor/svgedit.js
+++ b/src/editor/svgedit.js
@@ -27,14 +27,17 @@ import {
import SvgCanvas from '../svgcanvas/svgcanvas.js';
import jQueryPluginJSHotkeys from './js-hotkeys/jquery.hotkeys.min.js';
import ConfigObj from './ConfigObj.js';
-import LayersPanel from './LayersPanel.js';
+import LayersPanel from './panels/LayersPanel.js';
+import LeftPanelHandlers from './panels/LeftPanelHandlers.js';
+import BottomPanelHandlers from './panels/BottomPanelHandlers.js';
+import TopPanelHandlers from './panels/TopPanelHandlers.js';
import {
readLang, putLocale,
setStrings
} from './locale.js';
-const {$id, $qa, isNullish, encode64, decode64, blankPageObjectURL} = SvgCanvas;
+const {$id, isNullish, encode64, decode64, blankPageObjectURL} = SvgCanvas;
const editor = {
/**
@@ -98,16 +101,11 @@ const loadSvgString = (str, {noAlert} = {}) => {
throw new Error('Error loading SVG');
};
-const configObj = new ConfigObj(editor);
-
-/**
-* EXPORTS.
-*/
-
-editor.pref = configObj.pref.bind(configObj);
-editor.setConfig = configObj.setConfig.bind(configObj);
-editor.curPrefs = configObj.curPrefs;
-editor.curConfig = configObj.curConfig;
+editor.configObj = new ConfigObj(editor);
+editor.pref = editor.configObj.pref.bind(editor.configObj);
+editor.setConfig = editor.configObj.setConfig.bind(editor.configObj);
+editor.curPrefs = editor.configObj.curPrefs;
+editor.curConfig = editor.configObj.curConfig;
/**
* All methods are optional.
@@ -220,28 +218,13 @@ editor.init = () => {
const newSeEditPrefsDialog = document.createElement('se-edit-prefs-dialog');
newSeEditPrefsDialog.setAttribute('id', 'se-edit-prefs');
document.body.append(newSeEditPrefsDialog);
- // svg editor source dialoag added to DOM
- const newSeEditorDialog = document.createElement('se-svg-source-editor-dialog');
- newSeEditorDialog.setAttribute('id', 'se-svg-editor-dialog');
- document.body.append(newSeEditorDialog);
// canvas menu added to DOM
const dialogBox = document.createElement('se-cmenu_canvas-dialog');
dialogBox.setAttribute('id', 'se-cmenu_canvas');
document.body.append(dialogBox);
- // layer menu added to DOM
- const menuMore = document.createElement('se-cmenu-layers');
- menuMore.setAttribute('id', 'se-cmenu-layers-more');
- menuMore.value = 'layer_moreopts';
- menuMore.setAttribute('leftclick', true);
- document.body.append(menuMore);
- const menuLayerBox = document.createElement('se-cmenu-layers');
- menuLayerBox.setAttribute('id', 'se-cmenu-layers-list');
- menuLayerBox.value = 'layerlist';
- menuLayerBox.setAttribute('leftclick', false);
- document.body.append(menuLayerBox);
} catch (err) {}
- configObj.load();
+ editor.configObj.load();
// eslint-disable-next-line max-len
const goodLangs = ['ar', 'cs', 'de', 'en', 'es', 'fa', 'fr', 'fy', 'hi', 'it', 'ja', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'zh-CN', 'zh-TW'];
@@ -261,7 +244,7 @@ editor.init = () => {
try {
// load standard extensions
await Promise.all(
- configObj.curConfig.extensions.map(async (extname) => {
+ editor.configObj.curConfig.extensions.map(async (extname) => {
/**
* @tutorial ExtensionDocs
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
@@ -284,7 +267,7 @@ editor.init = () => {
);
// load user extensions (given as pathNames)
await Promise.all(
- configObj.curConfig.userExtensions.map(async (extPathName) => {
+ editor.configObj.curConfig.userExtensions.map(async (extPathName) => {
/**
* @tutorial ExtensionDocs
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
@@ -346,242 +329,21 @@ editor.init = () => {
*/
editor.canvas = svgCanvas = new SvgCanvas(
$id('svgcanvas'),
- configObj.curConfig
+ editor.configObj.curConfig
);
- /**
- * Updates the context panel tools based on the selected element.
- * @returns {void}
- */
- const updateContextPanel = () => {
- let elem = selectedElement;
- // If element has just been deleted, consider it null
- if (!isNullish(elem) && !elem.parentNode) { elem = null; }
- const currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName();
- const currentMode = svgCanvas.getMode();
- const unit = configObj.curConfig.baseUnit !== 'px' ? configObj.curConfig.baseUnit : null;
-
- const isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false;
- const menuItems = document.getElementById('se-cmenu_canvas');
- $('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,' +
- '#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel,' +
- ' #use_panel, #a_panel').hide();
- 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 = svgCanvas.getRotationAngle(elem);
- $('#angle').val(angle);
-
- const blurval = svgCanvas.getBlur(elem) * 10;
- $id('blur').value = blurval;
-
- if (svgCanvas.addedNew &&
- elname === 'image' &&
- svgCanvas.getMode() === 'image' &&
- !svgCanvas.getHref(elem).startsWith('data:')) {
- /* await */ promptImgURL({cancelDeletes: true});
- }
-
- if (!isNode && currentMode !== 'pathedit') {
- $('#selected_panel').show();
- // Elements in this array already have coord fields
- if (['line', 'circle', 'ellipse'].includes(elname)) {
- $('#xy_panel').hide();
- } else {
- let x, y;
-
- // Get BBox vals for g, polyline and path
- if (['g', 'polyline', 'path'].includes(elname)) {
- const bb = svgCanvas.getStrokedBBox([elem]);
- if (bb) {
- ({x, y} = bb);
- }
- } else {
- x = elem.getAttribute('x');
- y = elem.getAttribute('y');
- }
-
- if (unit) {
- x = convertUnit(x);
- y = convertUnit(y);
- }
-
- $('#selected_x').val(x || 0);
- $('#selected_y').val(y || 0);
- $('#xy_panel').show();
- }
-
- // Elements in this array cannot be converted to a path
- $id('tool_topath').style.display = ['image', 'text', 'path', 'g', 'use'].includes(elname) ? 'none' : 'block';
- $id('tool_reorient').style.display = (elname === 'path') ? 'block' : 'none';
- $id('tool_reorient').disabled = (angle === 0);
- } else {
- const point = path.getNodePoint();
- $('#tool_add_subpath').pressed = false;
- $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes);
-
- // 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');
- if (unit) {
- point.x = convertUnit(point.x);
- point.y = convertUnit(point.y);
- }
- $('#path_node_x').val(point.x);
- $('#path_node_y').val(point.y);
- if (point.type) {
- segType.val(point.type).removeAttr('disabled');
- } else {
- segType.val(4).attr('disabled', 'disabled');
- }
- }
- return;
- }
-
- // update contextual tools here
- const panels = {
- g: [],
- a: [],
- rect: ['rx', 'width', 'height'],
- image: ['width', 'height'],
- circle: ['cx', 'cy', 'r'],
- ellipse: ['cx', 'cy', 'rx', 'ry'],
- line: ['x1', 'y1', 'x2', 'y2'],
- text: [],
- use: []
- };
-
- const {tagName} = elem;
-
- // if ($(elem).data('gsvg')) {
- // $('#g_panel').show();
- // }
-
- let linkHref = null;
- if (tagName === 'a') {
- linkHref = svgCanvas.getHref(elem);
- $('#g_panel').show();
- }
-
- if (elem.parentNode.tagName === 'a' && !$(elem).siblings().length) {
- $('#a_panel').show();
- linkHref = svgCanvas.getHref(elem.parentNode);
- }
-
- // Hide/show the make_link buttons
- $('#tool_make_link, #tool_make_link_multi').toggle(!linkHref);
-
- if (linkHref) {
- $('#link_url').val(linkHref);
- }
-
- if (panels[tagName]) {
- const curPanel = panels[tagName];
-
- $('#' + tagName + '_panel').show();
-
- $.each(curPanel, function (i, item) {
- let attrVal = elem.getAttribute(item);
- if (configObj.curConfig.baseUnit !== 'px' && elem[item]) {
- const bv = elem[item].baseVal.value;
- attrVal = convertUnit(bv);
- }
- $('#' + tagName + '_' + item).val(attrVal || 0);
- });
-
- if (tagName === 'text') {
- $('#text_panel').css('display', 'inline');
- $('#tool_font_size').css('display', 'inline');
- $id('tool_italic').pressed = svgCanvas.getItalic();
- $id('tool_bold').pressed = svgCanvas.getBold();
- $('#font_family').val(elem.getAttribute('font-family'));
- $('#font_size').val(elem.getAttribute('font-size'));
- $('#text').val(elem.textContent);
- const textAnchorStart = $id('tool_text_anchor_start');
- const textAnchorMiddle = $id('tool_text_anchor_middle');
- const textAnchorEnd = $id('tool_text_anchor_end');
- switch (elem.getAttribute('text-anchor')) {
- case 'start':
- textAnchorStart.pressed = true;
- textAnchorMiddle.pressed = false;
- textAnchorEnd.pressed = false;
- break;
- case 'middle':
- textAnchorStart.pressed = false;
- textAnchorMiddle.pressed = true;
- textAnchorEnd.pressed = false;
- break;
- case 'end':
- textAnchorStart.pressed = false;
- textAnchorMiddle.pressed = false;
- textAnchorEnd.pressed = true;
- break;
- }
- if (svgCanvas.addedNew) {
- // Timeout needed for IE9
- setTimeout(() => {
- $('#text').focus().select();
- }, 100);
- }
- // text
- } else if (tagName === 'image' && svgCanvas.getMode() === 'image') {
- setImageURL(svgCanvas.getHref(elem));
- // image
- } else if (tagName === 'g' || tagName === 'use') {
- $('#container_panel').show();
- const title = svgCanvas.getTitle();
- const label = $('#g_title')[0];
- label.value = title;
- setInputWidth(label);
- $('#g_title').prop('disabled', tagName === 'use');
- }
- }
- menuItems.setAttribute((tagName === 'g' ? 'en' : 'dis') + 'ablemenuitems', '#ungroup');
- menuItems.setAttribute(((tagName === 'g' || !multiselected) ? 'dis' : 'en') + 'ablemenuitems', '#group');
-
- // if (!isNullish(elem))
- } else if (multiselected) {
- $('#multiselected_panel').show();
- menuItems.setAttribute('enablemenuitems', '#group');
- menuItems.setAttribute('disablemenuitems', '#ungroup');
- } else {
- menuItems.setAttribute('disablemenuitems', '#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back');
- }
-
- // update history buttons
- $id('tool_undo').disabled = (undoMgr.getUndoStackSize() === 0);
- $id('tool_redo').disabled = (undoMgr.getRedoStackSize() === 0);
-
- svgCanvas.addedNew = false;
-
- if ((elem && !isNode) || multiselected) {
- // update the selected elements' layer
- $('#selLayerNames').removeAttr('disabled').val(currentLayerName);
-
- // Enable regular menu options
- const canCMenu = document.getElementById('se-cmenu_canvas');
- canCMenu.setAttribute('enablemenuitems', '#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back');
- } else {
- $('#selLayerNames').attr('disabled', 'disabled');
- }
- };
-
- const layersPanel = new LayersPanel(svgCanvas, uiStrings, updateContextPanel);
+ editor.leftPanelHandlers = new LeftPanelHandlers(editor);
+ editor.bottomPanelHandlers = new BottomPanelHandlers(editor);
+ editor.topPanelHandlers = new TopPanelHandlers(editor);
+ editor.layersPanel = new LayersPanel(editor);
const modKey = (isMac() ? 'meta+' : 'ctrl+');
- const path = svgCanvas.pathActions;
const {undoMgr} = svgCanvas;
const workarea = $('#workarea');
+ editor.workarea = workarea;
const canvMenu = document.getElementById('se-cmenu_canvas');
let exportWindow = null;
- let defaultImageURL = configObj.curConfig.imgPath + 'logo.svg';
+ let defaultImageURL = editor.configObj.curConfig.imgPath + 'logo.svg';
const zoomInIcon = 'crosshair';
const zoomOutIcon = 'crosshair';
let uiContext = 'toolbars';
@@ -621,29 +383,9 @@ editor.init = () => {
rIntervals.push(5 * i);
}
- layersPanel.populateLayers();
-
- let editingsource = false;
- let origSource = '';
-
- /**
- * @param {Event} [e] Not used.
- * @param {boolean} forSaving
- * @returns {void}
- */
- const showSourceEditor = function (e, forSaving) {
- if (editingsource) { return; }
- editingsource = true;
- origSource = svgCanvas.getSvgString();
- const $editorDialog = document.getElementById('se-svg-editor-dialog');
- $editorDialog.setAttribute('dialog', 'open');
- $editorDialog.setAttribute('value', origSource);
- $editorDialog.setAttribute('copysec', Boolean(forSaving));
- $editorDialog.setAttribute('applysec', !forSaving);
- };
-
- let selectedElement = null;
- let multiselected = false;
+ editor.layersPanel.populateLayers();
+ editor.selectedElement = null;
+ editor.multiselected = false;
/**
* @param {boolean} editmode
@@ -656,9 +398,9 @@ editor.init = () => {
// Change select icon
$('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
$('#tool_select').addClass('tool_button_current').removeClass('tool_button');
- multiselected = false;
+ editor.multiselected = false;
if (elems.length) {
- selectedElement = elems[0];
+ editor.selectedElement = elems[0];
}
} else {
setTimeout(() => {
@@ -767,37 +509,6 @@ editor.init = () => {
$(opt).addClass('current').siblings().removeClass('current');
}
- /**
- * This is a common function used when a tool has been clicked (chosen).
- * It does several common things:
- * - Removes the `tool_button_current` class from whatever tool currently has it.
- * - Adds the `tool_button_current` class to the button passed in.
- * @function updateLeftPanel
- * @param {string|Element} button The DOM element or string selector representing the toolbar button
- * @returns {boolean} Whether the button was disabled or not
- */
- const updateLeftPanel = (button) => {
- if (button.disabled) return false;
- // remove the pressed state on other(s) button(s)
- $qa('#tools_left *[pressed]').forEach((b) => { b.pressed = false; });
- // pressed state for the clicked button
- $id(button).pressed = true;
- return true;
- };
-
- /**
- * Unless the select toolbar button is disabled, sets the button
- * and sets the select mode and cursor styles.
- * @function module:SVGEditor.clickSelect
- * @returns {void}
- */
- const clickSelect = () => {
- if (updateLeftPanel('tool_select')) {
- workarea.css('cursor', 'auto');
- svgCanvas.setMode('select');
- }
- };
-
/**
* Set a selected image's URL.
* @function module:SVGEditor.setImageURL
@@ -842,31 +553,6 @@ editor.init = () => {
svgCanvas.setBackground(color, url);
}
- /**
- * @param {PlainObject} [opts={}]
- * @param {boolean} [opts.cancelDeletes=false]
- * @returns {void} Resolves to `undefined`
- */
- function promptImgURL ({cancelDeletes = false} = {}) {
- let curhref = svgCanvas.getHref(selectedElement);
- curhref = curhref.startsWith('data:') ? '' : curhref;
- const url = prompt(uiStrings.notification.enterNewImgURL, curhref);
- if (url) {
- setImageURL(url);
- } else if (cancelDeletes) {
- svgCanvas.deleteSelectedElements();
- }
- }
-
- /**
- * @param {Element} elem
- * @returns {void}
- */
- const setInputWidth = (elem) => {
- const w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300);
- $(elem).width(w);
- };
-
/**
*
* @param {HTMLDivElement} [scanvas]
@@ -881,7 +567,7 @@ editor.init = () => {
const limit = 30000;
const contentElem = svgCanvas.getContentElem();
const units = getTypeMap();
- const unit = units[configObj.curConfig.baseUnit]; // 1 = 1px
+ const unit = units[editor.configObj.curConfig.baseUnit]; // 1 = 1px
// draw x ruler then y ruler
for (d = 0; d < 2; d++) {
@@ -1041,7 +727,7 @@ editor.init = () => {
x: wArea[0].scrollLeft + wOrig / 2,
y: wArea[0].scrollTop + hOrig / 2
};
- const multi = configObj.curConfig.canvas_expansion;
+ const multi = editor.configObj.curConfig.canvas_expansion;
w = Math.max(wOrig, svgCanvas.contentW * zoom * multi);
h = Math.max(hOrig, svgCanvas.contentH * zoom * multi);
@@ -1094,71 +780,16 @@ editor.init = () => {
wArea[0].scrollLeft = newCtr.x - wOrig / 2;
wArea[0].scrollTop = newCtr.y - hOrig / 2;
}
- if (configObj.curConfig.showRulers) {
+ if (editor.configObj.curConfig.showRulers) {
updateRulers(cnvs, zoom);
workarea.scroll();
}
- if (configObj.urldata.storagePrompt !== true && editor.storagePromptState === 'ignore') {
+ if (editor.configObj.urldata.storagePrompt !== true && editor.storagePromptState === 'ignore') {
$('#dialog_box').hide();
}
};
- /**
- * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate
- * @returns {void}
- */
- const updateToolButtonState = () => {
- const bNoFill = (svgCanvas.getColor('fill') === 'none');
- const bNoStroke = (svgCanvas.getColor('stroke') === 'none');
- const buttonsNeedingStroke = ['tool_fhpath', 'tool_line'];
- const buttonsNeedingFillAndStroke = [
- 'tools_rect', 'tools_ellipse',
- 'tool_text', 'tool_path'
- ];
-
- if (bNoStroke) {
- buttonsNeedingStroke.forEach((btn) => {
- // if btn is pressed, change to select button
- if ($id(btn).pressed) {
- clickSelect();
- }
- $(btn).disabled = true;
- });
- } else {
- buttonsNeedingStroke.forEach((btn) => {
- $id(btn).disabled = false;
- });
- }
-
- if (bNoStroke && bNoFill) {
- buttonsNeedingFillAndStroke.forEach((btn) => {
- // if btn is pressed, change to select button
- if ($id(btn).pressed) {
- clickSelect();
- }
- $(btn).disabled = true;
- });
- } else {
- buttonsNeedingFillAndStroke.forEach((btn) => {
- $id(btn).disabled = false;
- });
- }
-
- svgCanvas.runExtensions(
- 'toolButtonStateUpdate',
- /** @type {module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate} */ {
- nofill: bNoFill,
- nostroke: bNoStroke
- }
- );
- };
-
- const updateColorpickers = (apply) => {
- $id('fill_color').update(svgCanvas, selectedElement, apply);
- $id('stroke_color').update(svgCanvas, selectedElement, apply);
- };
-
/**
* Updates the toolbar (colors, opacity, etc) based on the selected element.
* This function also updates the opacity and id elements that are in the
@@ -1167,8 +798,8 @@ editor.init = () => {
*/
const updateToolbar = () => {
let i, len;
- if (!isNullish(selectedElement)) {
- switch (selectedElement.tagName) {
+ if (!isNullish(editor.selectedElement)) {
+ switch (editor.selectedElement.tagName) {
case 'use':
case 'image':
case 'foreignObject':
@@ -1176,7 +807,7 @@ editor.init = () => {
case 'g':
case 'a': {
// Look for common styles
- const childs = selectedElement.getElementsByTagName('*');
+ const childs = editor.selectedElement.getElementsByTagName('*');
let gWidth = null;
for (i = 0, len = childs.length; i < len; i++) {
const swidth = childs[i].getAttribute('stroke-width');
@@ -1189,21 +820,21 @@ editor.init = () => {
}
$('#stroke_width').val(gWidth === null ? '' : gWidth);
- updateColorpickers(true);
+ editor.bottomPanelHandlers.updateColorpickers(true);
break;
} default: {
- updateColorpickers(true);
+ editor.bottomPanelHandlers.updateColorpickers(true);
- $('#stroke_width').val(selectedElement.getAttribute('stroke-width') || 1);
- $('#stroke_style').val(selectedElement.getAttribute('stroke-dasharray') || 'none');
+ $('#stroke_width').val(editor.selectedElement.getAttribute('stroke-width') || 1);
+ $('#stroke_style').val(editor.selectedElement.getAttribute('stroke-dasharray') || 'none');
- let attr = selectedElement.getAttribute('stroke-linejoin') || 'miter';
+ let attr = editor.selectedElement.getAttribute('stroke-linejoin') || 'miter';
if ($('#linejoin_' + attr).length) {
setStrokeOpt($('#linejoin_' + attr)[0]);
}
- attr = selectedElement.getAttribute('stroke-linecap') || 'butt';
+ attr = editor.selectedElement.getAttribute('stroke-linecap') || 'butt';
if ($('#linecap_' + attr).length) {
setStrokeOpt($('#linecap_' + attr)[0]);
@@ -1213,15 +844,15 @@ editor.init = () => {
}
// All elements including image and group have opacity
- if (!isNullish(selectedElement)) {
- const opacPerc = (selectedElement.getAttribute('opacity') || 1.0) * 100;
+ if (!isNullish(editor.selectedElement)) {
+ const opacPerc = (editor.selectedElement.getAttribute('opacity') || 1.0) * 100;
$('#group_opacity').val(opacPerc);
$('#opac_slider').slider('option', 'value', opacPerc);
- $id('elem_id').value = selectedElement.id;
- $id('elem_class').value = (selectedElement.getAttribute('class') !== null) ? selectedElement.getAttribute('class') : '';
+ $id('elem_id').value = editor.selectedElement.id;
+ $id('elem_class').value = (editor.selectedElement.getAttribute('class') !== null) ? editor.selectedElement.getAttribute('class') : '';
}
- updateToolButtonState();
+ editor.bottomPanelHandlers.updateToolButtonState();
};
/**
@@ -1266,23 +897,23 @@ editor.init = () => {
const selectedChanged = function (win, elems) {
const mode = svgCanvas.getMode();
if (mode === 'select') {
- clickSelect();
+ editor.leftPanelHandlers.clickSelect();
}
const isNode = mode === 'pathedit';
// if elems[1] is present, then we have more than one element
- selectedElement = (elems.length === 1 || isNullish(elems[1]) ? elems[0] : null);
- multiselected = (elems.length >= 2 && !isNullish(elems[1]));
- if (!isNullish(selectedElement) && !isNode) {
+ editor.selectedElement = (elems.length === 1 || isNullish(elems[1]) ? elems[0] : null);
+ editor.multiselected = (elems.length >= 2 && !isNullish(elems[1]));
+ if (!isNullish(editor.selectedElement) && !isNode) {
updateToolbar();
} // if (!isNullish(elem))
// Deal with pathedit mode
togglePathEditMode(isNode, elems);
- updateContextPanel();
+ editor.topPanelHandlers.updateContextPanel();
svgCanvas.runExtensions('selectedChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_selectedChanged} */ {
elems,
- selectedElement,
- multiselected
+ selectedElement: editor.selectedElement,
+ multiselected: editor.multiselected
});
};
@@ -1303,9 +934,9 @@ editor.init = () => {
return;
}
- multiselected = (elems.length >= 2 && !isNullish(elems[1]));
+ editor.multiselected = (elems.length >= 2 && !isNullish(elems[1]));
// Only updating fields for single elements for now
- if (!multiselected) {
+ if (!editor.multiselected) {
switch (mode) {
case 'rotate': {
const ang = svgCanvas.getRotationAngle(elem);
@@ -1337,22 +968,22 @@ editor.init = () => {
const elementChanged = function (win, elems) {
const mode = svgCanvas.getMode();
if (mode === 'select') {
- clickSelect();
+ editor.leftPanelHandlers.clickSelect();
}
elems.forEach((elem) => {
const isSvgElem = (elem && elem.tagName === 'svg');
if (isSvgElem || svgCanvas.isLayer(elem)) {
- layersPanel.populateLayers();
+ editor.layersPanel.populateLayers();
// if the element changed was the svg, then it could be a resolution change
if (isSvgElem) {
updateCanvas();
}
// Update selectedElement if element is no longer part of the image.
// This occurs for the text elements in Firefox
- } else if (elem && selectedElement && isNullish(selectedElement.parentNode)) {
+ } else if (elem && editor.selectedElement && isNullish(editor.selectedElement.parentNode)) {
// || elem && elem.tagName == "path" && !multiselected) { // This was added in r1430, but not sure why
- selectedElement = elem;
+ editor.selectedElement = elem;
}
});
@@ -1365,11 +996,11 @@ editor.init = () => {
// we tell it to skip focusing the text control if the
// text element was previously in focus
- updateContextPanel();
+ editor.topPanelHandlers.updateContextPanel();
// In the event a gradient was flipped:
- if (selectedElement && mode === 'select') {
- updateColorpickers();
+ if (editor.selectedElement && mode === 'select') {
+ editor.bottomPanelHandlers.updateColorpickers();
}
svgCanvas.runExtensions('elementChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_elementChanged} */ {
@@ -1415,7 +1046,7 @@ editor.init = () => {
bb = zInfo.bbox;
if (zoomlevel < 0.001) {
- changeZoom(0.1);
+ editor.changeZoom(0.1);
return;
}
@@ -1429,45 +1060,12 @@ editor.init = () => {
if (svgCanvas.getMode() === 'zoom' && bb.width) {
// Go to select if a zoom box was drawn
- clickSelect();
+ editor.leftPanelHandlers.clickSelect();
}
zoomDone();
};
- /**
- * @type {module}
- */
- const changeZoom = (value) => {
- switch (value) {
- case 'canvas':
- case 'selection':
- case 'layer':
- case 'content':
- zoomChanged(window, value);
- break;
- default:
- {
- const zoomlevel = Number(value) / 100;
- if (zoomlevel < 0.001) {
- value = 0.1;
- return;
- }
- const zoom = svgCanvas.getZoom();
- const wArea = workarea;
-
- zoomChanged(window, {
- width: 0,
- height: 0,
- // center pt of scroll position
- x: (wArea[0].scrollLeft + wArea.width() / 2) / zoom,
- y: (wArea[0].scrollTop + wArea.height() / 2) / zoom,
- zoom: zoomlevel
- }, true);
- }
- }
- };
-
$('#cur_context_panel').delegate('a', 'click', (evt) => {
const link = $(evt.currentTarget);
if (link.attr('data-root')) {
@@ -1626,11 +1224,7 @@ editor.init = () => {
}
if (ext.events) {
- $id(ext.events.id).addEventListener('click', () => {
- if (updateLeftPanel(ext.events.id)) {
- ext.events.click();
- }
- });
+ editor.leftPanelHandlers.add(ext.events.id, ext.events.click);
}
return runCallback();
};
@@ -1679,77 +1273,15 @@ editor.init = () => {
// update resolution option with actual resolution
const res = svgCanvas.getResolution();
- if (configObj.curConfig.baseUnit !== 'px') {
- res.w = convertUnit(res.w) + configObj.curConfig.baseUnit;
- res.h = convertUnit(res.h) + configObj.curConfig.baseUnit;
+ if (editor.configObj.curConfig.baseUnit !== 'px') {
+ res.w = convertUnit(res.w) + editor.configObj.curConfig.baseUnit;
+ res.h = convertUnit(res.h) + editor.configObj.curConfig.baseUnit;
}
$('#se-img-prop').attr('dialog', 'close');
$('#se-img-prop').attr('title', svgCanvas.getDocumentTitle());
$('#se-img-prop').attr('width', res.w);
$('#se-img-prop').attr('height', res.h);
$('#se-img-prop').attr('save', editor.pref('img_save'));
- /**
- * @type {module}
- */
- const changeRectRadius = function (e) {
- svgCanvas.setRectRadius(e.target.value);
- };
-
- /**
- * @type {module}
- */
- const changeFontSize = function (e) {
- svgCanvas.setFontSize(e.target.value);
- };
-
- /**
- * @type {module}
- */
- const changeStrokeWidth = function (e) {
- let val = e.target.value;
- if (val === 0 && selectedElement && ['line', 'polyline'].includes(selectedElement.nodeName)) {
- val = e.target.value = 1;
- }
- svgCanvas.setStrokeWidth(val);
- };
-
- /**
- * @type {module}
- */
- const changeRotationAngle = (e) => {
- svgCanvas.setRotationAngle(e.target.value);
- $('#tool_reorient').toggleClass('disabled', Number.parseInt(e.target.value) === 0);
- };
-
- /**
- * @param {PlainObject} ctl
- * @param {string} [val=ctl.value]
- * @returns {void}
- */
- const changeOpacity = function (ctl, val) {
- if (isNullish(val)) { val = ctl.value; }
- $('#group_opacity').val(val);
- if (!ctl || !ctl.handle) {
- $('#opac_slider').slider('option', 'value', val);
- }
- svgCanvas.setOpacity(val / 100);
- };
-
- /**
- * @param {PlainObject} e
- * @returns {void}
- */
- const changeBlur = (e) => {
- svgCanvas.setBlur(e.target.value / 10, true);
- };
-
- $('#stroke_style').change((evt) => {
- svgCanvas.setStrokeAttr('stroke-dasharray', $(evt.currentTarget).val());
- });
-
- $('#stroke_linejoin').change((evt) => {
- svgCanvas.setStrokeAttr('stroke-linejoin', $(evt.currentTarget).val());
- });
// Lose focus for select elements when changed (Allows keyboard shortcuts to work better)
$('select').change((evt) => { $(evt.currentTarget).blur(); });
@@ -1768,7 +1300,7 @@ editor.init = () => {
promptMoveLayerOnce = true;
svgCanvas.moveSelectedToLayer(destLayer);
svgCanvas.clearSelection();
- layersPanel.populateLayers();
+ editor.layersPanel.populateLayers();
};
if (destLayer) {
if (promptMoveLayerOnce) {
@@ -1811,83 +1343,6 @@ editor.init = () => {
svgCanvas.setGroupTitle(evt.currentTarget.value);
});
- const attrChanger = function (e) {
- const attr = e.target.getAttribute('data-attr');
- let val = e.target.value;
- const valid = isValidUnit(attr, val, selectedElement);
-
- if (!valid) {
- e.target.value = selectedElement.getAttribute(attr);
- alert(uiStrings.notification.invalidAttrValGiven);
- return false;
- }
-
- if (attr !== 'id' && attr !== 'class') {
- if (isNaN(val)) {
- val = svgCanvas.convertToNum(attr, val);
- } else if (configObj.curConfig.baseUnit !== 'px') {
- // Convert unitless value to one with given unit
-
- const unitData = getTypeMap();
-
- if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
- val *= unitData[configObj.curConfig.baseUnit];
- }
- }
- }
-
- // if the user is changing the id, then de-select the element first
- // change the ID, then re-select it with the new ID
- if (attr === 'id') {
- const elem = selectedElement;
- svgCanvas.clearSelection();
- elem.id = val;
- svgCanvas.addToSelection([elem], true);
- } else {
- svgCanvas.changeSelectedAttribute(attr, val);
- }
- return true;
- };
-
- $('.attr_changer').change((evt) => {
- const attr = evt.currentTarget.getAttribute('data-attr');
- let val = evt.currentTarget.value;
- const valid = isValidUnit(attr, val, selectedElement);
-
- if (!valid) {
- evt.currentTarget.value = selectedElement.getAttribute(attr);
- alert(uiStrings.notification.invalidAttrValGiven);
- return false;
- }
-
- if (attr !== 'id' && attr !== 'class') {
- if (isNaN(val)) {
- val = svgCanvas.convertToNum(attr, val);
- } else if (configObj.curConfig.baseUnit !== 'px') {
- // Convert unitless value to one with given unit
-
- const unitData = getTypeMap();
-
- if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
- val *= unitData[configObj.curConfig.baseUnit];
- }
- }
- }
-
- // if the user is changing the id, then de-select the element first
- // change the ID, then re-select it with the new ID
- if (attr === 'id') {
- const elem = selectedElement;
- svgCanvas.clearSelection();
- elem.id = val;
- svgCanvas.addToSelection([elem], true);
- } else {
- svgCanvas.changeSelectedAttribute(attr, val);
- }
- evt.currentTarget.blur();
- return true;
- });
-
(function () {
const wArea = workarea[0];
@@ -1955,13 +1410,6 @@ editor.init = () => {
let jsHover = true;
let setClick = false;
- /*
- // Currently unused
- const hideMenu = () => {
- list.fadeOut(200);
- };
- */
-
$(window).mouseup(function (evt) {
if (!onButton) {
button.removeClass('buttondown');
@@ -2087,40 +1535,19 @@ editor.init = () => {
$('#font_family').val($(this).text()).change();
});
- editor.addDropDown('#opacity_dropdown', () => {
- if ($(this).find('div').length) { return; }
- const perc = Number.parseInt($(this).text().split('%')[0]);
- changeOpacity(false, perc);
- }, true);
-
- // For slider usage, see: http://jqueryui.com/demos/slider/
- $('#opac_slider').slider({
- start () {
- $('#opacity_dropdown li:not(.special)').hide();
- },
- stop () {
- $('#opacity_dropdown li').show();
- $(window).mouseup();
- },
- slide (evt, ui) {
- changeOpacity(ui);
- }
- });
-
- /*
- addAltDropDown('#stroke_linecap', '#linecap_opts', () => {
- setStrokeOpt(this, true);
- }, {dropUp: true});
-
- addAltDropDown('#stroke_linejoin', '#linejoin_opts', () => {
- setStrokeOpt(this, true);
- }, {dropUp: true});
-
- addAltDropDown('#tool_position', '#position_opts', () => {
- const letter = this.id.replace('tool_pos', '').charAt(0);
- svgCanvas.alignSelectedElements(letter, 'page');
- }, {multiclick: true});
+ /**
+ * @param {Float} multiplier
+ * @returns {void}
*/
+ editor.zoomImage = function (multiplier) {
+ const resolution = this.svgCanvasgetResolution();
+ multiplier = multiplier ? resolution.zoom * multiplier : 1;
+ // setResolution(res.w * multiplier, res.h * multiplier, true);
+ $id('zoom').value = (multiplier * 100).toFixed(1);
+ this.svgCanvassetZoom(multiplier);
+ zoomDone();
+ updateCanvas(true);
+ };
// Unfocus text input when workarea is mousedowned.
(function () {
@@ -2147,169 +1574,12 @@ editor.init = () => {
});
}());
- /**
- *
- * @returns {void}
- */
- const clickFHPath = () => {
- if (updateLeftPanel('tool_fhpath')) {
- svgCanvas.setMode('fhpath');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickLine = () => {
- if (updateLeftPanel('tool_line')) {
- svgCanvas.setMode('line');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickSquare = () => {
- if (updateLeftPanel('tool_square')) {
- svgCanvas.setMode('square');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickRect = () => {
- if (updateLeftPanel('tool_rect')) {
- svgCanvas.setMode('rect');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickFHRect = () => {
- if (updateLeftPanel('tool_fhrect')) {
- svgCanvas.setMode('fhrect');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickCircle = () => {
- if (updateLeftPanel('tool_circle')) {
- svgCanvas.setMode('circle');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickEllipse = () => {
- if (updateLeftPanel('tool_ellipse')) {
- svgCanvas.setMode('ellipse');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickFHEllipse = () => {
- if (updateLeftPanel('tool_fhellipse')) {
- svgCanvas.setMode('fhellipse');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickImage = () => {
- if (updateLeftPanel('tool_image')) {
- svgCanvas.setMode('image');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickZoom = () => {
- if (updateLeftPanel('tool_zoom')) {
- svgCanvas.setMode('zoom');
- workarea.css('cursor', zoomInIcon);
- }
- };
-
- /**
- * @param {Float} multiplier
- * @returns {void}
- */
- const zoomImage = function (multiplier) {
- const resolution = svgCanvas.getResolution();
- multiplier = multiplier ? resolution.zoom * multiplier : 1;
- // setResolution(res.w * multiplier, res.h * multiplier, true);
- $id('zoom').value = (multiplier * 100).toFixed(1);
- svgCanvas.setZoom(multiplier);
- zoomDone();
- updateCanvas(true);
- };
-
- /**
- *
- * @returns {void}
- */
- const dblclickZoom = () => {
- if (updateLeftPanel('tool_zoom')) {
- zoomImage();
- clickSelect();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickText = () => {
- if (updateLeftPanel('tool_text')) {
- svgCanvas.setMode('text');
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickPath = () => {
- if (updateLeftPanel('tool_path')) {
- svgCanvas.setMode('path');
- }
- };
-
- /**
- * Delete is a contextual tool that only appears in the ribbon if
- * an element has been selected.
- * @returns {void}
- */
- const deleteSelected = () => {
- if (!isNullish(selectedElement) || multiselected) {
- svgCanvas.deleteSelectedElements();
- }
- };
-
/**
*
* @returns {void}
*/
const cutSelected = () => {
- if (!isNullish(selectedElement) || multiselected) {
+ if (!isNullish(editor.selectedElement) || editor.multiselected) {
svgCanvas.cutSelectedElements();
}
};
@@ -2319,7 +1589,7 @@ editor.init = () => {
* @returns {void}
*/
const copySelected = () => {
- if (!isNullish(selectedElement) || multiselected) {
+ if (!isNullish(editor.selectedElement) || editor.multiselected) {
svgCanvas.copySelectedElements();
}
};
@@ -2335,79 +1605,26 @@ editor.init = () => {
svgCanvas.pasteElements('point', x, y);
};
- /**
- *
- * @returns {void}
- */
- const moveToTopSelected = () => {
- if (!isNullish(selectedElement)) {
- svgCanvas.moveToTopSelectedElement();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const moveToBottomSelected = () => {
- if (!isNullish(selectedElement)) {
- svgCanvas.moveToBottomSelectedElement();
- }
- };
-
/**
* @param {"Up"|"Down"} dir
* @returns {void}
*/
const moveUpDownSelected = function (dir) {
- if (!isNullish(selectedElement)) {
+ if (!isNullish(editor.selectedElement)) {
svgCanvas.moveUpDownSelected(dir);
}
};
- /**
- *
- * @returns {void}
- */
- const convertToPath = () => {
- if (!isNullish(selectedElement)) {
- svgCanvas.convertToPath();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const reorientPath = () => {
- if (!isNullish(selectedElement)) {
- path.reorient();
- }
- };
-
- /**
- *
- * @returns {void} Resolves to `undefined`
- */
- const makeHyperlink = () => {
- if (!isNullish(selectedElement) || multiselected) {
- const url = prompt(uiStrings.notification.enterNewLinkURL, 'http://');
- if (url) {
- svgCanvas.makeHyperlink(url);
- }
- }
- };
-
/**
* @param {Float} dx
* @param {Float} dy
* @returns {void}
*/
const moveSelected = function (dx, dy) {
- if (!isNullish(selectedElement) || multiselected) {
- if (configObj.curConfig.gridSnapping) {
+ if (!isNullish(editor.selectedElement) || editor.multiselected) {
+ if (editor.configObj.curConfig.gridSnapping) {
// Use grid snap value regardless of zoom level
- const multi = svgCanvas.getZoom() * configObj.curConfig.snappingStep;
+ const multi = svgCanvas.getZoom() * editor.configObj.curConfig.snappingStep;
dx *= multi;
dy *= multi;
}
@@ -2415,56 +1632,6 @@ editor.init = () => {
}
};
- /**
- *
- * @returns {void}
- */
- const linkControlPoints = () => {
- const linked = $id('tool_node_link').pressed;
- $id('tool_node_link').pressed = !linked;
- path.linkControlPoints(linked);
- };
-
- /**
- *
- * @returns {void}
- */
- const clonePathNode = () => {
- if (path.getNodePoint()) {
- path.clonePathNode();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const deletePathNode = () => {
- if (path.getNodePoint()) {
- path.deletePathNode();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const addSubPath = () => {
- const button = $('#tool_add_subpath');
- const sp = !button.hasClass('pressed');
- button.pressed = sp;
- // button.toggleClass('push_button_pressed tool_button');
- path.addSubPath(sp);
- };
-
- /**
- *
- * @returns {void}
- */
- const opencloseSubPath = () => {
- path.opencloseSubPath();
- };
-
/**
*
* @returns {void}
@@ -2487,11 +1654,11 @@ editor.init = () => {
* @returns {void}
*/
const rotateSelected = function (cw, step) {
- if (isNullish(selectedElement) || multiselected) { return; }
+ if (isNullish(editor.selectedElement) || editor.multiselected) { return; }
if (!cw) { step *= -1; }
const angle = Number.parseFloat($('#angle').val()) + step;
svgCanvas.setRotationAngle(angle);
- updateContextPanel();
+ editor.topPanelHandlers.updateContextPanel();
};
/**
@@ -2499,52 +1666,21 @@ editor.init = () => {
* @returns {void}
*/
const clickClear = () => {
- const [x, y] = configObj.curConfig.dimensions;
+ const [x, y] = editor.configObj.curConfig.dimensions;
const ok = confirm(uiStrings.notification.QwantToClear);
if (!ok) {
return;
}
- clickSelect();
+ editor.leftPanelHandlers.clickSelect();
svgCanvas.clear();
svgCanvas.setResolution(x, y);
updateCanvas(true);
- zoomImage();
- layersPanel.populateLayers();
- updateContextPanel();
+ editor.zoomImage();
+ editor.layersPanel.populateLayers();
+ editor.topPanelHandlers.updateContextPanel();
svgCanvas.runExtensions('onNewDocument');
};
- /**
- *
- * @returns {false}
- */
- const clickBold = () => {
- svgCanvas.setBold(!svgCanvas.getBold());
- updateContextPanel();
- return false;
- };
-
- /**
- *
- * @returns {false}
- */
- const clickItalic = () => {
- svgCanvas.setItalic(!svgCanvas.getItalic());
- updateContextPanel();
- return false;
- };
-
- /**
- *
- * @param {string} value "start","end" or "middle"
- * @returns {false}
- */
- const clickTextAnchor = (value) => {
- svgCanvas.setTextAnchor(value);
- updateContextPanel();
- return false;
- };
-
/**
*
* @returns {void}
@@ -2583,10 +1719,10 @@ editor.init = () => {
*/
function openExportWindow () {
const {loadingImage} = uiStrings.notification;
- if (configObj.curConfig.exportWindowType === 'new') {
+ if (editor.configObj.curConfig.exportWindowType === 'new') {
editor.exportWindowCt++;
}
- exportWindowName = configObj.curConfig.canvasName + editor.exportWindowCt;
+ exportWindowName = editor.configObj.curConfig.canvasName + editor.exportWindowCt;
let popHTML, popURL;
if (loadingURL) {
popURL = loadingURL;
@@ -2641,94 +1777,6 @@ editor.init = () => {
/* empty fn */
};
- /**
- *
- * @returns {void}
- */
- const clickUndo = () => {
- if (undoMgr.getUndoStackSize() > 0) {
- undoMgr.undo();
- layersPanel.populateLayers();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickRedo = () => {
- if (undoMgr.getRedoStackSize() > 0) {
- undoMgr.redo();
- layersPanel.populateLayers();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickGroup = () => {
- // group
- if (multiselected) {
- svgCanvas.groupSelectedElements();
- // ungroup
- } else if (selectedElement) {
- svgCanvas.ungroupSelectedElement();
- }
- };
-
- /**
- *
- * @returns {void}
- */
- const clickClone = () => {
- svgCanvas.cloneSelectedElements(20, 20);
- };
-
- /**
- * @param {string} pos indicate the alignment relative to top, bottom, middle etc..
- * @returns {void}
- */
- const clickAlign = (pos) => {
- svgCanvas.alignSelectedElements(pos, $('#align_relative_to').val());
- };
-
- /**
- *
- * @returns {void}
- */
- const clickWireframe = () => {
- $id('tool_wireframe').pressed = !$id('tool_wireframe').pressed;
- workarea.toggleClass('wireframe');
-
- const wfRules = $('#wireframe_rules');
- if (!wfRules.length) {
- /* wfRules = */ $('').appendTo('head');
- } else {
- wfRules.empty();
- }
-
- updateWireFrame();
- };
-
- const handlePalette = (e) => {
- e.preventDefault();
- // shift key or right click for stroke
- const {picker, color} = e.detail;
- // Webkit-based browsers returned 'initial' here for no stroke
- const paint = color === 'none' ? new $.jGraduate.Paint() : new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)});
- if (picker === 'fill') {
- $id('fill_color').setPaint(paint);
- } else {
- $id('stroke_color').setPaint(paint);
- }
- svgCanvas.setColor(picker, color);
- if (color !== 'none' && svgCanvas.getPaintOpacity(picker) !== 1) {
- svgCanvas.setPaintOpacity(picker, 1.0);
- }
- updateToolButtonState();
- };
-
let docprops = false;
let preferences = false;
@@ -2743,9 +1791,9 @@ editor.init = () => {
// update resolution option with actual resolution
const resolution = svgCanvas.getResolution();
- if (configObj.curConfig.baseUnit !== 'px') {
- resolution.w = convertUnit(resolution.w) + configObj.curConfig.baseUnit;
- resolution.h = convertUnit(resolution.h) + configObj.curConfig.baseUnit;
+ if (editor.configObj.curConfig.baseUnit !== 'px') {
+ resolution.w = convertUnit(resolution.w) + editor.configObj.curConfig.baseUnit;
+ resolution.h = convertUnit(resolution.h) + editor.configObj.curConfig.baseUnit;
}
$imgDialog.setAttribute('save', editor.pref('img_save'));
$imgDialog.setAttribute('width', resolution.w);
@@ -2764,14 +1812,14 @@ editor.init = () => {
const $editDialog = document.getElementById('se-edit-prefs');
$('#main_menu').hide();
// Update background color with current one
- const canvasBg = configObj.curPrefs.bkgd_color;
+ const canvasBg = editor.configObj.curPrefs.bkgd_color;
const url = editor.pref('bkgd_url');
if (url) {
$editDialog.setAttribute('bgurl', url);
}
- $editDialog.setAttribute('gridsnappingon', configObj.curConfig.gridSnapping);
- $editDialog.setAttribute('gridsnappingstep', configObj.curConfig.snappingStep);
- $editDialog.setAttribute('gridcolor', configObj.curConfig.gridColor);
+ $editDialog.setAttribute('gridsnappingon', editor.configObj.curConfig.gridSnapping);
+ $editDialog.setAttribute('gridsnappingstep', editor.configObj.curConfig.snappingStep);
+ $editDialog.setAttribute('gridcolor', editor.configObj.curConfig.gridColor);
$editDialog.setAttribute('canvasbg', canvasBg);
$editDialog.setAttribute('dialog', 'open');
};
@@ -2791,7 +1839,6 @@ editor.init = () => {
const hideSourceEditor = () => {
const $editorDialog = document.getElementById('se-svg-editor-dialog');
$editorDialog.setAttribute('dialog', 'closed');
- editingsource = false;
};
/**
@@ -2799,12 +1846,13 @@ editor.init = () => {
* @returns {void} Resolves to `undefined`
*/
const saveSourceEditor = (e) => {
- if (!editingsource) { return; }
+ const $editorDialog = document.getElementById('se-svg-editor-dialog');
+ if ($editorDialog.getAttribute('dialog') === 'open') return;
const saveChanges = () => {
svgCanvas.clearSelection();
hideSourceEditor();
- zoomImage();
- layersPanel.populateLayers();
+ editor.zoomImage();
+ editor.layersPanel.populateLayers();
updateTitle();
};
@@ -2817,7 +1865,7 @@ editor.init = () => {
return;
}
saveChanges();
- clickSelect();
+ editor.leftPanelHandlers.clickSelect();
};
/**
@@ -2888,16 +1936,16 @@ editor.init = () => {
}
// set grid setting
- configObj.curConfig.gridSnapping = gridsnappingon;
- configObj.curConfig.snappingStep = gridsnappingstep;
- configObj.curConfig.gridColor = gridcolor;
- configObj.curConfig.showRulers = showrulers;
+ editor.configObj.curConfig.gridSnapping = gridsnappingon;
+ editor.configObj.curConfig.snappingStep = gridsnappingstep;
+ editor.configObj.curConfig.gridColor = gridcolor;
+ editor.configObj.curConfig.showRulers = showrulers;
- $('#rulers').toggle(configObj.curConfig.showRulers);
- if (configObj.curConfig.showRulers) { updateRulers(); }
- configObj.curConfig.baseUnit = baseunit;
+ $('#rulers').toggle(editor.configObj.curConfig.showRulers);
+ if (editor.configObj.curConfig.showRulers) { updateRulers(); }
+ editor.configObj.curConfig.baseUnit = baseunit;
- svgCanvas.setConfig(configObj.curConfig);
+ svgCanvas.setConfig(editor.configObj.curConfig);
updateCanvas();
hidePreferences();
};
@@ -2908,6 +1956,8 @@ editor.init = () => {
*/
const cancelOverlays = (e) => {
$('#dialog_box').hide();
+ const $editorDialog = document.getElementById('se-svg-editor-dialog');
+ const editingsource = $editorDialog.getAttribute('dialog') === 'open';
if (!editingsource && !docprops && !preferences) {
if (curContext) {
svgCanvas.leaveContext();
@@ -2916,6 +1966,7 @@ editor.init = () => {
}
if (editingsource) {
+ const origSource = svgCanvas.getSvgString();
if (origSource !== e.detail.value) {
const ok = confirm(uiStrings.notification.QignoreSourceChanges);
if (ok) {
@@ -2951,19 +2002,8 @@ editor.init = () => {
alert(this.title);
});
- $('#change_image_url').click(promptImgURL);
-
- $('#stroke_width').val(configObj.curConfig.initStroke.width);
- $('#group_opacity').val(configObj.curConfig.initOpacity * 100);
-
- const handleColorPicker = (type, evt) => {
- const {paint} = evt.detail;
- svgCanvas.setPaint(type, paint);
- updateToolButtonState();
- };
-
- $id('stroke_color').addEventListener('change', (evt) => handleColorPicker('stroke', evt));
- $id('fill_color').addEventListener('change', (evt) => handleColorPicker('fill', evt));
+ $('#stroke_width').val(editor.configObj.curConfig.initStroke.width);
+ $('#group_opacity').val(editor.configObj.curConfig.initOpacity * 100);
$('#group_opacityLabel').click(() => {
$('#opacity_dropdown button').mousedown();
@@ -2980,102 +2020,7 @@ editor.init = () => {
$(this).removeClass('push_button_pressed').addClass('push_button');
});
- const SIDEPANEL_MAXWIDTH = 300;
- const SIDEPANEL_OPENWIDTH = 150;
- let sidedrag = -1, sidedragging = false, allowmove = false;
-
- /**
- * @param {Float} delta
- * @fires module:svgcanvas.SvgCanvas#event:ext_workareaResized
- * @returns {void}
- */
- const changeSidePanelWidth = function (delta) {
- const rulerX = $('#ruler_x');
- $('#sidepanels').width('+=' + delta);
- $('#layerpanel').width('+=' + delta);
- rulerX.css('right', Number.parseInt(rulerX.css('right')) + delta);
- workarea.css('right', Number.parseInt(workarea.css('right')) + delta);
- svgCanvas.runExtensions('workareaResized');
- };
-
- /**
- * @param {Event} evt
- * @returns {void}
- */
- const resizeSidePanel = function (evt) {
- if (!allowmove) { return; }
- if (sidedrag === -1) { return; }
- sidedragging = true;
- let deltaX = sidedrag - evt.pageX;
- const sideWidth = $('#sidepanels').width();
- if (sideWidth + deltaX > SIDEPANEL_MAXWIDTH) {
- deltaX = SIDEPANEL_MAXWIDTH - sideWidth;
- // sideWidth = SIDEPANEL_MAXWIDTH;
- } else if (sideWidth + deltaX < 2) {
- deltaX = 2 - sideWidth;
- // sideWidth = 2;
- }
- if (deltaX === 0) { return; }
- sidedrag -= deltaX;
- changeSidePanelWidth(deltaX);
- };
-
- const lmenuFunc = (action, el) => {
- switch (action) {
- case 'dupe':
- /* await */ layersPanel.cloneLayer();
- break;
- case 'delete':
- layersPanel.deleteLayer();
- break;
- case 'merge_down':
- layersPanel.mergeLayer();
- break;
- case 'merge_all':
- layersPanel.svgCanvas.mergeAllLayers();
- layersPanel.updateContextPanel();
- layersPanel.populateLayers();
- break;
- }
- };
-
- /**
- * If width is non-zero, then fully close it; otherwise fully open it.
- * @param {boolean} close Forces the side panel closed
- * @returns {void}
- */
- const toggleSidePanel = function (close) {
- const dpr = window.devicePixelRatio || 1;
- const w = $('#sidepanels').width();
- const isOpened = (dpr < 1 ? w : w / dpr) > 2;
- const zoomAdjustedSidepanelWidth = (dpr < 1 ? 1 : dpr) * SIDEPANEL_OPENWIDTH;
- const deltaX = (isOpened || close ? 0 : zoomAdjustedSidepanelWidth) - w;
- changeSidePanelWidth(deltaX);
- };
-
- $('#sidepanel_handle')
- .mousedown(function (evt) {
- sidedrag = evt.pageX;
- $(window).mousemove(resizeSidePanel);
- allowmove = false;
- // Silly hack for Chrome, which always runs mousemove right after mousedown
- setTimeout(() => {
- allowmove = true;
- }, 20);
- })
- .mouseup(function (evt) {
- if (!sidedragging) { toggleSidePanel(); }
- sidedrag = -1;
- sidedragging = false;
- });
-
- $(window).mouseup(() => {
- sidedrag = -1;
- sidedragging = false;
- $('#svg_editor').unbind('mousemove', resizeSidePanel);
- });
-
- layersPanel.populateLayers();
+ editor.layersPanel.populateLayers();
const centerCanvas = () => {
// this centers the canvas vertically in the workarea (horizontal handled in CSS)
@@ -3109,93 +2054,11 @@ editor.init = () => {
* @name module:SVGEditor~ToolButtons
* @type {module:SVGEditor.ToolButton[]}
*/
- // register action to top panel buttons
- $id('tool_source').addEventListener('click', showSourceEditor);
- $id('tool_wireframe').addEventListener('click', clickWireframe);
- $id('tool_undo').addEventListener('click', clickUndo);
- $id('tool_redo').addEventListener('click', clickRedo);
- $id('tool_clone').addEventListener('click', clickClone);
- $id('tool_clone_multi').addEventListener('click', clickClone);
- $id('tool_delete').addEventListener('click', deleteSelected);
- $id('tool_delete_multi').addEventListener('click', deleteSelected);
- $id('tool_move_top').addEventListener('click', moveToTopSelected);
- $id('tool_move_bottom').addEventListener('click', moveToBottomSelected);
- $id('tool_topath').addEventListener('click', convertToPath);
- $id('tool_make_link').addEventListener('click', makeHyperlink);
- $id('tool_make_link_multi').addEventListener('click', makeHyperlink);
- $id('tool_reorient').addEventListener('click', reorientPath);
- $id('tool_group_elements').addEventListener('click', clickGroup);
- $id('tool_align_left').addEventListener('click', () => clickAlign('left'));
- $id('tool_align_right').addEventListener('click', () => clickAlign('right'));
- $id('tool_align_center').addEventListener('click', () => clickAlign('center'));
- $id('tool_align_top').addEventListener('click', () => clickAlign('top'));
- $id('tool_align_bottom').addEventListener('click', () => clickAlign('bottom'));
- $id('tool_align_middle').addEventListener('click', () => clickAlign('middle'));
- $id('tool_node_clone').addEventListener('click', clonePathNode);
- $id('tool_node_delete').addEventListener('click', deletePathNode);
- $id('tool_openclose_path').addEventListener('click', opencloseSubPath);
- $id('tool_add_subpath').addEventListener('click', addSubPath);
- $id('tool_node_link').addEventListener('click', linkControlPoints);
- // register actions for left panel
- $id('tool_select').addEventListener('click', clickSelect);
- $id('tool_fhpath').addEventListener('click', clickFHPath);
- $id('tool_text').addEventListener('click', clickText);
- $id('tool_image').addEventListener('click', clickImage);
- $id('tool_zoom').addEventListener('click', clickZoom);
- $id('tool_zoom').addEventListener('dblclick', dblclickZoom);
- $id('tool_path').addEventListener('click', clickPath);
- $id('tool_line').addEventListener('click', clickLine);
-
- // flyout
- $id('tool_rect').addEventListener('click', clickRect);
- $id('tool_square').addEventListener('click', clickSquare);
- $id('tool_fhrect').addEventListener('click', clickFHRect);
- $id('tool_ellipse').addEventListener('click', clickEllipse);
- $id('tool_circle').addEventListener('click', clickCircle);
- $id('tool_fhellipse').addEventListener('click', clickFHEllipse);
-
- // register actions for bottom panel
- $id('zoom').addEventListener('change', (e) => changeZoom(e.detail.value));
- $id('elem_id').addEventListener('change', (e) => attrChanger(e));
- $id('elem_class').addEventListener('change', (e) => attrChanger(e));
- $id('circle_cx').addEventListener('change', (e) => attrChanger(e));
- $id('circle_cy').addEventListener('change', (e) => attrChanger(e));
- $id('circle_r').addEventListener('change', (e) => attrChanger(e));
- $id('ellipse_cx').addEventListener('change', (e) => attrChanger(e));
- $id('ellipse_cy').addEventListener('change', (e) => attrChanger(e));
- $id('ellipse_rx').addEventListener('change', (e) => attrChanger(e));
- $id('ellipse_ry').addEventListener('change', (e) => attrChanger(e));
- $id('selected_x').addEventListener('change', (e) => attrChanger(e));
- $id('selected_y').addEventListener('change', (e) => attrChanger(e));
- $id('rect_width').addEventListener('change', (e) => attrChanger(e));
- $id('rect_height').addEventListener('change', (e) => attrChanger(e));
- $id('line_x1').addEventListener('change', (e) => attrChanger(e));
- $id('line_y1').addEventListener('change', (e) => attrChanger(e));
- $id('line_x2').addEventListener('change', (e) => attrChanger(e));
- $id('line_y2').addEventListener('change', (e) => attrChanger(e));
- $id('image_width').addEventListener('change', (e) => attrChanger(e));
- $id('image_height').addEventListener('change', (e) => attrChanger(e));
- $id('path_node_x').addEventListener('change', (e) => attrChanger(e));
- $id('path_node_y').addEventListener('change', (e) => attrChanger(e));
- $id('angle').addEventListener('change', (e) => changeRotationAngle(e));
- $id('blur').addEventListener('change', (e) => changeBlur(e));
- $id('stroke_width').addEventListener('change', (e) => changeStrokeWidth(e));
- $id('rect_rx').addEventListener('change', (e) => changeRectRadius(e));
- $id('font_size').addEventListener('change', (e) => changeFontSize(e));
-
- // register actions in top toolbar
- $id('tool_ungroup').addEventListener('click', clickGroup);
- $id('tool_unlink_use').addEventListener('click', clickGroup);
- $id('sidepanel_handle').addEventListener('click', toggleSidePanel);
-
- $id('tool_bold').addEventListener('click', clickBold);
- $id('tool_italic').addEventListener('click', clickItalic);
- $id('tool_text_anchor_start').addEventListener('click', () => clickTextAnchor('start'));
- $id('tool_text_anchor_middle').addEventListener('click', () => clickTextAnchor('middle'));
- $id('tool_text_anchor_end').addEventListener('click', () => clickTextAnchor('end'));
-
- $id('palette').addEventListener('change', handlePalette);
+ editor.leftPanelHandlers.init();
+ editor.bottomPanelHandlers.init();
+ editor.topPanelHandlers.init();
+ editor.layersPanel.init();
$id('tool_clear').addEventListener('click', clickClear);
$id('tool_open').addEventListener('click', function (e) {
@@ -3207,6 +2070,8 @@ editor.init = () => {
window.dispatchEvent(new CustomEvent('importImage'));
});
$id('tool_save').addEventListener('click', function (e) {
+ const $editorDialog = document.getElementById('se-svg-editor-dialog');
+ const editingsource = $editorDialog.getAttribute('dialog') === 'open';
if (editingsource) {
saveSourceEditor();
} else {
@@ -3244,7 +2109,7 @@ editor.init = () => {
const action = e?.detail?.trigger;
switch (action) {
case 'delete':
- deleteSelected();
+ svgCanvas.deleteSelectedElements();
break;
case 'cut':
cutSelected();
@@ -3266,7 +2131,7 @@ editor.init = () => {
svgCanvas.ungroupSelectedElement();
break;
case 'move_front':
- moveToTopSelected();
+ svgCanvas.moveToTopSelectedElement();
break;
case 'move_up':
moveUpDownSelected('Up');
@@ -3275,7 +2140,7 @@ editor.init = () => {
moveUpDownSelected('Down');
break;
case 'move_back':
- moveToBottomSelected();
+ svgCanvas.moveToBottomSelected();
break;
default:
if (hasCustomHandler(action)) {
@@ -3284,13 +2149,7 @@ editor.init = () => {
break;
}
});
- $id('se-cmenu-layers-more').addEventListener('change', function (e) {
- lmenuFunc(e?.detail?.trigger, e?.detail?.source);
- });
- $id('se-cmenu-layers-list').addEventListener('change', function (e) {
- lmenuFunc(e?.detail?.trigger, e?.detail?.source);
- });
- layersPanel.addEvents();
+
const toolButtons = [
// Shortcuts not associated with buttons
{key: 'ctrl+left', fn () { rotateSelected(0, 1); }},
@@ -3299,8 +2158,8 @@ editor.init = () => {
{key: 'ctrl+shift+right', fn () { rotateSelected(1, 5); }},
{key: 'shift+O', fn: selectPrev},
{key: 'shift+P', fn: selectNext},
- {key: [modKey + 'up', true], fn () { zoomImage(2); }},
- {key: [modKey + 'down', true], fn () { zoomImage(0.5); }},
+ {key: [modKey + 'up', true], fn () { editor.zoomImage(2); }},
+ {key: [modKey + 'down', true], fn () { editor.zoomImage(0.5); }},
{key: [modKey + ']', true], fn () { moveUpDownSelected('Up'); }},
{key: [modKey + '[', true], fn () { moveUpDownSelected('Down'); }},
{key: ['up', true], fn () { moveSelected(0, -1); }},
@@ -3321,11 +2180,6 @@ editor.init = () => {
{key: ['alt+shift+right', true], fn () { svgCanvas.cloneSelectedElements(10, 0); }},
{key: 'a', fn () { svgCanvas.selectAllInCurrentLayer(); }},
{key: modKey + 'a', fn () { svgCanvas.selectAllInCurrentLayer(); }},
- // Standard shortcuts
- {key: modKey + 'z', fn: clickUndo},
- {key: modKey + 'shift+z', fn: clickRedo},
- {key: modKey + 'y', fn: clickRedo},
-
{key: modKey + 'x', fn: cutSelected},
{key: modKey + 'c', fn: copySelected},
{key: modKey + 'v', fn: pasteInCenter}
@@ -3442,8 +2296,8 @@ editor.init = () => {
// Select given tool
editor.ready(function () {
- const preTool = $id(`tool_${configObj.curConfig.initTool}`);
- const regTool = $id(configObj.curConfig.initTool);
+ const preTool = $id(`tool_${editor.configObj.curConfig.initTool}`);
+ const regTool = $id(editor.configObj.curConfig.initTool);
const selectTool = $id('tool_select');
const $editDialog = $id('se-edit-prefs');
@@ -3455,34 +2309,30 @@ editor.init = () => {
selectTool.click();
}
- if (configObj.curConfig.wireframe) {
+ if (editor.configObj.curConfig.wireframe) {
$id('tool_wireframe').click();
}
- if (configObj.curConfig.showlayers) {
- toggleSidePanel();
- }
+ $('#rulers').toggle(Boolean(editor.configObj.curConfig.showRulers));
- $('#rulers').toggle(Boolean(configObj.curConfig.showRulers));
-
- if (configObj.curConfig.showRulers) {
+ if (editor.configObj.curConfig.showRulers) {
$editDialog.setAttribute('showrulers', true);
}
- if (configObj.curConfig.baseUnit) {
- $editDialog.setAttribute('baseunit', configObj.curConfig.baseUnit);
+ if (editor.configObj.curConfig.baseUnit) {
+ $editDialog.setAttribute('baseunit', editor.configObj.curConfig.baseUnit);
}
- if (configObj.curConfig.gridSnapping) {
+ if (editor.configObj.curConfig.gridSnapping) {
$editDialog.setAttribute('gridsnappingon', true);
}
- if (configObj.curConfig.snappingStep) {
- $editDialog.setAttribute('gridsnappingstep', configObj.curConfig.snappingStep);
+ if (editor.configObj.curConfig.snappingStep) {
+ $editDialog.setAttribute('gridsnappingstep', editor.configObj.curConfig.snappingStep);
}
- if (configObj.curConfig.gridColor) {
- $editDialog.setAttribute('gridcolor', configObj.curConfig.gridColor);
+ if (editor.configObj.curConfig.gridColor) {
+ $editDialog.setAttribute('gridcolor', editor.configObj.curConfig.gridColor);
}
});
@@ -3515,7 +2365,7 @@ editor.init = () => {
}
// showSaveWarning is set to 'false' when the page is saved.
- if (!configObj.curConfig.no_save_warning && editor.showSaveWarning) {
+ if (!editor.configObj.curConfig.no_save_warning && editor.showSaveWarning) {
// Browser already asks question about closing the page
e.returnValue = uiStrings.notification.unsavedChanges; // Firefox needs this when beforeunload set by addEventListener (even though message is not used)
return uiStrings.notification.unsavedChanges;
@@ -3595,10 +2445,7 @@ editor.init = () => {
$('#dialog_box').hide();
return;
}
- /* if (file.type === 'application/pdf') { // Todo: Handle PDF imports
- }
- else */
if (!file.type.includes('image')) {
return;
}
@@ -3645,7 +2492,7 @@ editor.init = () => {
svgCanvas.selectOnly([newImage]);
svgCanvas.alignSelectedElements('m', 'page');
svgCanvas.alignSelectedElements('c', 'page');
- updateContextPanel();
+ editor.topPanelHandlers.updateContextPanel();
$('#dialog_box').hide();
};
// create dummy img so we know the default dimensions
@@ -3727,7 +2574,7 @@ editor.init = () => {
if (renameLayer) {
svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1');
- layersPanel.populateLayers();
+ editor.layersPanel.populateLayers();
}
svgCanvas.runExtensions('langChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_langChanged} */ lang);