V7 preview 2 (#463)
* commit toward svgcanvas/svgedit isolation * jquery removal, isolate svgcavas from svgedit, tests * refactor(panels) * fix update of colorpickers * update cypress * #tool_imagelib image library menu missing in main menu * #tool_imagelib lint issue fixed * #seConfirmDialog confirm change to elix alertdialog * #seConfirmDialog alert change to elix alert dialog * #seConfirmDialog remove super.attributeChangedCallback * #process_cancel prompt changes to alertDialog and seConfirmDialog * refactor to class step 1 * make load faster * #storageDialog dialog separate moved dialog * #process_cancel alert and process_cancel changes * #process_cancel lint issue fixed * add seList component * merge * fixes * storagedialog * move all storage related code to ext-storage * fix ruler * Update ConfigObj.js * fix resize * Update ext-storage.js * picker starts withthe right color * fix prefs * fix initial content load * npm update and fix some tests * npm run build
This commit is contained in:
@@ -6,9 +6,6 @@
|
||||
* @copyright 2010 Jeff Schiller, 2010 Alexis Deveria
|
||||
*/
|
||||
|
||||
// Dependencies:
|
||||
// 1) jQuery (for $.alert())
|
||||
|
||||
import 'pathseg';
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
|
||||
// eslint-disable-next-line node/no-unpublished-import
|
||||
import deparam from 'deparam';
|
||||
import * as Utils from '../common/utilities.js';
|
||||
|
||||
/**
|
||||
* Escapes special characters in a regular expression.
|
||||
* @function regexEscape
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
export const regexEscape = function (str) {
|
||||
// Originally from: http://phpjs.org/functions
|
||||
return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&');
|
||||
};
|
||||
/**
|
||||
* @class configObj
|
||||
*/
|
||||
@@ -147,27 +157,6 @@ export default class ConfigObj {
|
||||
// Note: The difference between Prefs and Config is that Prefs
|
||||
// can be changed in the UI and are stored in the browser,
|
||||
// while config cannot
|
||||
this.curConfig = {
|
||||
// We do not put on defaultConfig to simplify object copying
|
||||
// procedures (we obtain instead from defaultExtensions)
|
||||
extensions: [],
|
||||
userExtensions: [],
|
||||
/**
|
||||
* Can use `location.origin` to indicate the current
|
||||
* origin. Can contain a '*' to allow all domains or 'null' (as
|
||||
* a string) to support all `file:///` URLs. Cannot be set by
|
||||
* URL for security reasons (not safe, at least for
|
||||
* privacy or data integrity of SVG content).
|
||||
* Might have been fairly safe to allow
|
||||
* `new URL(location.href).origin` by default but
|
||||
* avoiding it ensures some more security that even third
|
||||
* party apps on the same domain also cannot communicate
|
||||
* with this app by default.
|
||||
* For use with `ext-xdomain-messaging.js`
|
||||
* @todo We might instead make as a user-facing preference.
|
||||
*/
|
||||
allowedOrigins: []
|
||||
};
|
||||
this.urldata = {};
|
||||
/**
|
||||
* @name module:SVGEditor~defaultExtensions
|
||||
@@ -186,6 +175,27 @@ export default class ConfigObj {
|
||||
'ext-star',
|
||||
'ext-storage'
|
||||
];
|
||||
this.curConfig = {
|
||||
// We do not put on defaultConfig to simplify object copying
|
||||
// procedures (we obtain instead from defaultExtensions)
|
||||
extensions: [],
|
||||
userExtensions: [],
|
||||
/**
|
||||
* Can use `location.origin` to indicate the current
|
||||
* origin. Can contain a '*' to allow all domains or 'null' (as
|
||||
* a string) to support all `file:///` URLs. Cannot be set by
|
||||
* URL for security reasons (not safe, at least for
|
||||
* privacy or data integrity of SVG content).
|
||||
* Might have been fairly safe to allow
|
||||
* `new URL(location.href).origin` by default but
|
||||
* avoiding it ensures some more security that even third
|
||||
* party apps on the same domain also cannot communicate
|
||||
* with this app by default.
|
||||
* For use with `ext-xdomain-messaging.js`
|
||||
* @todo We might instead make as a user-facing preference.
|
||||
*/
|
||||
allowedOrigins: []
|
||||
};
|
||||
this.editor = editor;
|
||||
}
|
||||
/**
|
||||
@@ -206,14 +216,16 @@ export default class ConfigObj {
|
||||
|
||||
// Now deal with extensions and other array config
|
||||
if (!curConfig.noDefaultExtensions) {
|
||||
curConfig.extensions = curConfig.extensions.concat(this.defaultExtensions);
|
||||
curConfig.extensions = [...this.defaultExtensions];
|
||||
}
|
||||
// ...and remove any dupes
|
||||
/*
|
||||
['extensions', 'allowedOrigins'].forEach(function (cfg) {
|
||||
curConfig[cfg] = $.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html
|
||||
return i === curConfig[cfg].indexOf(n);
|
||||
});
|
||||
});
|
||||
*/
|
||||
// Export updated config
|
||||
this.curConfig = curConfig;
|
||||
}
|
||||
@@ -345,7 +357,7 @@ export default class ConfigObj {
|
||||
this.defaultPrefs[key] = window.widget.preferenceForKey(storeKey);
|
||||
} else {
|
||||
const result = document.cookie.match(
|
||||
new RegExp('(?:^|;\\s*)' + Utils.regexEscape(
|
||||
new RegExp('(?:^|;\\s*)' + regexEscape(
|
||||
encodeURIComponent(storeKey)
|
||||
) + '=([^;]+)')
|
||||
);
|
||||
@@ -450,10 +462,10 @@ export default class ConfigObj {
|
||||
* @returns {string|void} If val is missing or falsey and `mayBeEmpty` is not set, the
|
||||
* value of the previously stored preference will be returned.
|
||||
* @todo Review whether any remaining existing direct references to
|
||||
* getting `curPrefs` can be changed to use `svgEditor.pref()` getting to ensure
|
||||
* getting `curPrefs` can be changed to use `svgEditor.configObj.pref()` getting to ensure
|
||||
* `defaultPrefs` fallback (also for sake of `allowInitialUserOverride`);
|
||||
* specifically, `bkgd_color` could be changed so that the pref dialog has a
|
||||
* button to auto-calculate background, but otherwise uses `svgEditor.pref()` to
|
||||
* button to auto-calculate background, but otherwise uses `svgEditor.configObj.pref()` to
|
||||
* be able to get default prefs or overridable settings
|
||||
*/
|
||||
pref (key, val, mayBeEmpty) {
|
||||
|
||||
190
src/editor/Rulers.js
Normal file
190
src/editor/Rulers.js
Normal file
@@ -0,0 +1,190 @@
|
||||
/* globals $ */
|
||||
import {getTypeMap} from '../common/units.js';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Rulers {
|
||||
/**
|
||||
* @type {Module}
|
||||
*/
|
||||
constructor (editor) {
|
||||
// Make [1,2,5] array
|
||||
this.rulerIntervals = [];
|
||||
for (let i = 0.1; i < 1e5; i *= 10) {
|
||||
this.rulerIntervals.push(i);
|
||||
this.rulerIntervals.push(2 * i);
|
||||
this.rulerIntervals.push(5 * i);
|
||||
}
|
||||
this.svgCanvas = editor.svgCanvas;
|
||||
this.editor = editor;
|
||||
}
|
||||
/**
|
||||
* @type {Module}
|
||||
*/
|
||||
manageScroll () {
|
||||
const rulerX = document.getElementById('ruler_x');
|
||||
const rulerY = document.getElementById('ruler_y');
|
||||
if (rulerX) rulerX.scrollLeft = this.editor.workarea[0].scrollLeft;
|
||||
if (rulerY) rulerY.scrollTop = this.editor.workarea[0].scrollTop;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {HTMLDivElement} [scanvas]
|
||||
* @param {Float} [zoom]
|
||||
* @returns {void}
|
||||
*/
|
||||
updateRulers (scanvas, zoom) {
|
||||
if (!zoom) { zoom = this.svgCanvas.getZoom(); }
|
||||
if (!scanvas) { scanvas = $('#svgcanvas'); }
|
||||
|
||||
let d, i;
|
||||
const limit = 30000;
|
||||
const contentElem = this.svgCanvas.getContentElem();
|
||||
const units = getTypeMap();
|
||||
const unit = units[this.editor.configObj.curConfig.baseUnit]; // 1 = 1px
|
||||
|
||||
// draw x ruler then y ruler
|
||||
for (d = 0; d < 2; d++) {
|
||||
const isX = (d === 0);
|
||||
const dim = isX ? 'x' : 'y';
|
||||
const lentype = isX ? 'width' : 'height';
|
||||
const contentDim = Number(contentElem.getAttribute(dim));
|
||||
|
||||
const $hcanvOrig = $('#ruler_' + dim + ' canvas:first');
|
||||
|
||||
// Bit of a hack to fully clear the canvas in Safari & IE9
|
||||
const $hcanv = $hcanvOrig.clone();
|
||||
$hcanvOrig.replaceWith($hcanv);
|
||||
|
||||
const hcanv = $hcanv[0];
|
||||
|
||||
// Set the canvas size to the width of the container
|
||||
let rulerLen = scanvas[lentype]();
|
||||
const totalLen = rulerLen;
|
||||
hcanv.parentNode.style[lentype] = totalLen + 'px';
|
||||
let ctx = hcanv.getContext('2d');
|
||||
let ctxArr, num, ctxArrNum;
|
||||
|
||||
ctx.fillStyle = 'rgb(200,0,0)';
|
||||
ctx.fillRect(0, 0, hcanv.width, hcanv.height);
|
||||
|
||||
// Remove any existing canvasses
|
||||
$hcanv.siblings().remove();
|
||||
|
||||
// Create multiple canvases when necessary (due to browser limits)
|
||||
if (rulerLen >= limit) {
|
||||
ctxArrNum = Number.parseInt(rulerLen / limit) + 1;
|
||||
ctxArr = [];
|
||||
ctxArr[0] = ctx;
|
||||
let copy;
|
||||
for (i = 1; i < ctxArrNum; i++) {
|
||||
hcanv[lentype] = limit;
|
||||
copy = hcanv.cloneNode(true);
|
||||
hcanv.parentNode.append(copy);
|
||||
ctxArr[i] = copy.getContext('2d');
|
||||
}
|
||||
|
||||
copy[lentype] = rulerLen % limit;
|
||||
|
||||
// set copy width to last
|
||||
rulerLen = limit;
|
||||
}
|
||||
|
||||
hcanv[lentype] = rulerLen;
|
||||
|
||||
const uMulti = unit * zoom;
|
||||
|
||||
// Calculate the main number interval
|
||||
const rawM = 50 / uMulti;
|
||||
let multi = 1;
|
||||
for (i = 0; i < this.rulerIntervals.length; i++) {
|
||||
num = this.rulerIntervals[i];
|
||||
multi = num;
|
||||
if (rawM <= num) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bigInt = multi * uMulti;
|
||||
|
||||
ctx.font = '9px sans-serif';
|
||||
|
||||
let rulerD = ((contentDim / uMulti) % multi) * uMulti;
|
||||
let labelPos = rulerD - bigInt;
|
||||
// draw big intervals
|
||||
let ctxNum = 0;
|
||||
while (rulerD < totalLen) {
|
||||
labelPos += bigInt;
|
||||
// const realD = rulerD - contentDim; // Currently unused
|
||||
|
||||
const curD = Math.round(rulerD) + 0.5;
|
||||
if (isX) {
|
||||
ctx.moveTo(curD, 15);
|
||||
ctx.lineTo(curD, 0);
|
||||
} else {
|
||||
ctx.moveTo(15, curD);
|
||||
ctx.lineTo(0, curD);
|
||||
}
|
||||
|
||||
num = (labelPos - contentDim) / uMulti;
|
||||
let label;
|
||||
if (multi >= 1) {
|
||||
label = Math.round(num);
|
||||
} else {
|
||||
const decs = String(multi).split('.')[1].length;
|
||||
label = num.toFixed(decs);
|
||||
}
|
||||
|
||||
// Change 1000s to Ks
|
||||
if (label !== 0 && label !== 1000 && label % 1000 === 0) {
|
||||
label = (label / 1000) + 'K';
|
||||
}
|
||||
|
||||
if (isX) {
|
||||
ctx.fillText(label, rulerD + 2, 8);
|
||||
} else {
|
||||
// draw label vertically
|
||||
const str = String(label).split('');
|
||||
for (i = 0; i < str.length; i++) {
|
||||
ctx.fillText(str[i], 1, (rulerD + 9) + i * 9);
|
||||
}
|
||||
}
|
||||
|
||||
const part = bigInt / 10;
|
||||
// draw the small intervals
|
||||
for (i = 1; i < 10; i++) {
|
||||
let subD = Math.round(rulerD + part * i) + 0.5;
|
||||
if (ctxArr && subD > rulerLen) {
|
||||
ctxNum++;
|
||||
ctx.stroke();
|
||||
if (ctxNum >= ctxArrNum) {
|
||||
i = 10;
|
||||
rulerD = totalLen;
|
||||
continue;
|
||||
}
|
||||
ctx = ctxArr[ctxNum];
|
||||
rulerD -= limit;
|
||||
subD = Math.round(rulerD + part * i) + 0.5;
|
||||
}
|
||||
|
||||
// odd lines are slighly longer
|
||||
const lineNum = (i % 2) ? 12 : 10;
|
||||
if (isX) {
|
||||
ctx.moveTo(subD, 15);
|
||||
ctx.lineTo(subD, lineNum);
|
||||
} else {
|
||||
ctx.moveTo(15, subD);
|
||||
ctx.lineTo(lineNum, subD);
|
||||
}
|
||||
}
|
||||
rulerD += bigInt;
|
||||
}
|
||||
ctx.strokeStyle = '#000';
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Rulers;
|
||||
@@ -6,15 +6,13 @@ class PaintBox {
|
||||
/**
|
||||
* @param {string|Element|external:jQuery} container
|
||||
* @param {"fill"} type
|
||||
* @param {string} color
|
||||
* @param {number} opacity
|
||||
*/
|
||||
constructor (container, type, color, opacity) {
|
||||
constructor (container, type) {
|
||||
// set up gradients to be used for the buttons
|
||||
const svgdocbox = new DOMParser().parseFromString(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<rect
|
||||
fill="#${color}" opacity="${opacity}" width="22" height="22"/>
|
||||
fill="#000000" opacity="1" width="22" height="22"/>
|
||||
<defs><linearGradient id="gradbox_${PaintBox.ctr++}"/></defs>
|
||||
</svg>`,
|
||||
'text/xml'
|
||||
@@ -26,7 +24,7 @@ class PaintBox {
|
||||
this.rect = docElem.firstElementChild;
|
||||
this.defs = docElem.getElementsByTagName('defs')[0];
|
||||
this.grad = this.defs.firstElementChild;
|
||||
this.paint = new $.jGraduate.Paint({solidColor: color});
|
||||
// this.paint = new $.jGraduate.Paint({solidColor: color});
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -138,22 +136,6 @@ class PaintBox {
|
||||
this.setPaint(paint);
|
||||
return (paint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
prep () {
|
||||
const ptype = this.paint.type;
|
||||
|
||||
switch (ptype) {
|
||||
case 'linearGradient':
|
||||
case 'radialGradient': {
|
||||
const paint = new $.jGraduate.Paint({copy: this.paint});
|
||||
this.setPaint(this.type, paint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PaintBox.ctr = 0;
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import './seButton.js';
|
||||
import './seFlyingButton.js';
|
||||
import './seExplorerButton.js';
|
||||
import './seDropdown.js';
|
||||
import './seZoom.js';
|
||||
import './seInput.js';
|
||||
import './seSpinInput.js';
|
||||
import './sePalette.js';
|
||||
import './seMenu.js';
|
||||
import './seMenuItem.js';
|
||||
import './seList.js';
|
||||
import './seListItem.js';
|
||||
import './seColorPicker.js';
|
||||
|
||||
@@ -283,7 +283,8 @@ export default function jQueryPluginJGraduate ($) {
|
||||
const $wc = (selector) => $($shadowRoot.querySelectorAll(selector));
|
||||
|
||||
if (!idref) {
|
||||
/* await */ $.alert('Container element must have an id attribute to maintain unique id strings for sub-elements.');
|
||||
// eslint-disable-next-line no-alert
|
||||
alert('Container element must have an id attribute to maintain unique id strings for sub-elements.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
99
src/editor/components/seList.js
Normal file
99
src/editor/components/seList.js
Normal file
@@ -0,0 +1,99 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import 'elix/define/DropdownList.js';
|
||||
|
||||
const template = document.createElement('template');
|
||||
template.innerHTML = `
|
||||
<style>
|
||||
[part~="source"] {
|
||||
grid-template-columns: 20px 1fr auto;
|
||||
}
|
||||
::slotted(*) {
|
||||
padding: 4px;
|
||||
background: #E8E8E8;
|
||||
border: 1px solid #B0B0B0;
|
||||
width: 100%;
|
||||
}
|
||||
[part~="popup"] {
|
||||
width: 150%;
|
||||
}
|
||||
</style>
|
||||
<label>Label</label>
|
||||
<elix-dropdown-list>
|
||||
<slot></slot>
|
||||
</elix-dropdown-list>
|
||||
|
||||
`;
|
||||
/**
|
||||
* @class SeList
|
||||
*/
|
||||
export class SeList extends HTMLElement {
|
||||
/**
|
||||
* @function constructor
|
||||
*/
|
||||
constructor () {
|
||||
super();
|
||||
// create the shadowDom and insert the template
|
||||
this._shadowRoot = this.attachShadow({mode: 'open'});
|
||||
this._shadowRoot.appendChild(template.content.cloneNode(true));
|
||||
this.$dropdown = this._shadowRoot.querySelector('elix-dropdown-list');
|
||||
this.$label = this._shadowRoot.querySelector('label');
|
||||
}
|
||||
/**
|
||||
* @function observedAttributes
|
||||
* @returns {any} observed
|
||||
*/
|
||||
static get observedAttributes () {
|
||||
return ['label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @function attributeChangedCallback
|
||||
* @param {string} name
|
||||
* @param {string} oldValue
|
||||
* @param {string} newValue
|
||||
* @returns {void}
|
||||
*/
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
switch (name) {
|
||||
case 'label':
|
||||
this.$label.textContent = newValue;
|
||||
break;
|
||||
default:
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`unknown attribute: ${name}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {any}
|
||||
*/
|
||||
get label () {
|
||||
return this.getAttribute('label');
|
||||
}
|
||||
|
||||
/**
|
||||
* @function set
|
||||
* @returns {void}
|
||||
*/
|
||||
set label (value) {
|
||||
this.setAttribute('label', value);
|
||||
}
|
||||
/**
|
||||
* @function connectedCallback
|
||||
* @returns {void}
|
||||
*/
|
||||
connectedCallback () {
|
||||
this.$dropdown.addEventListener('change', (e) => {
|
||||
e.preventDefault();
|
||||
const selectedItem = e?.detail?.closeResult;
|
||||
if (selectedItem !== undefined && selectedItem?.id !== undefined) {
|
||||
document.getElementById(selectedItem.id).click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
customElements.define('se-list', SeList);
|
||||
71
src/editor/components/seListItem.js
Normal file
71
src/editor/components/seListItem.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import 'elix/define/Option.js';
|
||||
|
||||
const template = document.createElement('template');
|
||||
template.innerHTML = `
|
||||
<style>
|
||||
</style>
|
||||
<elix-option aria-label="option">
|
||||
<slot></slot>
|
||||
</elix-option>
|
||||
`;
|
||||
/**
|
||||
* @class SeMenu
|
||||
*/
|
||||
export class SeListItem extends HTMLElement {
|
||||
/**
|
||||
* @function constructor
|
||||
*/
|
||||
constructor () {
|
||||
super();
|
||||
// create the shadowDom and insert the template
|
||||
this._shadowRoot = this.attachShadow({mode: 'open'});
|
||||
this._shadowRoot.appendChild(template.content.cloneNode(true));
|
||||
this.$menuitem = this._shadowRoot.querySelector('elix-menu-item');
|
||||
}
|
||||
/**
|
||||
* @function observedAttributes
|
||||
* @returns {any} observed
|
||||
*/
|
||||
static get observedAttributes () {
|
||||
return ['option'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @function attributeChangedCallback
|
||||
* @param {string} name
|
||||
* @param {string} oldValue
|
||||
* @param {string} newValue
|
||||
* @returns {void}
|
||||
*/
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
switch (name) {
|
||||
case 'option':
|
||||
this.$menuitem.setAttribute('option', newValue);
|
||||
break;
|
||||
default:
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`unknown attribute: ${name}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {any}
|
||||
*/
|
||||
get option () {
|
||||
return this.getAttribute('option');
|
||||
}
|
||||
|
||||
/**
|
||||
* @function set
|
||||
* @returns {void}
|
||||
*/
|
||||
set option (value) {
|
||||
this.setAttribute('option', value);
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
customElements.define('se-list-item', SeListItem);
|
||||
@@ -8,7 +8,7 @@ template.innerHTML = `
|
||||
</style>
|
||||
<elix-menu-item>
|
||||
<div style="display:inline-block;">
|
||||
<img src="" alt="icon" style="display:none;" />
|
||||
<img src="./images/logo.svg" alt="icon" style="display:none;" />
|
||||
<span></span>
|
||||
</div>
|
||||
</elix-menu-item>
|
||||
|
||||
@@ -18,7 +18,7 @@ template.innerHTML = `
|
||||
padding: 0px;
|
||||
}
|
||||
</style>
|
||||
<img src="./images/logo.svg" alt="icon" width="12" height="12" />
|
||||
<img src="./images/logo.svg" alt="icon" width="12" height="12" aria-labelledby="label" />
|
||||
<span id="label">label</span>
|
||||
<elix-number-spin-box min="1" step="1"></elix-number-spin-box>
|
||||
`;
|
||||
|
||||
179
src/editor/components/seZoom.js
Normal file
179
src/editor/components/seZoom.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import ListComboBox from 'elix/define/ListComboBox.js';
|
||||
import NumberSpinBox from 'elix/define/NumberSpinBox.js';
|
||||
// import Input from 'elix/src/base/Input.js';
|
||||
import * as internal from 'elix/src/base/internal.js';
|
||||
import {templateFrom, fragmentFrom} from 'elix/src/core/htmlLiterals.js';
|
||||
|
||||
/**
|
||||
* @class Dropdown
|
||||
*/
|
||||
class Zoom extends ListComboBox {
|
||||
/**
|
||||
* @function get
|
||||
* @returns {PlainObject}
|
||||
*/
|
||||
get [internal.defaultState] () {
|
||||
return Object.assign(super[internal.defaultState], {
|
||||
inputPartType: NumberSpinBox,
|
||||
src: './images/logo.svg',
|
||||
inputsize: '100%'
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {PlainObject}
|
||||
*/
|
||||
get [internal.template] () {
|
||||
const result = super[internal.template];
|
||||
const source = result.content.getElementById('source');
|
||||
// add a icon before our dropdown
|
||||
source.prepend(fragmentFrom.html`
|
||||
<img src="./images/logo.svg" alt="icon" width="18" height="18"></img>
|
||||
`.cloneNode(true));
|
||||
// change the style so it fits in our toolbar
|
||||
result.content.append(
|
||||
templateFrom.html`
|
||||
<style>
|
||||
[part~="source"] {
|
||||
grid-template-columns: 20px 1fr auto;
|
||||
}
|
||||
::slotted(*) {
|
||||
padding: 4px;
|
||||
background: #E8E8E8;
|
||||
border: 1px solid #B0B0B0;
|
||||
width: 100%;
|
||||
}
|
||||
[part~="popup"] {
|
||||
width: 150%;
|
||||
}
|
||||
</style>
|
||||
`.content
|
||||
);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @function observedAttributes
|
||||
* @returns {any} observed
|
||||
*/
|
||||
static get observedAttributes () {
|
||||
return ['title', 'src', 'inputsize', 'value'];
|
||||
}
|
||||
/**
|
||||
* @function attributeChangedCallback
|
||||
* @param {string} name
|
||||
* @param {string} oldValue
|
||||
* @param {string} newValue
|
||||
* @returns {void}
|
||||
*/
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
switch (name) {
|
||||
case 'title':
|
||||
// this.$span.setAttribute('title', `${newValue} ${shortcut ? `[${shortcut}]` : ''}`);
|
||||
break;
|
||||
case 'src':
|
||||
this.src = newValue;
|
||||
break;
|
||||
case 'inputsize':
|
||||
this.inputsize = newValue;
|
||||
break;
|
||||
default:
|
||||
super.attributeChangedCallback(name, oldValue, newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function [internal.render]
|
||||
* @param {PlainObject} changed
|
||||
* @returns {void}
|
||||
*/
|
||||
[internal.render] (changed) {
|
||||
super[internal.render](changed);
|
||||
if (this[internal.firstRender]) {
|
||||
this.$img = this.shadowRoot.querySelector('img');
|
||||
this.$input = this.shadowRoot.getElementById('input');
|
||||
}
|
||||
if (changed.src) {
|
||||
this.$img.setAttribute('src', this[internal.state].src);
|
||||
}
|
||||
if (changed.inputsize) {
|
||||
this.$input.shadowRoot.querySelector('[part~="input"]').style.width = this[internal.state].inputsize;
|
||||
}
|
||||
if (changed.inputPartType) {
|
||||
// Wire up handler on new input.
|
||||
this.addEventListener('close', (e) => {
|
||||
e.preventDefault();
|
||||
const value = e.detail?.closeResult?.getAttribute('value');
|
||||
if (value) {
|
||||
const closeEvent = new CustomEvent('change', {detail: {value}});
|
||||
this.dispatchEvent(closeEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function src
|
||||
* @returns {string} src
|
||||
*/
|
||||
get src () {
|
||||
return this[internal.state].src;
|
||||
}
|
||||
/**
|
||||
* @function src
|
||||
* @returns {void}
|
||||
*/
|
||||
set src (src) {
|
||||
this[internal.setState]({src});
|
||||
}
|
||||
/**
|
||||
* @function inputsize
|
||||
* @returns {string} src
|
||||
*/
|
||||
get inputsize () {
|
||||
return this[internal.state].inputsize;
|
||||
}
|
||||
/**
|
||||
* @function src
|
||||
* @returns {void}
|
||||
*/
|
||||
set inputsize (inputsize) {
|
||||
this[internal.setState]({inputsize});
|
||||
}
|
||||
/**
|
||||
* @function value
|
||||
* @returns {string} src
|
||||
*/
|
||||
get value () {
|
||||
return this[internal.state].value;
|
||||
}
|
||||
/**
|
||||
* @function value
|
||||
* @returns {void}
|
||||
*/
|
||||
set value (value) {
|
||||
this[internal.setState]({value});
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
customElements.define('se-zoom', Zoom);
|
||||
|
||||
/*
|
||||
{TODO
|
||||
min: 0.001, max: 10000, step: 50, stepfunc: stepZoom,
|
||||
function stepZoom (elem, step) {
|
||||
const origVal = Number(elem.value);
|
||||
if (origVal === 0) { return 100; }
|
||||
const sugVal = origVal + step;
|
||||
if (step === 0) { return origVal; }
|
||||
|
||||
if (origVal >= 100) {
|
||||
return sugVal;
|
||||
}
|
||||
if (sugVal >= origVal) {
|
||||
return origVal * 2;
|
||||
}
|
||||
return origVal / 2;
|
||||
}
|
||||
*/
|
||||
@@ -184,7 +184,7 @@ export class SeCMenuDialog extends HTMLElement {
|
||||
});
|
||||
break;
|
||||
default:
|
||||
super.attributeChangedCallback(name, oldValue, newValue);
|
||||
// super.attributeChangedCallback(name, oldValue, newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ export class SeCMenuLayerDialog extends HTMLElement {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.attributeChangedCallback(name, oldValue, newValue);
|
||||
// super.attributeChangedCallback(name, oldValue, newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,11 +194,11 @@ template.innerHTML = `
|
||||
</fieldset>
|
||||
<fieldset id="change_grid">
|
||||
<legend id="svginfo_grid_settings">Grid</legend>
|
||||
<label>
|
||||
<label for="svginfo_snap_onoff">
|
||||
<span id="svginfo_snap_onoff">Snapping on/off</span>
|
||||
<input type="checkbox" value="snapping_on" id="grid_snapping_on" />
|
||||
</label>
|
||||
<label>
|
||||
<label for="grid_snapping_step">
|
||||
<span id="svginfo_snap_step">Snapping Step-Size:</span>
|
||||
<input type="text" id="grid_snapping_step" size="3" value="10" />
|
||||
</label>
|
||||
|
||||
@@ -3,3 +3,7 @@ import './editorPreferencesDialog.js';
|
||||
import './svgSourceDialog.js';
|
||||
import './cmenuDialog.js';
|
||||
import './cmenuLayersDialog.js';
|
||||
import './seSelectDialog.js';
|
||||
import './seConfirmDialog.js';
|
||||
import './sePromptDialog.js';
|
||||
import './seAlertDialog.js';
|
||||
|
||||
11
src/editor/dialogs/seAlertDialog.js
Normal file
11
src/editor/dialogs/seAlertDialog.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// eslint-disable-next-line node/no-unpublished-import
|
||||
import AlertDialog from 'elix/define/AlertDialog.js';
|
||||
|
||||
const dialog = new AlertDialog();
|
||||
const seAlert = (text) => {
|
||||
dialog.textContent = text;
|
||||
dialog.choices = ['Ok'];
|
||||
dialog.open();
|
||||
};
|
||||
|
||||
window.seAlert = seAlert;
|
||||
13
src/editor/dialogs/seConfirmDialog.js
Normal file
13
src/editor/dialogs/seConfirmDialog.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// eslint-disable-next-line node/no-unpublished-import
|
||||
import AlertDialog from 'elix/define/AlertDialog.js';
|
||||
|
||||
const dialog = new AlertDialog();
|
||||
const seConfirm = async (text, choices) => {
|
||||
dialog.textContent = text;
|
||||
dialog.choices = (choices === undefined) ? ['Ok', 'Cancel'] : choices;
|
||||
dialog.open();
|
||||
const response = await dialog.whenClosed();
|
||||
return response.choice;
|
||||
};
|
||||
|
||||
window.seConfirm = seConfirm;
|
||||
83
src/editor/dialogs/sePromptDialog.js
Normal file
83
src/editor/dialogs/sePromptDialog.js
Normal file
@@ -0,0 +1,83 @@
|
||||
// eslint-disable-next-line node/no-unpublished-import
|
||||
import AlertDialog from 'elix/define/AlertDialog.js';
|
||||
/**
|
||||
* @class SePromptDialog
|
||||
*/
|
||||
export class SePromptDialog extends HTMLElement {
|
||||
/**
|
||||
* @function constructor
|
||||
*/
|
||||
constructor () {
|
||||
super();
|
||||
// create the shadowDom and insert the template
|
||||
this._shadowRoot = this.attachShadow({mode: 'open'});
|
||||
this.dialog = new AlertDialog();
|
||||
}
|
||||
/**
|
||||
* @function observedAttributes
|
||||
* @returns {any} observed
|
||||
*/
|
||||
static get observedAttributes () {
|
||||
return ['title', 'close'];
|
||||
}
|
||||
/**
|
||||
* @function attributeChangedCallback
|
||||
* @param {string} name
|
||||
* @param {string} oldValue
|
||||
* @param {string} newValue
|
||||
* @returns {void}
|
||||
*/
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
switch (name) {
|
||||
case 'title':
|
||||
if (this.dialog.opened) {
|
||||
this.dialog.close();
|
||||
}
|
||||
this.dialog.textContent = newValue;
|
||||
this.dialog.choices = ['Cancel'];
|
||||
this.dialog.open();
|
||||
break;
|
||||
case 'close':
|
||||
if (this.dialog.opened) {
|
||||
this.dialog.close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.error('unkonw attr for:', name, 'newValue =', newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {any}
|
||||
*/
|
||||
get title () {
|
||||
return this.getAttribute('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* @function set
|
||||
* @returns {void}
|
||||
*/
|
||||
set title (value) {
|
||||
this.setAttribute('title', value);
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {any}
|
||||
*/
|
||||
get close () {
|
||||
return this.getAttribute('close');
|
||||
}
|
||||
|
||||
/**
|
||||
* @function set
|
||||
* @returns {void}
|
||||
*/
|
||||
set close (value) {
|
||||
this.setAttribute('close', value);
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
customElements.define('se-prompt-dialog', SePromptDialog);
|
||||
13
src/editor/dialogs/seSelectDialog.js
Normal file
13
src/editor/dialogs/seSelectDialog.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// eslint-disable-next-line node/no-unpublished-import
|
||||
import AlertDialog from 'elix/define/AlertDialog.js';
|
||||
|
||||
const dialog = new AlertDialog();
|
||||
const seSelect = async (text, choices) => {
|
||||
dialog.textContent = text;
|
||||
dialog.choices = choices;
|
||||
dialog.open();
|
||||
const response = await dialog.whenClosed();
|
||||
return response.choice;
|
||||
};
|
||||
|
||||
window.seSelect = seSelect;
|
||||
@@ -362,7 +362,7 @@ class EmbeddedSVGEdit {
|
||||
let sameOriginWithGlobal = false;
|
||||
try {
|
||||
sameOriginWithGlobal = window.location.origin === that.frame.contentWindow.location.origin &&
|
||||
that.frame.contentWindow.svgEditor.canvas;
|
||||
that.frame.contentWindow.svgEditor.svgCanvas;
|
||||
} catch (err) {}
|
||||
|
||||
if (sameOriginWithGlobal) {
|
||||
|
||||
@@ -23,8 +23,8 @@ export default {
|
||||
name: 'arrows',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const
|
||||
addElem = svgCanvas.addSVGElementFromJson,
|
||||
{nonce, $} = S,
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
name: 'closepath',
|
||||
async init ({importLocale, $}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
let selElems;
|
||||
const updateButton = function (path) {
|
||||
const seglist = path.pathSegList,
|
||||
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
name: 'connector',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const {getElem} = svgCanvas;
|
||||
const {$, svgroot} = S,
|
||||
addElem = svgCanvas.addSVGElementFromJson,
|
||||
@@ -356,7 +356,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}];
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
return {
|
||||
/** @todo JFH special flag */
|
||||
newUI: true,
|
||||
@@ -374,7 +374,7 @@ export default {
|
||||
startX = opts.start_x;
|
||||
startY = opts.start_y;
|
||||
const mode = svgCanvas.getMode();
|
||||
const {curConfig: {initStroke}} = svgEditor;
|
||||
const {curConfig: {initStroke}} = svgEditor.configObj;
|
||||
|
||||
if (mode === 'connector') {
|
||||
if (started) { return undefined; }
|
||||
|
||||
@@ -23,10 +23,10 @@ export default {
|
||||
name: 'eyedropper',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {$, ChangeElementCommand} = S, // , svgcontent,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
svgCanvas = svgEditor.canvas,
|
||||
{svgCanvas} = svgEditor,
|
||||
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
|
||||
currentStyle = {
|
||||
fillPaint: 'red', fillOpacity: 1.0,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* globals seConfirm */
|
||||
/**
|
||||
* @file ext-foreignobject.js
|
||||
*
|
||||
@@ -24,13 +25,13 @@ export default {
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const {$, text2xml, NS} = S;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const
|
||||
// {svgcontent} = S,
|
||||
// addElem = svgCanvas.addSVGElementFromJson,
|
||||
svgdoc = S.svgroot.parentNode.ownerDocument;
|
||||
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
|
||||
const properlySourceSizeTextArea = function () {
|
||||
// TODO: remove magic numbers here and get values from CSS
|
||||
@@ -196,11 +197,11 @@ export default {
|
||||
// Create source save/cancel buttons
|
||||
/* const save = */ $('#tool_source_save').clone()
|
||||
.hide().attr('id', 'foreign_save').unbind()
|
||||
.appendTo('#tool_source_back').click(async function () {
|
||||
.appendTo('#tool_source_back').click(function () {
|
||||
if (!editingforeign) { return; }
|
||||
|
||||
if (!setForeignString($('#svg_source_textarea').val())) {
|
||||
const ok = await $.confirm('Errors found. Revert to original?');
|
||||
const ok = seConfirm('Errors found. Revert to original?');
|
||||
if (!ok) { return; }
|
||||
endChanges();
|
||||
} else {
|
||||
|
||||
@@ -23,15 +23,15 @@ export default {
|
||||
name: 'grid',
|
||||
async init ({$, NS, getTypeMap}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
||||
{assignAttributes} = svgCanvas,
|
||||
hcanvas = document.createElement('canvas'),
|
||||
canvBG = $('#canvasBackground'),
|
||||
units = getTypeMap(), // Assumes prior `init()` call on `units.js` module
|
||||
intervals = [0.01, 0.1, 1, 10, 100, 1000];
|
||||
let showGrid = svgEditor.curConfig.showGrid || false;
|
||||
let showGrid = svgEditor.configObj.curConfig.showGrid || false;
|
||||
|
||||
$(hcanvas).hide().appendTo('body');
|
||||
|
||||
@@ -90,7 +90,7 @@ export default {
|
||||
*/
|
||||
function updateGrid (zoom) {
|
||||
// TODO: Try this with <line> elements, then compare performance difference
|
||||
const unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
|
||||
const unit = units[svgEditor.configObj.curConfig.baseUnit]; // 1 = 1px
|
||||
const uMulti = unit * zoom;
|
||||
// Calculate the main number interval
|
||||
const rawM = 100 / uMulti;
|
||||
@@ -109,7 +109,7 @@ export default {
|
||||
const part = bigInt / 10;
|
||||
|
||||
ctx.globalAlpha = 0.2;
|
||||
ctx.strokeStyle = svgEditor.curConfig.gridColor;
|
||||
ctx.strokeStyle = svgEditor.configObj.curConfig.gridColor;
|
||||
for (let i = 1; i < 10; i++) {
|
||||
const subD = Math.round(part * i) + 0.5;
|
||||
// const lineNum = (i % 2)?12:10;
|
||||
@@ -161,7 +161,7 @@ export default {
|
||||
events: {
|
||||
id: 'view_grid',
|
||||
click () {
|
||||
svgEditor.curConfig.showGrid = showGrid = !showGrid;
|
||||
svgEditor.configObj.curConfig.showGrid = showGrid = !showGrid;
|
||||
gridUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ export default {
|
||||
name: 'helloworld',
|
||||
async init ({$, importLocale}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
return {
|
||||
name: strings.name,
|
||||
events: [{
|
||||
@@ -78,7 +78,7 @@ export default {
|
||||
});
|
||||
|
||||
// Show the text using the custom alert function
|
||||
$.alert(text);
|
||||
alert(text); // eslint-disable-line no-alert
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
name: 'imagelib',
|
||||
async init ({$, decode64, dropXMLInternalSubset}) {
|
||||
const svgEditor = this;
|
||||
const imagelibStrings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const imagelibStrings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
|
||||
const {uiStrings, canvas: svgCanvas} = svgEditor;
|
||||
|
||||
@@ -223,7 +223,7 @@ export default {
|
||||
} else {
|
||||
pending[id].entry.remove();
|
||||
}
|
||||
// await $.alert('Unexpected data was returned: ' + response, function() {
|
||||
// await alert('Unexpected data was returned: ' + response, function() {
|
||||
// if (mode !== 'm') {
|
||||
// closeBrowser();
|
||||
// } else {
|
||||
@@ -372,7 +372,7 @@ export default {
|
||||
let browser = $('#imgbrowse');
|
||||
if (!browser.length) {
|
||||
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
|
||||
'</div></div>').insertAfter('#svg_docprops');
|
||||
'</div></div>').insertAfter('#svg_editor');
|
||||
browser = $('#imgbrowse');
|
||||
|
||||
const allLibs = imagelibStrings.select_lib;
|
||||
@@ -386,8 +386,8 @@ export default {
|
||||
left: 0,
|
||||
width: '100%'
|
||||
});
|
||||
|
||||
const cancel = $('<button>' + uiStrings.common.cancel + '</button>')
|
||||
// eslint-disable-next-line max-len
|
||||
$('<button><img class="svg_icon" src="./images/cancel.svg" alt="icon" width="16" height="16" />' + uiStrings.common.cancel + '</button>')
|
||||
.appendTo(browser)
|
||||
.on('click touchend', function () {
|
||||
$('#imgbrowse_holder').hide();
|
||||
@@ -398,8 +398,8 @@ export default {
|
||||
});
|
||||
|
||||
const leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
|
||||
|
||||
const back = $('<button hidden>' + imagelibStrings.show_list + '</button>')
|
||||
// eslint-disable-next-line max-len
|
||||
const back = $('<button hidden><img class="svg_icon" src="./images/library.svg" alt="icon" width="16" height="16" />' + imagelibStrings.show_list + '</button>')
|
||||
.appendTo(leftBlock)
|
||||
.on('click touchend', function () {
|
||||
frame.attr('src', 'about:blank').hide();
|
||||
@@ -430,9 +430,6 @@ export default {
|
||||
'margin-top': 10
|
||||
});
|
||||
|
||||
cancel.prepend($.getSvgIcon('cancel', true));
|
||||
back.prepend($.getSvgIcon('tool_imagelib', true));
|
||||
|
||||
imagelibStrings.imgLibs.forEach(function ({name, url, description}) {
|
||||
$('<li>')
|
||||
.appendTo(libOpts)
|
||||
@@ -452,21 +449,16 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
const buttons = [{
|
||||
const events = {
|
||||
id: 'tool_imagelib',
|
||||
type: 'app_menu',
|
||||
icon: 'imagelib.png',
|
||||
position: 4,
|
||||
events: {
|
||||
mouseup: showBrowser
|
||||
click () {
|
||||
showBrowser();
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
return {
|
||||
svgicons: 'ext-imagelib.xml',
|
||||
buttons: imagelibStrings.buttons.map((button, i) => {
|
||||
return Object.assign(buttons[i], button);
|
||||
}),
|
||||
events,
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#imgbrowse_holder {' +
|
||||
|
||||
@@ -45,9 +45,9 @@ export default {
|
||||
name: 'markers',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {$} = S;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const // {svgcontent} = S,
|
||||
addElem = svgCanvas.addSVGElementFromJson;
|
||||
const mtypes = ['start', 'mid', 'end'];
|
||||
@@ -404,12 +404,13 @@ export default {
|
||||
|
||||
/**
|
||||
* @param {"start"|"mid"|"end"} pos
|
||||
* @returns {Promise<void>} Resolves to `undefined`
|
||||
* @returns {void} Resolves to `undefined`
|
||||
*/
|
||||
async function showTextPrompt (pos) {
|
||||
function showTextPrompt (pos) {
|
||||
let def = $('#' + pos + '_marker').val();
|
||||
if (def.substr(0, 1) === '\\') { def = ''; }
|
||||
const txt = await $.prompt('Enter text for ' + pos + ' marker', def);
|
||||
// eslint-disable-next-line no-alert
|
||||
const txt = prompt('Enter text for ' + pos + ' marker', def);
|
||||
if (txt) {
|
||||
triggerTextEntry(pos, txt);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ export default {
|
||||
name: 'mathjax',
|
||||
async init ({$}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
|
||||
// Configuration of the MathJax extention.
|
||||
|
||||
@@ -202,7 +202,8 @@ export default {
|
||||
});
|
||||
} catch (e) {
|
||||
console.log('Failed loading MathJax.'); // eslint-disable-line no-console
|
||||
$.alert('Failed loading MathJax. You will not be able to change the mathematics.');
|
||||
// eslint-disable-next-line no-alert
|
||||
alert('Failed loading MathJax. You will not be able to change the mathematics.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ export default {
|
||||
name: 'panning',
|
||||
async init ({importLocale}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const buttons = [{
|
||||
id: 'ext-panning',
|
||||
icon: 'panning.png',
|
||||
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
name: 'placemark',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const addElem = svgCanvas.addSVGElementFromJson;
|
||||
const {$} = S; // {svgcontent},
|
||||
let
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
||||
// undoCommand = 'Not image',
|
||||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const markerTypes = {
|
||||
nomarker: {},
|
||||
forwardslash:
|
||||
|
||||
@@ -22,11 +22,11 @@ export default {
|
||||
name: 'polygon',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
const {$} = S, // {svgcontent}
|
||||
// addElem = svgCanvas.addSVGElementFromJson,
|
||||
editingitex = false;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
let selElems,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
|
||||
/*
|
||||
if (!setItexString($('#svg_source_textarea').val())) {
|
||||
const ok = await $.confirm('Errors found. Revert to original?', function (ok) {
|
||||
const ok = seConfirm('Errors found. Revert to original?', function (ok) {
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ export default {
|
||||
name: 'server_moinsave',
|
||||
async init ({$, encode64, importLocale}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {svgCanvas} = svgEditor;
|
||||
const saveSvgAction = '/+modify';
|
||||
|
||||
// Create upload target (hidden iframe)
|
||||
@@ -64,7 +64,8 @@ export default {
|
||||
<input type="hidden" name="contenttype" value="application/x-svgdraw">
|
||||
`).appendTo('body')
|
||||
.submit().remove();
|
||||
$.alert(strings.saved);
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(strings.saved);
|
||||
top.window.location = '/' + name;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ export default {
|
||||
name: 'server_opensave',
|
||||
async init ({$, decode64, encode64}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const {
|
||||
curConfig: {
|
||||
avoidClientSide, // Deprecated
|
||||
@@ -146,7 +146,8 @@ export default {
|
||||
}
|
||||
|
||||
if (note.length) {
|
||||
await $.alert(note);
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(note);
|
||||
}
|
||||
|
||||
const filename = getFileNameFromTitle();
|
||||
|
||||
@@ -11,7 +11,7 @@ export default {
|
||||
name: 'shapes',
|
||||
init ({$}) {
|
||||
const svgEditor = this;
|
||||
const canv = svgEditor.canvas;
|
||||
const canv = svgEditor.svgCanvas;
|
||||
const svgroot = canv.getRootElem();
|
||||
let lastBBox = {};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
name: 'star',
|
||||
async init (S) {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
|
||||
const {$} = S; // {svgcontent},
|
||||
let
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
||||
// undoCommand = 'Not image',
|
||||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -18,24 +18,47 @@
|
||||
* @todo We might provide control of storage settings through the UI besides the
|
||||
* initial (or URL-forced) dialog. *
|
||||
*/
|
||||
import './storageDialog.js';
|
||||
|
||||
const loadExtensionTranslation = async function (lang) {
|
||||
let translationModule;
|
||||
try {
|
||||
translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`);
|
||||
} catch (_error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Missing translation (${lang}) - using 'en'`);
|
||||
translationModule = await import(`./locale/en.js`);
|
||||
/**
|
||||
* Expire the storage cookie.
|
||||
* @returns {void}
|
||||
*/
|
||||
const removeStoragePrefCookie = () => {
|
||||
expireCookie('svgeditstore');
|
||||
};
|
||||
/**
|
||||
* Set the cookie to expire.
|
||||
* @param {string} cookie
|
||||
* @returns {void}
|
||||
*/
|
||||
const expireCookie = (cookie) => {
|
||||
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace `storagePrompt` parameter within URL.
|
||||
* @param {string} val
|
||||
* @returns {void}
|
||||
* @todo Replace the string manipulation with `searchParams.set`
|
||||
*/
|
||||
const replaceStoragePrompt = (val) => {
|
||||
val = val ? 'storagePrompt=' + val : '';
|
||||
const loc = top.location; // Allow this to work with the embedded editor as well
|
||||
if (loc.href.includes('storagePrompt=')) {
|
||||
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
|
||||
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
|
||||
});
|
||||
} else {
|
||||
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
|
||||
}
|
||||
return translationModule.default;
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'storage',
|
||||
init ({$}) {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
|
||||
// We could empty any already-set data for users when they decline storage,
|
||||
// but it would be a risk for users who wanted to store but accidentally
|
||||
@@ -43,7 +66,6 @@ export default {
|
||||
// to change, set the "emptyStorageOnDecline" config setting to true
|
||||
// in svgedit-config-iife.js/svgedit-config-es.js.
|
||||
const {
|
||||
emptyStorageOnDecline,
|
||||
// When the code in svg-editor.js prevents local storage on load per
|
||||
// user request, we also prevent storing on unload here so as to
|
||||
// avoid third-party sites making XSRF requests or providing links
|
||||
@@ -55,31 +77,50 @@ export default {
|
||||
// the "noStorageOnLoad" config setting to true in svgedit-config-*.js.
|
||||
noStorageOnLoad,
|
||||
forceStorage
|
||||
} = svgEditor.curConfig;
|
||||
const {storage, updateCanvas} = svgEditor;
|
||||
} = svgEditor.configObj.curConfig;
|
||||
const {storage} = svgEditor;
|
||||
|
||||
/**
|
||||
* Replace `storagePrompt` parameter within URL.
|
||||
* @param {string} val
|
||||
* @returns {void}
|
||||
* @todo Replace the string manipulation with `searchParams.set`
|
||||
*/
|
||||
function replaceStoragePrompt (val) {
|
||||
val = val ? 'storagePrompt=' + val : '';
|
||||
const loc = top.location; // Allow this to work with the embedded editor as well
|
||||
if (loc.href.includes('storagePrompt=')) {
|
||||
/*
|
||||
loc.href = loc.href.replace(/(?<sep>[&?])storagePrompt=[^&]*(?<amp>&?)/, function (n0, sep, amp) {
|
||||
return (val ? sep : '') + val + (!val && amp ? sep : (amp || ''));
|
||||
});
|
||||
*/
|
||||
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
|
||||
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
|
||||
});
|
||||
} else {
|
||||
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
|
||||
// storageDialog added to DOM
|
||||
const storageBox = document.createElement('se-storage-dialog');
|
||||
storageBox.setAttribute('id', 'se-storage-dialog');
|
||||
document.body.append(storageBox);
|
||||
|
||||
// manage the change in the storageDialog
|
||||
|
||||
storageBox.addEventListener('change', (e) => {
|
||||
storageBox.setAttribute('dialog', 'close');
|
||||
if (e?.detail?.trigger === 'ok') {
|
||||
if (e?.detail?.select !== 'noPrefsOrContent') {
|
||||
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');
|
||||
document.cookie = 'svgeditstore=' + encodeURIComponent(e.detail.select) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
|
||||
if (storagePrompt === 'true' && e?.detail?.checkbox) {
|
||||
replaceStoragePrompt();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
removeStoragePrefCookie();
|
||||
if (svgEditor.configObj.curConfig.emptyStorageOnDecline && e?.detail?.checkbox) {
|
||||
this.setSVGContentStorage('');
|
||||
Object.keys(svgEditor.curPrefs).forEach((name) => {
|
||||
name = 'svg-edit-' + name;
|
||||
if (svgEditor.storage) {
|
||||
svgEditor.storage.removeItem(name);
|
||||
}
|
||||
expireCookie(name);
|
||||
});
|
||||
}
|
||||
if (e?.detail?.select && e?.detail?.checkbox) {
|
||||
replaceStoragePrompt('false');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (e?.detail?.trigger === 'cancel') {
|
||||
removeStoragePrefCookie();
|
||||
}
|
||||
}
|
||||
setupBeforeUnloadListener();
|
||||
svgEditor.storagePromptState = 'closed';
|
||||
svgEditor.updateCanvas(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets SVG content as a string with "svgedit-" and the current
|
||||
@@ -89,7 +130,7 @@ export default {
|
||||
*/
|
||||
function setSVGContentStorage (val) {
|
||||
if (storage) {
|
||||
const name = 'svgedit-' + svgEditor.curConfig.canvasName;
|
||||
const name = 'svgedit-' + svgEditor.configObj.curConfig.canvasName;
|
||||
if (!val) {
|
||||
storage.removeItem(name);
|
||||
} else {
|
||||
@@ -98,40 +139,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie to expire.
|
||||
* @param {string} cookie
|
||||
* @returns {void}
|
||||
*/
|
||||
function expireCookie (cookie) {
|
||||
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire the storage cookie.
|
||||
* @returns {void}
|
||||
*/
|
||||
function removeStoragePrefCookie () {
|
||||
expireCookie('svgeditstore');
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties storage for each of the current preferences.
|
||||
* @returns {void}
|
||||
*/
|
||||
function emptyStorage () {
|
||||
setSVGContentStorage('');
|
||||
Object.keys(svgEditor.curPrefs).forEach((name) => {
|
||||
name = 'svg-edit-' + name;
|
||||
if (storage) {
|
||||
storage.removeItem(name);
|
||||
}
|
||||
expireCookie(name);
|
||||
});
|
||||
}
|
||||
|
||||
// emptyStorage();
|
||||
|
||||
/**
|
||||
* Listen for unloading: If and only if opted in by the user, set the content
|
||||
* document and preferences into storage:
|
||||
@@ -154,7 +161,7 @@ export default {
|
||||
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
|
||||
// svgEditor.showSaveWarning = false;
|
||||
|
||||
const {curPrefs} = svgEditor;
|
||||
const {curPrefs} = svgEditor.configObj;
|
||||
|
||||
Object.entries(curPrefs).forEach(([key, val]) => {
|
||||
const store = (val !== undefined);
|
||||
@@ -177,15 +184,8 @@ export default {
|
||||
let loaded = false;
|
||||
return {
|
||||
name: 'storage',
|
||||
async langReady ({lang}) {
|
||||
langReady ({lang}) {
|
||||
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const {
|
||||
message, storagePrefsAndContent, storagePrefsOnly,
|
||||
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
|
||||
rememberLabel, rememberTooltip
|
||||
} = strings;
|
||||
|
||||
// No need to run this one-time dialog again just because the user
|
||||
// changes the language
|
||||
if (loaded) {
|
||||
@@ -213,93 +213,13 @@ export default {
|
||||
)
|
||||
// ...then show the storage prompt.
|
||||
)) {
|
||||
const options = [];
|
||||
if (storage) {
|
||||
options.unshift(
|
||||
{value: 'prefsAndContent', text: storagePrefsAndContent},
|
||||
{value: 'prefsOnly', text: storagePrefsOnly},
|
||||
{value: 'noPrefsOrContent', text: storageNoPrefsOrContent}
|
||||
);
|
||||
} else {
|
||||
options.unshift(
|
||||
{value: 'prefsOnly', text: storagePrefs},
|
||||
{value: 'noPrefsOrContent', text: storageNoPrefs}
|
||||
);
|
||||
}
|
||||
|
||||
// Hack to temporarily provide a wide and high enough dialog
|
||||
const oldContainerWidth = $('#dialog_container')[0].style.width,
|
||||
oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
|
||||
oldContentHeight = $('#dialog_content')[0].style.height,
|
||||
oldContainerHeight = $('#dialog_container')[0].style.height;
|
||||
$('#dialog_content')[0].style.height = '120px';
|
||||
$('#dialog_container')[0].style.height = '170px';
|
||||
$('#dialog_container')[0].style.width = '800px';
|
||||
$('#dialog_container')[0].style.marginLeft = '-400px';
|
||||
|
||||
const options = Boolean(storage);
|
||||
// Open select-with-checkbox dialog
|
||||
// From svg-editor.js
|
||||
svgEditor.storagePromptState = 'waiting';
|
||||
const {response: pref, checked} = await $.select(
|
||||
message,
|
||||
options,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
label: rememberLabel,
|
||||
checked: true,
|
||||
tooltip: rememberTooltip
|
||||
}
|
||||
);
|
||||
if (pref && pref !== 'noPrefsOrContent') {
|
||||
// Regardless of whether the user opted
|
||||
// to remember the choice (and move to a URL which won't
|
||||
// ask them again), we have to assume the user
|
||||
// doesn't even want to remember their not wanting
|
||||
// storage, so we don't set the cookie or continue on with
|
||||
// setting storage on beforeunload
|
||||
document.cookie = 'svgeditstore=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'
|
||||
// If the URL was configured to always insist on a prompt, if
|
||||
// the user does indicate a wish to store their info, we
|
||||
// don't want ask them again upon page refresh so move
|
||||
// them instead to a URL which does not always prompt
|
||||
if (storagePrompt === 'true' && checked) {
|
||||
replaceStoragePrompt();
|
||||
return;
|
||||
}
|
||||
} else { // The user does not wish storage (or cancelled, which we treat equivalently)
|
||||
removeStoragePrefCookie();
|
||||
if (pref && // If the user explicitly expresses wish for no storage
|
||||
emptyStorageOnDecline
|
||||
) {
|
||||
emptyStorage();
|
||||
}
|
||||
if (pref && checked) {
|
||||
// Open a URL which won't set storage and won't prompt user about storage
|
||||
replaceStoragePrompt('false');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset width/height of dialog (e.g., for use by Export)
|
||||
$('#dialog_container')[0].style.width = oldContainerWidth;
|
||||
$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
|
||||
$('#dialog_content')[0].style.height = oldContentHeight;
|
||||
$('#dialog_container')[0].style.height = oldContainerHeight;
|
||||
|
||||
// It should be enough to (conditionally) add to storage on
|
||||
// beforeunload, but if we wished to update immediately,
|
||||
// we might wish to try setting:
|
||||
// svgEditor.setConfig({noStorageOnLoad: true});
|
||||
// and then call:
|
||||
// svgEditor.loadContentAndPrefs();
|
||||
|
||||
// We don't check for noStorageOnLoad here because
|
||||
// the prompt gives the user the option to store data
|
||||
setupBeforeUnloadListener();
|
||||
|
||||
svgEditor.storagePromptState = 'closed';
|
||||
updateCanvas(true);
|
||||
const $storageDialog = document.getElementById('se-storage-dialog');
|
||||
$storageDialog.setAttribute('dialog', 'open');
|
||||
$storageDialog.setAttribute('storage', options);
|
||||
} else if (!noStorageOnLoad || forceStorage) {
|
||||
setupBeforeUnloadListener();
|
||||
}
|
||||
|
||||
183
src/editor/extensions/ext-storage/storageDialog.js
Normal file
183
src/editor/extensions/ext-storage/storageDialog.js
Normal file
@@ -0,0 +1,183 @@
|
||||
/* eslint-disable max-len */
|
||||
/* eslint-disable node/no-unpublished-import */
|
||||
import 'elix/define/Dialog.js';
|
||||
|
||||
const template = document.createElement('template');
|
||||
template.innerHTML = `
|
||||
<style>
|
||||
|
||||
#dialog_content {
|
||||
margin: 10px 10px 5px 10px;
|
||||
background: #DDD;
|
||||
overflow: auto;
|
||||
text-align: left;
|
||||
border: 1px solid #B0B0B0;
|
||||
}
|
||||
|
||||
#dialog_content p, #dialog_content select, #dialog_content label {
|
||||
margin: 10px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
#dialog_container {
|
||||
font-family: Verdana;
|
||||
text-align: center;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
max-width: 400px;
|
||||
z-index: 50001;
|
||||
background: #CCC;
|
||||
border: 1px outset #777;
|
||||
font-family:Verdana,Helvetica,sans-serif;
|
||||
font-size:0.8em;
|
||||
}
|
||||
|
||||
#dialog_container, #dialog_content {
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#dialog_buttons input[type=text] {
|
||||
width: 90%;
|
||||
display: block;
|
||||
margin: 0 0 5px 11px;
|
||||
}
|
||||
|
||||
#dialog_buttons input[type=button] {
|
||||
margin: 0 1em;
|
||||
}
|
||||
</style>
|
||||
<elix-dialog id="dialog_box" aria-label="SVG-Edit storage preferences" closed>
|
||||
<div class="overlay"></div>
|
||||
<div id="dialog_container">
|
||||
<div id="dialog_content">
|
||||
<p>
|
||||
By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below.
|
||||
</p>
|
||||
<select id="se-storage-pref">
|
||||
<option value="prefsAndContent">Store preferences and SVG content locally</option>
|
||||
<option value="prefsOnly">Only store preferences locally</option>
|
||||
<option value="noPrefsOrContent">Do not store my preferences or SVG content locally</option>
|
||||
</select>
|
||||
<label title="If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.">
|
||||
Remember this choice?<input type="checkbox" id="se-remember" value="" checked>
|
||||
</label>
|
||||
</div>
|
||||
<div id="dialog_buttons">
|
||||
<button id="storage_ok">
|
||||
<img class="svg_icon" src="./images/ok.svg" alt="icon" width="16" height="16" />
|
||||
Ok
|
||||
</button>
|
||||
<button id="storage_cancel">
|
||||
<img class="svg_icon" src="./images/cancel.svg" alt="icon" width="16" height="16" />
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</elix-dialog>
|
||||
`;
|
||||
/**
|
||||
* @class SeStorageDialog
|
||||
*/
|
||||
export class SeStorageDialog extends HTMLElement {
|
||||
/**
|
||||
* @function constructor
|
||||
*/
|
||||
constructor () {
|
||||
super();
|
||||
// create the shadowDom and insert the template
|
||||
this._shadowRoot = this.attachShadow({mode: 'open'});
|
||||
this._shadowRoot.appendChild(template.content.cloneNode(true));
|
||||
this.$dialog = this._shadowRoot.querySelector('#dialog_box');
|
||||
this.$storage = this._shadowRoot.querySelector('#js-storage');
|
||||
this.$okBtn = this._shadowRoot.querySelector('#storage_ok');
|
||||
this.$cancelBtn = this._shadowRoot.querySelector('#storage_cancel');
|
||||
this.$storageInput = this._shadowRoot.querySelector('#se-storage-pref');
|
||||
this.$rememberInput = this._shadowRoot.querySelector('#se-remember');
|
||||
}
|
||||
/**
|
||||
* @function observedAttributes
|
||||
* @returns {any} observed
|
||||
*/
|
||||
static get observedAttributes () {
|
||||
return ['dialog', 'storage'];
|
||||
}
|
||||
/**
|
||||
* @function attributeChangedCallback
|
||||
* @param {string} name
|
||||
* @param {string} oldValue
|
||||
* @param {string} newValue
|
||||
* @returns {void}
|
||||
*/
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
switch (name) {
|
||||
case 'dialog':
|
||||
if (newValue === 'open') {
|
||||
this.$dialog.open();
|
||||
} else {
|
||||
this.$dialog.close();
|
||||
}
|
||||
break;
|
||||
case 'storage':
|
||||
if (newValue === 'true') {
|
||||
this.$storageInput.options[0].disabled = false;
|
||||
} else {
|
||||
this.$storageInput.options[0].disabled = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// super.attributeChangedCallback(name, oldValue, newValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @function get
|
||||
* @returns {any}
|
||||
*/
|
||||
get dialog () {
|
||||
return this.getAttribute('dialog');
|
||||
}
|
||||
/**
|
||||
* @function set
|
||||
* @returns {void}
|
||||
*/
|
||||
set dialog (value) {
|
||||
this.setAttribute('dialog', value);
|
||||
}
|
||||
/**
|
||||
* @function connectedCallback
|
||||
* @returns {void}
|
||||
*/
|
||||
connectedCallback () {
|
||||
const onSubmitHandler = (e, action) => {
|
||||
const triggerEvent = new CustomEvent('change', {detail: {
|
||||
trigger: action,
|
||||
select: this.$storageInput.value,
|
||||
checkbox: this.$rememberInput.checked
|
||||
}});
|
||||
this.dispatchEvent(triggerEvent);
|
||||
};
|
||||
this.$okBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'ok'));
|
||||
this.$cancelBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'cancel'));
|
||||
}
|
||||
/**
|
||||
* Sets SVG content as a string with "svgedit-" and the current
|
||||
* canvas name as namespace.
|
||||
* @param {string} val
|
||||
* @returns {void}
|
||||
*/
|
||||
setSVGContentStorage (val) {
|
||||
if (this.storage) {
|
||||
const name = 'svgedit-' + this.configObj.curConfig.canvasName;
|
||||
if (!val) {
|
||||
this.storage.removeItem(name);
|
||||
} else {
|
||||
this.storage.setItem(name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register
|
||||
customElements.define('se-storage-dialog', SeStorageDialog);
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
name: 'webappfind',
|
||||
async init ({$}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||
const strings = await loadExtensionTranslation(svgEditor.configObj.pref('lang'));
|
||||
const saveMessage = 'save',
|
||||
readMessage = 'read',
|
||||
excludedMessages = [readMessage, saveMessage];
|
||||
@@ -63,7 +63,8 @@ export default {
|
||||
} */
|
||||
break;
|
||||
case 'save-end':
|
||||
$.alert(`save complete for pathID ${pathID}!`);
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(`save complete for pathID ${pathID}!`);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unexpected WebAppFind event type');
|
||||
@@ -98,7 +99,7 @@ export default {
|
||||
webappfind: {
|
||||
type: saveMessage,
|
||||
pathID,
|
||||
content: svgEditor.canvas.getSvgString()
|
||||
content: svgEditor.svgCanvas.getSvgString()
|
||||
}
|
||||
}, window.location.origin === 'null'
|
||||
// Avoid "null" string error for `file:` protocol (even
|
||||
|
||||
@@ -8,7 +8,7 @@ export default {
|
||||
name: 'xdomain-messaging',
|
||||
init () {
|
||||
const svgEditor = this;
|
||||
const svgCanvas = svgEditor.canvas;
|
||||
const {svgCanvas} = svgEditor;
|
||||
try {
|
||||
window.addEventListener('message', function (e) {
|
||||
// We accept and post strings for the sake of IE9 support
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
// The default is not to allow any origins, including even the same domain or
|
||||
// if run on a `file:///` URL. See `svgedit-config-es.js` for an example of how
|
||||
// to configure
|
||||
const {allowedOrigins} = svgEditor.curConfig;
|
||||
const {allowedOrigins} = svgEditor.configObj.curConfig;
|
||||
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
|
||||
console.log(`Origin ${e.origin} not whitelisted for posting to ${window.origin}`); // eslint-disable-line no-console
|
||||
return;
|
||||
|
||||
10
src/editor/images/library.svg
Normal file
10
src/editor/images/library.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 201 211">
|
||||
<g>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m2.75,49.51761l56.56,-46.26761c12.73,8.25 25.71001,7 46.44,0.75l-56.03999,47.23944l-22.72002,25.01056l-24.23999,-26.73239z" id="svg_2" stroke-width="7"/>
|
||||
<path fill="#a03333" stroke="#3f3f3f" d="m3.75,203.25002c14.33301,7 30.66699,7 46,0l0,-152.00002c-14.66699,8 -32.33301,8 -47,0l1,152.00002zm45.75,-152.25002l56.25,-46.75l0,151l-56,48.00002m-47.25,-154.25002l57.25,-46.5" id="svg_1" stroke-width="7" stroke-linecap="round"/>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m49.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_5"/>
|
||||
<path fill="#2f8e2f" stroke="#3f3f3f" d="m50.75,202.25c14.33301,7 30.66699,7.04253 46,0.04253l0,-151.04253c-14.66699,8 -32.33301,8 -47,0l1,151zm45.75,-151.25l56.25,-46.75l0,144.01219l-56,51.98782m-47.25,-151.25002l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_6"/>
|
||||
<path fill="#efe8b8" stroke="#d6c47c" stroke-linecap="round" d="m95.75,49.51801l56.56,-46.26801c12.72998,8.25 25.71002,7 46.44,0.75l-56.03998,47.239l-22.72003,25.011l-24.23999,-26.73199z" stroke-width="7" id="svg_10"/>
|
||||
<path fill="#336393" stroke="#3f3f3f" d="m96.75,200.29445c14.33301,7 30.66699,7 46,0l0,-149.04445c-14.66699,8 -32.33301,8 -47,0l1,149.04445zm45.75,-149.29445l56.25,-46.75l0,148.04445l-56,48m-47.25,-151.29445l57.25,-46.5" stroke-width="7" stroke-linecap="round" id="svg_11"/>
|
||||
</g>
|
||||
</svg></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 839 B After Width: | Height: | Size: 839 B |
17
src/editor/images/netlify-dark.svg
Normal file
17
src/editor/images/netlify-dark.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
@@ -74,19 +74,20 @@
|
||||
<div id="sidepanel_handle" title="Drag left/right to resize side panel [X]">L a y e r s
|
||||
</div>
|
||||
</div>
|
||||
<se-menu id="main_button" label="SVG-Edit" src="./images/logo.svg">
|
||||
<se-menu id="main_button" label="SVG-Edit" src="./images/logo.svg" alt="logo">
|
||||
<!-- File-like buttons: New, Save, Source -->
|
||||
<se-menu-item id="tool_clear" label="New Image" shortcut="N" src="./images/new.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_open" label="Open SVG" src="./images/open.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_import" label="Import Image" src="./images/importImg.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_save" label="Save Image" shortcut="S" src="./images/saveImg.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_imagelib" label="Image library" src="./images/library.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_export" label="Export" src="./images/export.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_docprops" label="Document Properties" shortcut="D" src="./images/docprop.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_editor_prefs" label="Editor Preferences" src="./images/editPref.svg"></se-menu-item>
|
||||
<se-menu-item id="tool_editor_homepage" label="SVG-Edit Home Page" src="./images/svg-edit-home.svg"></se-menu-item>
|
||||
<div style="width:50%;margin:auto;">
|
||||
<a href="https://www.netlify.com">
|
||||
<img style="height:25px;" src="https://www.netlify.com/img/global/badges/netlify-dark.svg"
|
||||
<img style="height:25px;" src="./images/netlify-dark.svg"
|
||||
alt="Deploys by Netlify" />
|
||||
</a>
|
||||
</div>
|
||||
@@ -126,15 +127,23 @@
|
||||
title="Change rotation angle"></se-spin-input>
|
||||
<se-spin-input size="2" id="blur" min=0 max=100 step=5 src="./images/blur.svg"
|
||||
title="Change gaussian blur value"></se-spin-input>
|
||||
<se-list>
|
||||
<se-list-item id="tool_posleft">Align Left</se-list-item>
|
||||
<se-list-item id="tool_poscenter">Align Center</se-list-item>
|
||||
<se-list-item id="tool_posright">Align Right</se-list-item>
|
||||
<se-list-item id="tool_postop">Align Top</se-list-item>
|
||||
<se-list-item id="tool_posmiddle">Align Middle</se-list-item>
|
||||
<se-list-item id="tool_posbottom">Align Bottom</se-list-item>
|
||||
</se-list>
|
||||
<div class="dropdown toolset" id="tool_position" title="Align Element to Page">
|
||||
<div id="cur_position" class="icon_label"></div>
|
||||
<button></button>
|
||||
</div>
|
||||
<div id="xy_panel" class="toolset">
|
||||
<se-input id="selected_x" data-attr:="x" size="4" type="text" label="x:" title="Change X coordinate">
|
||||
</se-input>
|
||||
<se-input id="selected_y" data-attr="y" size="4" type="text" label="y:" title="Change Y coordinate">
|
||||
</se-input>
|
||||
<se-spin-input id="selected_x" data-attr:="x" size="4" type="text" label="x:" title="Change X coordinate">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="selected_y" data-attr="y" size="4" type="text" label="y:" title="Change Y coordinate">
|
||||
</se-spin-input>
|
||||
</div>
|
||||
</div> <!-- selected_panel -->
|
||||
<!-- Buttons when multiple elements are selected -->
|
||||
@@ -153,33 +162,30 @@
|
||||
<se-button id="tool_align_top" title="Align Top" src="./images/align_top.svg"></se-button>
|
||||
<se-button id="tool_align_middle" title="Align Middle" src="./images/align_middle.svg"></se-button>
|
||||
<se-button id="tool_align_bottom" title="Align Bottom" src="./images/align_bottom.svg"></se-button>
|
||||
<label id="tool_align_relative">
|
||||
<span id="relativeToLabel">relative to:</span>
|
||||
<select id="align_relative_to" title="Align relative to ...">
|
||||
<option id="selected_objects" value="selected">selected objects</option>
|
||||
<option id="largest_object" value="largest">largest object</option>
|
||||
<option id="smallest_object" value="smallest">smallest object</option>
|
||||
<option id="page" value="page">page</option>
|
||||
</select>
|
||||
</label>
|
||||
<se-list id="tool_align_relative" label="relative to:">
|
||||
<se-list-item id="selected_objects" value="selected">selected objects</se-list-item>
|
||||
<se-list-item id="largest_object" value="largest">largest object</se-list-item>
|
||||
<se-list-item id="smallest_object" value="smallest">smallest object</se-list-item>
|
||||
<se-list-item id="page" value="page">page</se-list-item>
|
||||
</se-list>
|
||||
<div class="tool_sep"></div>
|
||||
</div> <!-- multiselected_panel -->
|
||||
<div id="rect_panel">
|
||||
<div class="toolset">
|
||||
<se-input id="rect_width" data-attr="width" size="4" src="./images/width.svg"
|
||||
title="Change rectangle width"></se-input>
|
||||
<se-input id="rect_height" data-attr="height" size="4" src="./images/height.svg"
|
||||
title="Change rectangle height"></se-input>
|
||||
<se-spin-input id="rect_width" data-attr="width" size="4" src="./images/width.svg"
|
||||
title="Change rectangle width"></se-spin-input>
|
||||
<se-spin-input id="rect_height" data-attr="height" size="4" src="./images/height.svg"
|
||||
title="Change rectangle height"></se-spin-input>
|
||||
</div>
|
||||
<se-spin-input id="rect_rx" min=0 max=1000 step=1 size="3" title="Change Rectangle Corner Radius"
|
||||
data-attr="Corner Radius" src="./images/c_radius.svg"></se-spin-input>
|
||||
</div> <!-- rect_panel -->
|
||||
<div id="image_panel">
|
||||
<div class="toolset">
|
||||
<se-input id="image_width" data-attr="width" size="4" type="text" src="./images/width.svg"
|
||||
title="Change image width"></se-input>
|
||||
<se-input id="image_height" data-attr="height" size="4" type="text" src="./images/height.svg"
|
||||
title="Change image height"></se-input>
|
||||
<se-spin-input id="image_width" data-attr="width" size="4" type="text" src="./images/width.svg"
|
||||
title="Change image width"></se-spin-input>
|
||||
<se-spin-input id="image_height" data-attr="height" size="4" type="text" src="./images/height.svg"
|
||||
title="Change image height"></se-spin-input>
|
||||
</div>
|
||||
<div class="toolset">
|
||||
<label id="tool_image_url">url:
|
||||
@@ -194,37 +200,35 @@
|
||||
</div> <!-- image_panel -->
|
||||
<div id="circle_panel">
|
||||
<div class="toolset">
|
||||
<se-input id="circle_cx" data-attr="cx" size="4" label="cx:"></se-input>
|
||||
<se-input id="circle_cy" data-attr="cy" size="4" label="cy:"></se-input>
|
||||
<se-spin-input id="circle_cx" data-attr="cx" size="4" label="cx:"></se-spin-input>
|
||||
<se-spin-input id="circle_cy" data-attr="cy" size="4" label="cy:"></se-spin-input>
|
||||
</div>
|
||||
<div class="toolset">
|
||||
<se-input id="circle_r" data-attr="r" size="4" label="r:"></se-input>
|
||||
<se-spin-input id="circle_r" data-attr="r" size="4" label="r:"></se-spin-input>
|
||||
</div>
|
||||
</div> <!-- circle_panel -->
|
||||
<div id="ellipse_panel">
|
||||
<div class="toolset">
|
||||
<se-input id="ellipse_cx" data-attr="cx" size="4" title="Change ellipse's cx coordinate" label="cx:">
|
||||
</se-input>
|
||||
<se-input id="ellipse_cy" data-attr="cy" size="4" title="Change ellipse's cy coordinate" label="cy:">
|
||||
</se-input>
|
||||
<se-spin-input id="ellipse_cx" data-attr="cx" size="4" title="Change ellipse's cx coordinate" label="cx:">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="ellipse_cy" data-attr="cy" size="4" title="Change ellipse's cy coordinate" label="cy:">
|
||||
</se-spin-input>
|
||||
</div>
|
||||
<div class="toolset">
|
||||
<se-input id="ellipse_rx" data-attr="rx" size="4" title="Change ellipse's x radius" label="rx:"></se-input>
|
||||
<se-input id="ellipse_ry" data-attr="ry" size="4" title="Change ellipse's y radius" label="ry:"></se-input>
|
||||
<se-spin-input id="ellipse_rx" data-attr="rx" size="4" title="Change ellipse's x radius" label="rx:"></se-spin-input>
|
||||
<se-spin-input id="ellipse_ry" data-attr="ry" size="4" title="Change ellipse's y radius" label="ry:"></se-spin-input>
|
||||
</div>
|
||||
</div> <!-- ellipse_panel -->
|
||||
<div id="line_panel">
|
||||
<div class="toolset">
|
||||
<se-input id="line_x1" data-attr="x1" size="4" title="Change line's starting x coordinate" label="x1:">
|
||||
</se-input>
|
||||
<se-input id="line_y1" data-attr="y1" size="4" title="Change line's starting y coordinate" label="y1:">
|
||||
</se-input>
|
||||
</div>
|
||||
<div class="toolset">
|
||||
<se-input id="line_x2" data-attr="x2" size="4" title="Change line's ending x coordinate" label="x2:">
|
||||
</se-input>
|
||||
<se-input id="line_y2" data-attr="y2" size="4" title="Change line's ending y coordinate" label="y2:">
|
||||
</se-input>
|
||||
<se-spin-input id="line_x1" data-attr="x1" size="4" title="Change line's starting x coordinate" label="x1:">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="line_y1" data-attr="y1" size="4" title="Change line's starting y coordinate" label="y1:">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="line_x2" data-attr="x2" size="4" title="Change line's ending x coordinate" label="x2:">
|
||||
</se-spin-input>
|
||||
<se-spin-input id="line_y2" data-attr="y2" size="4" title="Change line's ending y coordinate" label="y2:">
|
||||
</se-spin-input>
|
||||
</div>
|
||||
</div> <!-- line_panel -->
|
||||
<div id="text_panel">
|
||||
@@ -235,25 +239,16 @@
|
||||
<se-button id="tool_text_anchor_middle" title="Align the text from middle" src="./images/anchor_middle.svg"></se-button>
|
||||
<se-button id="tool_text_anchor_end" title="Align the text from end" src="./images/anchor_end.svg"></se-button>
|
||||
</div>
|
||||
<div class="toolset" id="tool_font_family">
|
||||
<label>
|
||||
<!-- Font family -->
|
||||
<input id="font_family" type="text" title="Change Font Family" size="12" />
|
||||
</label>
|
||||
<div id="font_family_dropdown" class="dropdown">
|
||||
<button></button>
|
||||
<ul>
|
||||
<li style="font-family:serif">Serif</li>
|
||||
<li style="font-family:sans-serif">Sans-serif</li>
|
||||
<li style="font-family:cursive">Cursive</li>
|
||||
<li style="font-family:fantasy">Fantasy</li>
|
||||
<li style="font-family:monospace">Monospace</li>
|
||||
<li style="font-family:courier">Courier</li>
|
||||
<li style="font-family:helvetica">Helvetica</li>
|
||||
<li style="font-family:times">Times</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<se-list id="tool_font_family" label="Font:">
|
||||
<se-list-item value="Sans-serif"> <div style="font-family:serif">Sans-serif</div></se-list-item>
|
||||
<se-list-item value="Serif"> <div style="font-family:serif">Serif</div></se-list-item>
|
||||
<se-list-item value="Cursive"> <div style="font-family:serif">Cursive</div></se-list-item>
|
||||
<se-list-item value="Fantasy"> <div style="font-family:serif">Fantasy</div></se-list-item>
|
||||
<se-list-item value="Monospace"> <div style="font-family:serif">Monospace</div></se-list-item>
|
||||
<se-list-item value="Courier"> <div style="font-family:serif">Courier</div></se-list-item>
|
||||
<se-list-item value="Helvetica"> <div style="font-family:serif">Helvetica</div></se-list-item>
|
||||
<se-list-item value="Times"> <div style="font-family:serif">Times</div></se-list-item>
|
||||
</se-list>
|
||||
<se-spin-input size="2" id="font_size" min=1 max=1000 step=1 title="Change Font Size"
|
||||
src="./images/fontsize.svg"></se-spin-input>
|
||||
<!-- Not visible, but still used -->
|
||||
@@ -285,8 +280,8 @@
|
||||
<div class="tool_sep"></div>
|
||||
<se-button id="tool_node_link" title="Link Control Points" src="./images/tool_node_link.svg" pressed></se-button>
|
||||
<div class="tool_sep"></div>
|
||||
<se-input id="path_node_x" data-attr="x" size="4" title="Change node's x coordinate" label="x:"></se-input>
|
||||
<se-input id="path_node_y" data-attr="y" size="4" title="Change node's y coordinate" label="y:"></se-input>
|
||||
<se-spin-input id="path_node_x" data-attr="x" size="4" title="Change node's x coordinate" label="x:"></se-spin-input>
|
||||
<se-spin-input id="path_node_y" data-attr="y" size="4" title="Change node's y coordinate" label="y:"></se-spin-input>
|
||||
<select id="seg_type" title="Change Segment type">
|
||||
<option id="straight_segments" selected="selected" value="4">Straight</option>
|
||||
<option id="curve_segments" value="6">Curve</option>
|
||||
@@ -331,7 +326,7 @@
|
||||
</div> <!-- tools_left -->
|
||||
<div id="tools_bottom">
|
||||
<!-- Zoom buttons -->
|
||||
<se-dropdown id="zoom" src="./images/zoom.svg" title="Change zoom level" inputsize="40px">
|
||||
<se-zoom id="zoom" src="./images/zoom.svg" title="Change zoom level" inputsize="40px">
|
||||
<div value="1000">1000</div>
|
||||
<div value="400">400</div>
|
||||
<div value="200">200</div>
|
||||
@@ -342,66 +337,37 @@
|
||||
<div value="selection">Fit to selection</div>
|
||||
<div value="layer">Fit to layer content</div>
|
||||
<div value="content">Fit to all content</div>
|
||||
</se-dropdown>
|
||||
</se-zoom>
|
||||
<se-colorpicker id="fill_color" src="./images/fill.svg" title="Change fill color" type="fill"></se-colorpicker>
|
||||
<se-colorpicker id="stroke_color" src="./images/stroke.svg" title="Change stroke color" type="stroke"></se-colorpicker>
|
||||
<se-spin-input id="stroke_width" min=0 max=99 step=1 title="Change stroke width by 1" label=""></se-spin-input>
|
||||
<label class="stroke_tool">
|
||||
<select id="stroke_style" title="Change stroke dash style">
|
||||
<option selected="selected" value="none">—</option>
|
||||
<option value="2,2">...</option>
|
||||
<option value="5,5">- -</option>
|
||||
<option value="5,2,2,2">- .</option>
|
||||
<option value="5,2,2,2,2,2">- ..</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="stroke_tool dropdown" id="stroke_linejoin">
|
||||
<div id="cur_linejoin" title="Linejoin: Miter"></div>
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="stroke_tool dropdown" id="stroke_linecap">
|
||||
<div id="cur_linecap" title="Linecap: Butt"></div>
|
||||
<button></button>
|
||||
</div>
|
||||
<div id="tool_opacity">
|
||||
<se-spin-input size="3" id="group_opacity" min=0 max=100 step=5 title="Change selected item opacity" label=""></se-spin-input>
|
||||
<div id="opacity_dropdown" class="dropdown">
|
||||
<button></button>
|
||||
<ul>
|
||||
<li>0%</li>
|
||||
<li>25%</li>
|
||||
<li>50%</li>
|
||||
<li>75%</li>
|
||||
<li>100%</li>
|
||||
<li class="special">
|
||||
<div id="opac_slider"></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div> <!-- tool_opacity -->
|
||||
<se-list id="stroke_style" title="Change stroke dash style" label="">
|
||||
<se-list-item value="none">—</se-list-item>
|
||||
<se-list-item value="2,2">...</se-list-item>
|
||||
<se-list-item value="5,5">- -</se-list-item>
|
||||
<se-list-item value="5,2,2,2">- .</se-list-item>
|
||||
<se-list-item value="5,2,2,2,2,2">- ..</se-list-item>
|
||||
</se-list>
|
||||
<se-list id="stroke_linejoin" title="Linejoin: Miter" label="">
|
||||
<se-list-item id="linejoin_miter"><se-button size="small" title="Linejoin: Miter" src="./images/linejoin_miter.svg"></se-button></se-list-item>
|
||||
<se-list-item id="linejoin_round"><se-button size="small" title="Linejoin: Round" src="./images/linejoin_round.svg"></se-button></se-list-item>
|
||||
<se-list-item id="linejoin_bevel"><se-button size="small" title="Linejoin: Bevel" src="./images/linejoin_bevel.svg"></se-button></se-list-item>
|
||||
</se-list>
|
||||
<se-list id="stroke_linecap" title="Linecap: Butt" label="">
|
||||
<se-list-item id="linecap_butt"><se-button size="small" title="Linecap: Butt" src="./images/linecap_butt.svg"></se-button></se-list-item>
|
||||
<se-list-item id="linecap_square"><se-button size="small" title="Linecap: Square" src="./images/linecap_square.svg"></se-button></se-list-item>
|
||||
<se-list-item id="linecap_round"><se-button size="small" title="Linecap: Round" src="./images/linecap_round.svg"></se-button></se-list-item>
|
||||
</se-list>
|
||||
<se-list id="opacity_dropdown" label="">
|
||||
<se-list-item>0%</se-list-item>
|
||||
<se-list-item>25%</se-list-item>
|
||||
<se-list-item>50%</se-list-item>
|
||||
<se-list-item>75%</se-list-item>
|
||||
<se-list-item>100%</se-list-item>
|
||||
</se-list>
|
||||
<se-spin-input size="3" id="group_opacity" min=0 max=100 step=5 title="Change selected item opacity" label=""></se-spin-input>
|
||||
<se-palette id="palette"></se-palette>
|
||||
</div> <!-- tools_bottom -->
|
||||
<div id="option_lists" class="dropdown">
|
||||
<ul id="linejoin_opts">
|
||||
<li class="tool_button current" id="linejoin_miter" title="Linejoin: Miter"></li>
|
||||
<li class="tool_button" id="linejoin_round" title="Linejoin: Round"></li>
|
||||
<li class="tool_button" id="linejoin_bevel" title="Linejoin: Bevel"></li>
|
||||
</ul>
|
||||
<ul id="linecap_opts">
|
||||
<li class="tool_button current" id="linecap_butt" title="Linecap: Butt"></li>
|
||||
<li class="tool_button" id="linecap_square" title="Linecap: Square"></li>
|
||||
<li class="tool_button" id="linecap_round" title="Linecap: Round"></li>
|
||||
</ul>
|
||||
<ul id="position_opts" class="optcols3">
|
||||
<li class="push_button" id="tool_posleft" title="Align Left"></li>
|
||||
<li class="push_button" id="tool_poscenter" title="Align Center"></li>
|
||||
<li class="push_button" id="tool_posright" title="Align Right"></li>
|
||||
<li class="push_button" id="tool_postop" title="Align Top"></li>
|
||||
<li class="push_button" id="tool_posmiddle" title="Align Middle"></li>
|
||||
<li class="push_button" id="tool_posbottom" title="Align Bottom"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dialog_box">
|
||||
<div class="overlay"></div>
|
||||
<div id="dialog_container">
|
||||
|
||||
196
src/editor/panels/BottomPanelHandlers.js
Normal file
196
src/editor/panels/BottomPanelHandlers.js
Normal file
@@ -0,0 +1,196 @@
|
||||
/* 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.svgCanvas;
|
||||
}
|
||||
/**
|
||||
* @type {module}
|
||||
*/
|
||||
get selectedElement () {
|
||||
return this.editor.selectedElement;
|
||||
}
|
||||
/**
|
||||
* @type {module}
|
||||
*/
|
||||
get multiselected () {
|
||||
return this.editor.multiselected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {module}
|
||||
*/
|
||||
changeStrokeWidth (e) {
|
||||
let val = e.target.value;
|
||||
if (val === 0 && this.selectedElement && ['line', 'polyline'].includes(this.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.bind(this)(e.detail.value));
|
||||
$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));
|
||||
const {curConfig} = this.editor.configObj;
|
||||
$id('fill_color').setPaint(new $.jGraduate.Paint({alpha: 100, solidColor: curConfig.initFill.color}));
|
||||
$id('stroke_color').setPaint(new $.jGraduate.Paint({alpha: 100, solidColor: curConfig.initStroke.color}));
|
||||
}
|
||||
}
|
||||
|
||||
export default BottomPanelHandlers;
|
||||
@@ -1,43 +1,162 @@
|
||||
/* 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.svgCanvas;
|
||||
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.configObj.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}
|
||||
*/
|
||||
async newLayer () {
|
||||
newLayer () {
|
||||
let uniqName;
|
||||
let i = this.svgCanvas.getCurrentDrawing().getNumLayers();
|
||||
do {
|
||||
uniqName = this.uiStrings.layers.layer + ' ' + (++i);
|
||||
} while (this.svgCanvas.getCurrentDrawing().hasLayer(uniqName));
|
||||
|
||||
const newName = await $.prompt(this.uiStrings.notification.enterUniqueLayerName, uniqName);
|
||||
const newName = prompt(this.uiStrings.notification.enterUniqueLayerName, uniqName);
|
||||
if (!newName) { return; }
|
||||
if (this.svgCanvas.getCurrentDrawing().hasLayer(newName)) {
|
||||
/* await */ $.alert(this.uiStrings.notification.dupeLayerName);
|
||||
alert(this.uiStrings.notification.dupeLayerName);
|
||||
return;
|
||||
}
|
||||
this.svgCanvas.createLayer(newName);
|
||||
@@ -63,15 +182,15 @@ class LayersPanel {
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
* @returns {void}
|
||||
*/
|
||||
async cloneLayer () {
|
||||
cloneLayer () {
|
||||
const name = this.svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy';
|
||||
|
||||
const newName = await $.prompt(this.uiStrings.notification.enterUniqueLayerName, name);
|
||||
const newName = prompt(this.uiStrings.notification.enterUniqueLayerName, name);
|
||||
if (!newName) { return; }
|
||||
if (this.svgCanvas.getCurrentDrawing().hasLayer(newName)) {
|
||||
/* await */ $.alert(this.uiStrings.notification.dupeLayerName);
|
||||
alert(this.uiStrings.notification.dupeLayerName);
|
||||
return;
|
||||
}
|
||||
this.svgCanvas.cloneLayer(newName);
|
||||
@@ -110,13 +229,13 @@ class LayersPanel {
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
async layerRename () {
|
||||
layerRename () {
|
||||
// const curIndex = $('#layerlist tr.layersel').prevAll().length; // Currently unused
|
||||
const oldName = $('#layerlist tr.layersel td.layername').text();
|
||||
const newName = await $.prompt(this.uiStrings.notification.enterNewLayerName, '');
|
||||
const newName = prompt(this.uiStrings.notification.enterNewLayerName, '');
|
||||
if (!newName) { return; }
|
||||
if (oldName === newName || this.svgCanvas.getCurrentDrawing().hasLayer(newName)) {
|
||||
/* await */ $.alert(this.uiStrings.notification.layerHasThatName);
|
||||
alert(this.uiStrings.notification.layerHasThatName);
|
||||
return;
|
||||
}
|
||||
this.svgCanvas.renameCurrentLayer(newName);
|
||||
216
src/editor/panels/LeftPanelHandlers.js
Normal file
216
src/editor/panels/LeftPanelHandlers.js
Normal file
@@ -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.svgCanvas;
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
632
src/editor/panels/TopPanelHandlers.js
Normal file
632
src/editor/panels/TopPanelHandlers.js
Normal file
@@ -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.svgCanvas;
|
||||
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.configObj.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.svgCanvas.undoMgr.getUndoStackSize() === 0);
|
||||
$id('tool_redo').disabled = (this.svgCanvas.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 = */ $('<style id="wireframe_rules"></style>').appendTo('head');
|
||||
} else {
|
||||
wfRules.empty();
|
||||
}
|
||||
this.editor.updateWireFrame();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clickUndo () {
|
||||
const {undoMgr} = this.editor.svgCanvas;
|
||||
if (undoMgr.getUndoStackSize() > 0) {
|
||||
undoMgr.undo();
|
||||
this.editor.layersPanel.populateLayers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clickRedo () {
|
||||
const {undoMgr} = this.editor.svgCanvas;
|
||||
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.editor.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.editor.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;
|
||||
@@ -379,25 +379,6 @@ hr {
|
||||
|
||||
/*—————————————————————————————*/
|
||||
|
||||
.tool_button:hover,
|
||||
.push_button:hover,
|
||||
.buttonup:hover,
|
||||
.buttondown,
|
||||
.tool_button_current,
|
||||
.push_button_pressed
|
||||
{
|
||||
background-color: #ffc !important;
|
||||
}
|
||||
|
||||
.tool_button_current,
|
||||
.push_button_pressed,
|
||||
.buttondown {
|
||||
background-color: #f4e284 !important;
|
||||
-webkit-box-shadow: inset 1px 1px 2px rgba(0,0,0,0.4), 1px 1px 0 white !important;
|
||||
-moz-box-shadow: inset 1px 1px 2px rgba(0,0,0,0.4), 1px 1px 0 white !important;
|
||||
box-shadow: inset 1px 1px 2px rgba(0,0,0,0.4), 1px 1px 0 white !important;
|
||||
}
|
||||
|
||||
#tools_top {
|
||||
position: absolute;
|
||||
left: 108px;
|
||||
@@ -405,7 +386,6 @@ hr {
|
||||
top: 2px;
|
||||
height: 40px;
|
||||
border-bottom: none;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#tools_top .tool_sep {
|
||||
@@ -515,12 +495,6 @@ input[type=text] {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#tools_left .tool_button,
|
||||
#tools_left .tool_button_current {
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
}
|
||||
@@ -592,21 +566,6 @@ input[type=text] {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tool_button,
|
||||
.push_button,
|
||||
.tool_button_current,
|
||||
.push_button_pressed
|
||||
{
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin: 2px 2px 4px 2px;
|
||||
padding: 3px;
|
||||
box-shadow: inset 1px 1px 2px white, 1px 1px 1px rgba(0,0,0,0.3);
|
||||
background-color: #E8E8E8;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#main_menu li#tool_open, #main_menu li#tool_import {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -683,10 +642,6 @@ input[type=text] {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.dropdown li.tool_button {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
#stroke_expand {
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
* @license MIT
|
||||
* @copyright 2011 Jeff Schiller
|
||||
*/
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
import {
|
||||
snapToGrid, assignAttributes, getBBox, getRefElem, findDefs
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
transformPoint, transformListToTransform, matrixMultiply, transformBox
|
||||
} from '../common/math.js';
|
||||
import {getTransformList} from '../common/svgtransformlist.js';
|
||||
} from './math.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* globals jQuery */
|
||||
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import {isWebkit} from '../common/browser.js';
|
||||
import {convertPath} from './path.js';
|
||||
import {preventClickDefault} from '../common/utilities.js';
|
||||
import {preventClickDefault} from './utilities.js';
|
||||
|
||||
// Constants
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* @module jQueryPluginDBox
|
||||
*/
|
||||
/**
|
||||
* @param {external:jQuery} $
|
||||
* @param {PlainObject} [strings]
|
||||
* @param {PlainObject} [strings.ok]
|
||||
* @param {PlainObject} [strings.cancel]
|
||||
* @returns {external:jQuery}
|
||||
*/
|
||||
export default function jQueryPluginDBox ($, {
|
||||
ok: okString = 'Ok',
|
||||
cancel: cancelString = 'Cancel'
|
||||
} = {}) {
|
||||
// This sets up alternative dialog boxes. They mostly work the same way as
|
||||
// their UI counterparts, expect instead of returning the result, a callback
|
||||
// needs to be included that returns the result as its first parameter.
|
||||
// In the future we may want to add additional types of dialog boxes, since
|
||||
// they should be easy to handle this way.
|
||||
$('#dialog_container').draggable({
|
||||
cancel: '#dialog_content, #dialog_buttons *',
|
||||
containment: 'window'
|
||||
}).css('position', 'absolute');
|
||||
|
||||
const box = $('#dialog_box'),
|
||||
btnHolder = $('#dialog_buttons'),
|
||||
dialogContent = $('#dialog_content');
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} module:jQueryPluginDBox.PromiseResultObject
|
||||
* @property {string|true} response
|
||||
* @property {boolean} checked
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves to `false` (if cancelled), for prompts and selects
|
||||
* without checkboxes, it resolves to the value of the form control. For other
|
||||
* types without checkboxes, it resolves to `true`. For checkboxes, it resolves
|
||||
* to an object with the `response` key containing the same value as the previous
|
||||
* mentioned (string or `true`) and a `checked` (boolean) property.
|
||||
* @typedef {Promise<boolean|string|module:jQueryPluginDBox.PromiseResultObject>} module:jQueryPluginDBox.ResultPromise
|
||||
*/
|
||||
/**
|
||||
* @typedef {PlainObject} module:jQueryPluginDBox.SelectOption
|
||||
* @property {string} text
|
||||
* @property {string} value
|
||||
*/
|
||||
/**
|
||||
* @typedef {PlainObject} module:jQueryPluginDBox.CheckboxInfo
|
||||
* @property {string} label Label for the checkbox
|
||||
* @property {string} value Value of the checkbox
|
||||
* @property {string} tooltip Tooltip on the checkbox label
|
||||
* @property {boolean} checked Whether the checkbox is checked by default
|
||||
*/
|
||||
/**
|
||||
* Triggered upon a change of value for the select pull-down.
|
||||
* @callback module:jQueryPluginDBox.SelectChangeListener
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* Creates a dialog of the specified type with a given message
|
||||
* and any defaults and type-specific metadata. Returns a `Promise`
|
||||
* which resolves differently depending on whether the dialog
|
||||
* was cancelled or okayed (with the response and any checked state).
|
||||
* @param {"alert"|"prompt"|"select"|"process"} type
|
||||
* @param {string} msg
|
||||
* @param {string} [defaultVal]
|
||||
* @param {module:jQueryPluginDBox.SelectOption[]} [opts]
|
||||
* @param {module:jQueryPluginDBox.SelectChangeListener} [changeListener]
|
||||
* @param {module:jQueryPluginDBox.CheckboxInfo} [checkbox]
|
||||
* @returns {jQueryPluginDBox.ResultPromise}
|
||||
*/
|
||||
function dbox (type, msg, defaultVal, opts, changeListener, checkbox) {
|
||||
dialogContent.html('<p>' + msg.replace(/\n/g, '</p><p>') + '</p>')
|
||||
.toggleClass('prompt', (type === 'prompt'));
|
||||
btnHolder.empty();
|
||||
|
||||
const ok = $('<input type="button" data-ok="" value="' + okString + '">').appendTo(btnHolder);
|
||||
|
||||
return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new
|
||||
if (type !== 'alert') {
|
||||
$('<input type="button" value="' + cancelString + '">')
|
||||
.appendTo(btnHolder)
|
||||
.click(function () {
|
||||
box.hide();
|
||||
resolve(false);
|
||||
});
|
||||
}
|
||||
|
||||
let ctrl, chkbx;
|
||||
if (type === 'prompt') {
|
||||
ctrl = $('<input type="text">').prependTo(btnHolder);
|
||||
ctrl.val(defaultVal || '');
|
||||
ctrl.bind('keydown', 'return', function () { ok.click(); });
|
||||
} else if (type === 'select') {
|
||||
const div = $('<div style="text-align:center;">');
|
||||
ctrl = $(`<select aria-label="${msg}">`).appendTo(div);
|
||||
if (checkbox) {
|
||||
const label = $('<label>').text(checkbox.label);
|
||||
chkbx = $('<input type="checkbox">').appendTo(label);
|
||||
chkbx.val(checkbox.value);
|
||||
if (checkbox.tooltip) {
|
||||
label.attr('title', checkbox.tooltip);
|
||||
}
|
||||
chkbx.prop('checked', Boolean(checkbox.checked));
|
||||
div.append($('<div>').append(label));
|
||||
}
|
||||
$.each(opts || [], function (opt, val) {
|
||||
if (typeof val === 'object') {
|
||||
ctrl.append($('<option>').val(val.value).html(val.text));
|
||||
} else {
|
||||
ctrl.append($('<option>').html(val));
|
||||
}
|
||||
});
|
||||
dialogContent.append(div);
|
||||
if (defaultVal) {
|
||||
ctrl.val(defaultVal);
|
||||
}
|
||||
if (changeListener) {
|
||||
ctrl.bind('change', 'return', changeListener);
|
||||
}
|
||||
ctrl.bind('keydown', 'return', function () { ok.click(); });
|
||||
} else if (type === 'process') {
|
||||
ok.hide();
|
||||
}
|
||||
|
||||
box.show();
|
||||
|
||||
ok.click(function () {
|
||||
box.hide();
|
||||
const response = (type === 'prompt' || type === 'select') ? ctrl.val() : true;
|
||||
if (chkbx) {
|
||||
resolve({response, checked: chkbx.prop('checked')});
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
}).focus();
|
||||
|
||||
if (type === 'prompt' || type === 'select') {
|
||||
ctrl.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} msg Message to alert
|
||||
* @returns {jQueryPluginDBox.ResultPromise}
|
||||
*/
|
||||
$.alert = function (msg) {
|
||||
return dbox('alert', msg);
|
||||
};
|
||||
/**
|
||||
* @param {string} msg Message for which to ask confirmation
|
||||
* @returns {jQueryPluginDBox.ResultPromise}
|
||||
*/
|
||||
$.confirm = function (msg) {
|
||||
return dbox('confirm', msg);
|
||||
};
|
||||
/**
|
||||
* @param {string} msg Message to indicate upon cancelable indicator
|
||||
* @returns {jQueryPluginDBox.ResultPromise}
|
||||
*/
|
||||
$.process_cancel = function (msg) {
|
||||
return dbox('process', msg);
|
||||
};
|
||||
/**
|
||||
* @param {string} msg Message to accompany the prompt
|
||||
* @param {string} [defaultText=""] The default text to show for the prompt
|
||||
* @returns {jQueryPluginDBox.ResultPromise}
|
||||
*/
|
||||
$.prompt = function (msg, defaultText = '') {
|
||||
return dbox('prompt', msg, defaultText);
|
||||
};
|
||||
$.select = function (msg, opts, changeListener, txt, checkbox) {
|
||||
return dbox('select', msg, txt, opts, changeListener, checkbox);
|
||||
};
|
||||
return $;
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import {NS} from '../common/namespaces.js';
|
||||
import {isOpera} from '../common/browser.js';
|
||||
import {
|
||||
toXml, getElem
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
copyElem as utilCopyElem
|
||||
} from './copy-elem.js';
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
*/
|
||||
|
||||
import * as hstry from './history.js';
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {
|
||||
getVisibleElements, getStrokedBBoxDefaultVisible, findDefs,
|
||||
walkTree, isNullish, getHref, setHref, getElem
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
convertToNum
|
||||
} from '../common/units.js';
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
* @license MIT
|
||||
* @copyright 2011 Jeff Schiller
|
||||
*/
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute
|
||||
import {
|
||||
assignAttributes, cleanupElement, getElem, getRotationAngle, snapToGrid, walkTree,
|
||||
getBBox as utilsGetBBox, isNullish, preventClickDefault, setHref
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
convertAttrs
|
||||
} from '../common/units.js';
|
||||
import {
|
||||
transformPoint, hasMatrixTransform, getMatrix, snapToAngle
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
getTransformList
|
||||
} from '../common/svgtransformlist.js';
|
||||
} from './svgtransformlist.js';
|
||||
import {
|
||||
supportsNonScalingStroke, isWebkit
|
||||
} from '../common/browser.js';
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
* @copyright 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
import {getHref, setHref, getRotationAngle, isNullish} from '../common/utilities.js';
|
||||
import {removeElementFromListMap} from '../common/svgtransformlist.js';
|
||||
import {getHref, setHref, getRotationAngle, isNullish} from './utilities.js';
|
||||
import {removeElementFromListMap} from './svgtransformlist.js';
|
||||
|
||||
/**
|
||||
* Group: Undo/Redo history management.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
import {getElem, assignAttributes, cleanupElement} from '../common/utilities.js';
|
||||
import {getElem, assignAttributes, cleanupElement} from './utilities.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
|
||||
let jsonContext_ = null;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {toXml, walkTree, isNullish} from '../common/utilities.js';
|
||||
import {toXml, walkTree, isNullish} from './utilities.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* @property {Float} y
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
|
||||
// Constants
|
||||
@@ -1,9 +1,9 @@
|
||||
/* globals jQuery */
|
||||
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import {
|
||||
getStrokedBBoxDefaultVisible
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import * as hstry from './history.js';
|
||||
// Constants
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {shortFloat} from '../common/units.js';
|
||||
import {getTransformList} from '../common/svgtransformlist.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
import {ChangeElementCommand, BatchCommand} from './history.js';
|
||||
import {
|
||||
transformPoint, snapToAngle, rectsIntersect,
|
||||
transformListToTransform
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
assignAttributes, getElem, getRotationAngle, snapToGrid, isNullish,
|
||||
getBBox as utilsGetBBox
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
isWebkit
|
||||
} from '../common/browser.js';
|
||||
|
||||
@@ -11,11 +11,11 @@ import {NS} from '../common/namespaces.js';
|
||||
import {ChangeElementCommand} from './history.js';
|
||||
import {
|
||||
transformPoint, getMatrix
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
assignAttributes, getRotationAngle, isNullish,
|
||||
getElem
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
supportsPathInsertItemBefore, supportsPathReplaceItem, isWebkit
|
||||
} from '../common/browser.js';
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
* @copyright 2011 Alexis Deveria, 2011 Jeff Schiller
|
||||
*/
|
||||
|
||||
import {getTransformList} from '../common/svgtransformlist.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
import {shortFloat} from '../common/units.js';
|
||||
import {transformPoint} from '../common/math.js';
|
||||
import {transformPoint} from './math.js';
|
||||
import {
|
||||
getRotationAngle, getBBox,
|
||||
getRefElem, findDefs, isNullish,
|
||||
getBBox as utilsGetBBox
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
init as pathMethodInit, insertItemBeforeMethod, ptObjToArrMethod, getGripPtMethod,
|
||||
getPointFromGripMethod, addPointGripMethod, getGripContainerMethod, addCtrlGripMethod,
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {convertToNum} from '../common/units.js';
|
||||
import {isWebkit} from '../common/browser.js';
|
||||
import {getTransformList} from '../common/svgtransformlist.js';
|
||||
import {getRotationAngle, getHref, getBBox, getRefElem, isNullish} from '../common/utilities.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
import {getRotationAngle, getHref, getBBox, getRefElem, isNullish} from './utilities.js';
|
||||
import {BatchCommand, ChangeElementCommand} from './history.js';
|
||||
import {remapElement} from './coords.js';
|
||||
import {
|
||||
isIdentity, matrixMultiply, transformPoint, transformListToTransform,
|
||||
hasMatrixTransform
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import {getReverseNS, NS} from '../common/namespaces.js';
|
||||
import {isGecko} from '../common/browser.js';
|
||||
import {getHref, setHref, getUrlFromAttr} from '../common/utilities.js';
|
||||
import {getHref, setHref, getUrlFromAttr} from './utilities.js';
|
||||
|
||||
const REVERSE_NS = getReverseNS();
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
*/
|
||||
|
||||
import {isTouch, isWebkit} from '../common/browser.js'; // , isOpera
|
||||
import {getRotationAngle, getBBox, getStrokedBBox, isNullish} from '../common/utilities.js';
|
||||
import {transformListToTransform, transformBox, transformPoint} from '../common/math.js';
|
||||
import {getTransformList} from '../common/svgtransformlist.js';
|
||||
import {getRotationAngle, getBBox, getStrokedBBox, isNullish} from './utilities.js';
|
||||
import {transformListToTransform, transformBox, transformPoint} from './math.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
*
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import * as hstry from './history.js';
|
||||
import * as pathModule from './path.js';
|
||||
import {
|
||||
isNullish, getStrokedBBoxDefaultVisible, setHref, getElem, getHref, getVisibleElements,
|
||||
findDefs, getRotationAngle, getRefElem, getBBox as utilsGetBBox, walkTreePost, assignAttributes
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
transformPoint, matrixMultiply, transformListToTransform
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
getTransformList
|
||||
} from '../common/svgtransformlist.js';
|
||||
} from './svgtransformlist.js';
|
||||
import {
|
||||
recalculateDimensions
|
||||
} from './recalculate.js';
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {
|
||||
isNullish, getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible
|
||||
} from '../common/utilities.js';
|
||||
import {transformPoint, transformListToTransform, rectsIntersect} from '../common/math.js';
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js';
|
||||
} from './utilities.js';
|
||||
import {transformPoint, transformListToTransform, rectsIntersect} from './math.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js';
|
||||
import {
|
||||
getTransformList
|
||||
} from '../common/svgtransformlist.js';
|
||||
} from './svgtransformlist.js';
|
||||
import * as hstry from './history.js';
|
||||
|
||||
const {BatchCommand} = hstry;
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
|
||||
import {jsPDF} from 'jspdf/dist/jspdf.es.min.js';
|
||||
import 'svg2pdf.js/dist/svg2pdf.es.js';
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js';
|
||||
import * as hstry from './history.js';
|
||||
import {
|
||||
text2xml, cleanupElement, findDefs, getHref, preventClickDefault,
|
||||
toXml, getStrokedBBoxDefaultVisible, encode64, createObjectURL,
|
||||
dataURLToObjectURL, walkTree, getBBox as utilsGetBBox
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
transformPoint, transformListToTransform
|
||||
} from '../common/math.js';
|
||||
import {resetListMap} from '../common/svgtransformlist.js';
|
||||
} from './math.js';
|
||||
import {resetListMap} from './svgtransformlist.js';
|
||||
import {
|
||||
convertUnit, shortFloat, convertToNum
|
||||
} from '../common/units.js';
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
import {Canvg as canvg} from 'canvg';
|
||||
import 'pathseg';
|
||||
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import jQueryPluginDBox from './dbox.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
|
||||
import * as pathModule from './path.js';
|
||||
import * as hstry from './history.js';
|
||||
@@ -78,12 +77,13 @@ import {
|
||||
findDefs, getHref, setHref, getRefElem, getRotationAngle, getPathBBox,
|
||||
preventClickDefault, walkTree, getBBoxOfElementAsPath, convertToPath, encode64, decode64,
|
||||
getVisibleElements, dropXMLInternalSubset, init as utilsInit,
|
||||
getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, isNullish
|
||||
} from '../common/utilities.js';
|
||||
getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, isNullish, blankPageObjectURL,
|
||||
$id, $qa, $qq
|
||||
} from './utilities.js';
|
||||
import {
|
||||
transformPoint, matrixMultiply, hasMatrixTransform, transformListToTransform,
|
||||
isIdentity, transformBox
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
convertToNum, getTypeMap, init as unitsInit
|
||||
} from '../common/units.js';
|
||||
@@ -97,7 +97,7 @@ import {
|
||||
} from '../common/browser.js'; // , supportsEditableText
|
||||
import {
|
||||
getTransformList, SVGTransformList as SVGEditTransformList
|
||||
} from '../common/svgtransformlist.js';
|
||||
} from './svgtransformlist.js';
|
||||
import {
|
||||
remapElement,
|
||||
init as coordsInit
|
||||
@@ -116,7 +116,7 @@ import {
|
||||
init as clearInit
|
||||
} from './clear.js';
|
||||
|
||||
let $ = jQueryPluginSVG(jQuery);
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
const {
|
||||
MoveElementCommand, InsertElementCommand, RemoveElementCommand,
|
||||
ChangeElementCommand, BatchCommand
|
||||
@@ -168,7 +168,7 @@ if (window.opera) {
|
||||
class SvgCanvas {
|
||||
/**
|
||||
* @param {HTMLElement} container - The container HTML element that should hold the SVG root element
|
||||
* @param {module:SVGEditor.curConfig} config - An object that contains configuration data
|
||||
* @param {module:SVGeditor.configObj.curConfig} config - An object that contains configuration data
|
||||
*/
|
||||
constructor (container, config) {
|
||||
// Alias Namespace constants
|
||||
@@ -1740,7 +1740,6 @@ class SvgCanvas {
|
||||
*/
|
||||
this.setUiStrings = function (strs) {
|
||||
Object.assign(uiStrings, strs.notification);
|
||||
$ = jQueryPluginDBox($, strs.common);
|
||||
pathModule.setUiStrings(strs);
|
||||
};
|
||||
|
||||
@@ -2743,4 +2742,14 @@ class SvgCanvas {
|
||||
} // End constructor
|
||||
} // End class
|
||||
|
||||
// attach utilities function to the class that are used by SvgEdit so
|
||||
// we can avoid using the whole utilities.js file in svgEdit.js
|
||||
SvgCanvas.isNullish = isNullish;
|
||||
SvgCanvas.encode64 = encode64;
|
||||
SvgCanvas.decode64 = decode64;
|
||||
SvgCanvas.$id = $id;
|
||||
SvgCanvas.$qq = $qq;
|
||||
SvgCanvas.$qa = $qa;
|
||||
SvgCanvas.blankPageObjectURL = blankPageObjectURL;
|
||||
|
||||
export default SvgCanvas;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {text2xml} from '../common/utilities.js';
|
||||
import {text2xml} from './utilities.js';
|
||||
|
||||
/**
|
||||
* @function module:svgcanvas.svgRootElement svgRootElement the svg node and its children.
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
import {NS} from './namespaces.js';
|
||||
import {supportsNativeTransformLists} from './browser.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {supportsNativeTransformLists} from '../common/browser.js';
|
||||
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
||||
*/
|
||||
|
||||
import jQueryPluginSVG from '../common/jQuery.attr.js';
|
||||
import jQueryPluginSVG from './jQuery.attr.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {
|
||||
transformPoint, getMatrix
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
assignAttributes, getElem, getBBox as utilsGetBBox
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
supportsGoodTextCharPos
|
||||
} from '../common/browser.js';
|
||||
@@ -263,15 +263,6 @@ export const textActionsMethod = (function () {
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
// Not currently in use
|
||||
function hideCursor () {
|
||||
if (cursor) {
|
||||
cursor.setAttribute('visibility', 'hidden');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} evt
|
||||
|
||||
@@ -8,16 +8,16 @@ import * as draw from './draw.js';
|
||||
import * as hstry from './history.js';
|
||||
import {
|
||||
getRotationAngle, getBBox as utilsGetBBox, isNullish, setHref, getStrokedBBoxDefaultVisible
|
||||
} from '../common/utilities.js';
|
||||
} from './utilities.js';
|
||||
import {
|
||||
isGecko
|
||||
} from '../common/browser.js';
|
||||
import {
|
||||
transformPoint, transformListToTransform
|
||||
} from '../common/math.js';
|
||||
} from './math.js';
|
||||
import {
|
||||
getTransformList
|
||||
} from '../common/svgtransformlist.js';
|
||||
} from './svgtransformlist.js';
|
||||
|
||||
const {
|
||||
UndoManager, HistoryEventTypes
|
||||
|
||||
@@ -8,16 +8,16 @@
|
||||
*/
|
||||
|
||||
import jQueryPluginSVG from './jQuery.attr.js'; // Needed for SVG attribute setting and array form with `attr`
|
||||
import {NS} from './namespaces.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {getTransformList} from './svgtransformlist.js';
|
||||
import {setUnitAttr, getTypeMap} from './units.js';
|
||||
import {setUnitAttr, getTypeMap} from '../common/units.js';
|
||||
import {
|
||||
hasMatrixTransform, transformListToTransform, transformBox
|
||||
} from './math.js';
|
||||
import {
|
||||
isWebkit, supportsHVLineContainerBBox, supportsPathBBox, supportsXpath,
|
||||
supportsSelectors
|
||||
} from './browser.js';
|
||||
} from '../common/browser.js';
|
||||
|
||||
// Constants
|
||||
const $ = jQueryPluginSVG(jQuery);
|
||||
@@ -1298,17 +1298,6 @@ export const snapToGrid = function (value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes special characters in a regular expression.
|
||||
* @function module:utilities.regexEscape
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
export const regexEscape = function (str) {
|
||||
// Originally from: http://phpjs.org/functions
|
||||
return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&');
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents default browser click behaviour on the given element.
|
||||
* @function module:utilities.preventClickDefault
|
||||
@@ -1350,6 +1339,7 @@ export const mock = ({
|
||||
getRotationAngle = getRotationAngleUser;
|
||||
};
|
||||
|
||||
// shortcuts to common DOM functions
|
||||
export const $id = (id) => document.getElementById(id);
|
||||
export const $q = (sel) => document.querySelector(sel);
|
||||
export const $qq = (sel) => [...document.querySelectorAll(sel)];
|
||||
export const $qq = (sel) => document.querySelector(sel);
|
||||
export const $qa = (sel) => [...document.querySelectorAll(sel)];
|
||||
Reference in New Issue
Block a user