move to standard linter for simpler configuration

This commit is contained in:
JFH
2021-12-28 11:02:29 -03:00
parent 258e2bd6a1
commit fdcfc8a253
251 changed files with 19760 additions and 19935 deletions

View File

@@ -6,36 +6,36 @@
* @copyright 2010 Jeff Schiller, 2010 Alexis Deveria
*/
const NSSVG = 'http://www.w3.org/2000/svg';
const NSSVG = 'http://www.w3.org/2000/svg'
const { userAgent } = navigator;
const { userAgent } = navigator
// Note: Browser sniffing should only be used if no other detection method is possible
const isWebkit_ = userAgent.includes('AppleWebKit');
const isGecko_ = userAgent.includes('Gecko/');
const isChrome_ = userAgent.includes('Chrome/');
const isMac_ = userAgent.includes('Macintosh');
const isTouch_ = 'ontouchstart' in window;
const isWebkit_ = userAgent.includes('AppleWebKit')
const isGecko_ = userAgent.includes('Gecko/')
const isChrome_ = userAgent.includes('Chrome/')
const isMac_ = userAgent.includes('Macintosh')
const isTouch_ = 'ontouchstart' in window
// text character positioning (for IE9 and now Chrome)
const supportsGoodTextCharPos_ = (function () {
const svgroot = document.createElementNS(NSSVG, 'svg');
const svgContent = document.createElementNS(NSSVG, 'svg');
document.documentElement.append(svgroot);
svgContent.setAttribute('x', 5);
svgroot.append(svgContent);
const text = document.createElementNS(NSSVG, 'text');
text.textContent = 'a';
svgContent.append(text);
const svgroot = document.createElementNS(NSSVG, 'svg')
const svgContent = document.createElementNS(NSSVG, 'svg')
document.documentElement.append(svgroot)
svgContent.setAttribute('x', 5)
svgroot.append(svgContent)
const text = document.createElementNS(NSSVG, 'text')
text.textContent = 'a'
svgContent.append(text)
try { // Chrome now fails here
const pos = text.getStartPositionOfChar(0).x;
return (pos === 0);
const pos = text.getStartPositionOfChar(0).x
return (pos === 0)
} catch (err) {
return false;
return false
} finally {
svgroot.remove();
svgroot.remove()
}
}());
}())
// Public API
@@ -43,31 +43,31 @@ const supportsGoodTextCharPos_ = (function () {
* @function module:browser.isWebkit
* @returns {boolean}
*/
export const isWebkit = () => isWebkit_;
export const isWebkit = () => isWebkit_
/**
* @function module:browser.isGecko
* @returns {boolean}
*/
export const isGecko = () => isGecko_;
export const isGecko = () => isGecko_
/**
* @function module:browser.isChrome
* @returns {boolean}
*/
export const isChrome = () => isChrome_;
export const isChrome = () => isChrome_
/**
* @function module:browser.isMac
* @returns {boolean}
*/
export const isMac = () => isMac_;
export const isMac = () => isMac_
/**
* @function module:browser.isTouch
* @returns {boolean}
*/
export const isTouch = () => isTouch_;
export const isTouch = () => isTouch_
/**
* @function module:browser.supportsGoodTextCharPos
* @returns {boolean}
*/
export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_

View File

@@ -6,17 +6,17 @@
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
*/
const NSSVG = 'http://www.w3.org/2000/svg';
const NSSVG = 'http://www.w3.org/2000/svg'
const wAttrs = [ 'x', 'x1', 'cx', 'rx', 'width' ];
const hAttrs = [ 'y', 'y1', 'cy', 'ry', 'height' ];
const unitAttrs = [ 'r', 'radius', ...wAttrs, ...hAttrs ];
const wAttrs = ['x', 'x1', 'cx', 'rx', 'width']
const hAttrs = ['y', 'y1', 'cy', 'ry', 'height']
const unitAttrs = ['r', 'radius', ...wAttrs, ...hAttrs]
// Container of elements.
let elementContainer_;
let elementContainer_
// Stores mapping of unit type to user coordinates.
let typeMap_ = {};
let typeMap_ = {}
/**
* @interface module:units.ElementContainer
@@ -63,20 +63,20 @@ let typeMap_ = {};
* @returns {void}
*/
export const init = function (elementContainer) {
elementContainer_ = elementContainer;
elementContainer_ = elementContainer
// Get correct em/ex values by creating a temporary SVG.
const svg = document.createElementNS(NSSVG, 'svg');
document.body.append(svg);
const rect = document.createElementNS(NSSVG, 'rect');
rect.setAttribute('width', '1em');
rect.setAttribute('height', '1ex');
rect.setAttribute('x', '1in');
svg.append(rect);
const bb = rect.getBBox();
svg.remove();
const svg = document.createElementNS(NSSVG, 'svg')
document.body.append(svg)
const rect = document.createElementNS(NSSVG, 'rect')
rect.setAttribute('width', '1em')
rect.setAttribute('height', '1ex')
rect.setAttribute('x', '1in')
svg.append(rect)
const bb = rect.getBBox()
svg.remove()
const inch = bb.x;
const inch = bb.x
typeMap_ = {
em: bb.width,
ex: bb.height,
@@ -87,8 +87,8 @@ export const init = function (elementContainer) {
pc: inch / 6,
px: 1,
'%': 0
};
};
}
}
/**
* Group: Unit conversion functions.
@@ -99,8 +99,8 @@ export const init = function (elementContainer) {
* @returns {module:units.TypeMap} The unit object with values for each unit
*/
export const getTypeMap = function () {
return typeMap_;
};
return typeMap_
}
/**
* @typedef {GenericArray} module:units.CompareNumbers
@@ -119,15 +119,15 @@ export const getTypeMap = function () {
* with comma-separated floats
*/
export const shortFloat = function (val) {
const digits = elementContainer_.getRoundDigits();
const digits = elementContainer_.getRoundDigits()
if (!isNaN(val)) {
return Number(Number(val).toFixed(digits));
return Number(Number(val).toFixed(digits))
}
if (Array.isArray(val)) {
return shortFloat(val[0]) + ',' + shortFloat(val[1]);
return shortFloat(val[0]) + ',' + shortFloat(val[1])
}
return Number.parseFloat(val).toFixed(digits) - 0;
};
return Number.parseFloat(val).toFixed(digits) - 0
}
/**
* Converts the number to given unit or baseUnit.
@@ -137,12 +137,12 @@ export const shortFloat = function (val) {
* @returns {Float}
*/
export const convertUnit = function (val, unit) {
unit = unit || elementContainer_.getBaseUnit();
unit = unit || elementContainer_.getBaseUnit()
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
// const val = baseVal.valueInSpecifiedUnits;
// baseVal.convertToSpecifiedUnits(1);
return shortFloat(val / typeMap_[unit]);
};
return shortFloat(val / typeMap_[unit])
}
/**
* Sets an element's attribute based on the unit in its current value.
@@ -185,19 +185,19 @@ export const setUnitAttr = function (elem, attr, val) {
// val += unit;
// }
// }
elem.setAttribute(attr, val);
};
elem.setAttribute(attr, val)
}
const attrsToConvert = {
line: [ 'x1', 'x2', 'y1', 'y2' ],
circle: [ 'cx', 'cy', 'r' ],
ellipse: [ 'cx', 'cy', 'rx', 'ry' ],
foreignObject: [ 'x', 'y', 'width', 'height' ],
rect: [ 'x', 'y', 'width', 'height' ],
image: [ 'x', 'y', 'width', 'height' ],
use: [ 'x', 'y', 'width', 'height' ],
text: [ 'x', 'y' ]
};
line: ['x1', 'x2', 'y1', 'y2'],
circle: ['cx', 'cy', 'r'],
ellipse: ['cx', 'cy', 'rx', 'ry'],
foreignObject: ['x', 'y', 'width', 'height'],
rect: ['x', 'y', 'width', 'height'],
image: ['x', 'y', 'width', 'height'],
use: ['x', 'y', 'width', 'height'],
text: ['x', 'y']
}
/**
* Converts all applicable attributes to the configured baseUnit.
@@ -206,18 +206,18 @@ const attrsToConvert = {
* @returns {void}
*/
export const convertAttrs = function (element) {
const elName = element.tagName;
const unit = elementContainer_.getBaseUnit();
const attrs = attrsToConvert[elName];
if (!attrs) { return; }
const elName = element.tagName
const unit = elementContainer_.getBaseUnit()
const attrs = attrsToConvert[elName]
if (!attrs) { return }
attrs.forEach( (attr) => {
const cur = element.getAttribute(attr);
attrs.forEach((attr) => {
const cur = element.getAttribute(attr)
if (cur && !isNaN(cur)) {
element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
element.setAttribute(attr, (cur / typeMap_[unit]) + unit)
}
});
};
})
}
/**
* Converts given values to numbers. Attributes must be supplied in
@@ -230,26 +230,26 @@ export const convertAttrs = function (element) {
*/
export const convertToNum = function (attr, val) {
// Return a number if that's what it already is
if (!isNaN(val)) { return val - 0; }
if (!isNaN(val)) { return val - 0 }
if (val.substr(-1) === '%') {
// Deal with percentage, depends on attribute
const num = val.substr(0, val.length - 1) / 100;
const width = elementContainer_.getWidth();
const height = elementContainer_.getHeight();
const num = val.substr(0, val.length - 1) / 100
const width = elementContainer_.getWidth()
const height = elementContainer_.getHeight()
if (wAttrs.includes(attr)) {
return num * width;
return num * width
}
if (hAttrs.includes(attr)) {
return num * height;
return num * height
}
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2);
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2)
}
const unit = val.substr(-2);
const num = val.substr(0, val.length - 2);
const unit = val.substr(-2)
const num = val.substr(0, val.length - 2)
// Note that this multiplication turns the string into a number
return num * typeMap_[unit];
};
return num * typeMap_[unit]
}
/**
* Check if an attribute's value is in a valid format.
@@ -263,29 +263,29 @@ export const isValidUnit = function (attr, val, selectedElement) {
if (unitAttrs.includes(attr)) {
// True if it's just a number
if (!isNaN(val)) {
return true;
return true
}
// Not a number, check if it has a valid unit
val = val.toLowerCase();
val = val.toLowerCase()
return Object.keys(typeMap_).some((unit) => {
const re = new RegExp('^-?[\\d\\.]+' + unit + '$');
return re.test(val);
});
const re = new RegExp('^-?[\\d\\.]+' + unit + '$')
return re.test(val)
})
}
if (attr === 'id') {
// if we're trying to change the id, make sure it's not already present in the doc
// and the id value is valid.
let result = false;
let result = false
// because getElem() can throw an exception in the case of an invalid id
// (according to https://www.w3.org/TR/xml-id/ IDs must be a NCName)
// we wrap it in an exception and only return true if the ID was valid and
// not already present
try {
const elem = elementContainer_.getElement(val);
result = (!elem || elem === selectedElement);
} catch (e) {/* empty fn */}
return result;
const elem = elementContainer_.getElement(val)
result = (!elem || elem === selectedElement)
} catch (e) { /* empty fn */ }
return result
}
return true;
};
return true
}

View File

@@ -1,4 +1,4 @@
import { mergeDeep } from './components/jgraduate/Util.js';
import { mergeDeep } from './components/jgraduate/Util.js'
/**
* Escapes special characters in a regular expression.
@@ -8,8 +8,8 @@ import { mergeDeep } from './components/jgraduate/Util.js';
*/
export const regexEscape = function (str) {
// Originally from: http://phpjs.org/functions
return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&');
};
return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&')
}
/**
* @class configObj
*/
@@ -47,7 +47,7 @@ export default class ConfigObj {
// Only shows in UI as far as alert notices, but useful to remember, so keeping as pref
save_notice_done: false,
export_notice_done: false
};
}
/**
* @tutorial ConfigOptions
* @interface module:SVGEditor.Config
@@ -134,7 +134,7 @@ export default class ConfigObj {
imgPath: './images',
// DOCUMENT PROPERTIES
// Change the following to a preference (already in the Document Properties dialog)?
dimensions: [ 640, 480 ],
dimensions: [640, 480],
// EDITOR OPTIONS
// Change the following to preferences (already in the Editor Options dialog)?
gridSnapping: false,
@@ -158,13 +158,13 @@ export default class ConfigObj {
avoidClientSide: false, // Deprecated in favor of `avoidClientSideDownload`
avoidClientSideDownload: false,
avoidClientSideOpen: false
};
}
this.curPrefs = {};
this.curPrefs = {}
// 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.urldata = {};
this.urldata = {}
/**
* @name module:SVGEditor~defaultExtensions
* @type {string[]}
@@ -182,7 +182,7 @@ export default class ConfigObj {
'ext-polystar',
'ext-storage',
'ext-opensave'
];
]
this.curConfig = {
// We do not put on defaultConfig to simplify object copying
// procedures (we obtain instead from defaultExtensions)
@@ -203,61 +203,64 @@ export default class ConfigObj {
* @todo We might instead make as a user-facing preference.
*/
allowedOrigins: []
};
this.editor = editor;
}
this.editor = editor
}
/**
* @function setupCurPrefs
* @returns {void}
*/
setupCurPrefs () {
const curPrefs = { ...this.defaultPrefs, ...this.curPrefs }; // Now safe to merge with priority for curPrefs in the event any are already set
const curPrefs = { ...this.defaultPrefs, ...this.curPrefs } // Now safe to merge with priority for curPrefs in the event any are already set
// Export updated prefs
this.curPrefs = curPrefs;
this.curPrefs = curPrefs
}
/**
* Sets up current config based on defaults.
* @returns {void}
*/
setupCurConfig () {
const curConfig = { ...this.defaultConfig, ...this.curConfig }; // Now safe to merge with priority for curConfig in the event any are already set
const curConfig = { ...this.defaultConfig, ...this.curConfig } // Now safe to merge with priority for curConfig in the event any are already set
// Now deal with extensions and other array config
if (!curConfig.noDefaultExtensions) {
curConfig.extensions = [ ...this.defaultExtensions ];
curConfig.extensions = [...this.defaultExtensions]
}
// Export updated config
this.curConfig = curConfig;
this.curConfig = curConfig
}
/**
* @function loadFromURL Load config/data from URL if given
* @returns {void}
*/
loadFromURL () {
const self = this;
const { search, searchParams } = new URL(location);
const self = this
const { search, searchParams } = new URL(location)
if (search) {
this.urldata = {};
const entries = searchParams.entries();
for(const entry of entries) {
this.urldata[entry[0]] = entry[1];
this.urldata = {}
const entries = searchParams.entries()
for (const entry of entries) {
this.urldata[entry[0]] = entry[1]
}
[ 'initStroke', 'initFill' ].forEach((prop) => {
['initStroke', 'initFill'].forEach((prop) => {
if (searchParams.has(`${prop}[color]`)) {
// Restore back to original non-deparamed value to avoid color
// strings being converted to numbers
if(this.urldata[prop] === undefined) { this.urldata[prop] = {}; }
this.urldata[prop].color = searchParams.get(`${prop}[color]`);
if (this.urldata[prop] === undefined) { this.urldata[prop] = {} }
this.urldata[prop].color = searchParams.get(`${prop}[color]`)
}
});
})
if (searchParams.has('bkgd_color')) {
this.urldata.bkgd_color = '#' + searchParams.get('bkgd_color');
this.urldata.bkgd_color = '#' + searchParams.get('bkgd_color')
}
if (this.urldata.dimensions) {
this.urldata.dimensions = this.urldata.dimensions.split(',');
this.urldata.dimensions = this.urldata.dimensions.split(',')
}
if (this.urldata.extensions) {
@@ -265,54 +268,55 @@ export default class ConfigObj {
// extensions via URL
this.urldata.extensions = (/[:/\\]/).test(this.urldata.extensions)
? ''
: this.urldata.extensions.split(',');
: this.urldata.extensions.split(',')
}
// Disallowing extension paths via URL for
// security reasons, even for same-domain
// ones given potential to interact in undesirable
// ways with other script resources
[ 'userExtensions', 'imgPath' ]
['userExtensions', 'imgPath']
.forEach(function (pathConfig) {
if (self.urldata[pathConfig]) {
delete self.urldata[pathConfig];
delete self.urldata[pathConfig]
}
});
})
// Note: `source` and `url` (as with `storagePrompt` later) are not
// set on config but are used below
this.setConfig(this.urldata, { overwrite: false });
this.setupCurConfig();
this.setConfig(this.urldata, { overwrite: false })
this.setupCurConfig()
if (!this.curConfig.preventURLContentLoading) {
let { source } = this.urldata;
let { source } = this.urldata
if (!source) { // urldata.source may have been null if it ended with '='
const src = searchParams.get('source');
const src = searchParams.get('source')
if (src && src.startsWith('data:')) {
source = src;
source = src
}
}
if (source) {
if (source.startsWith('data:')) {
this.editor.loadFromDataURI(source);
this.editor.loadFromDataURI(source)
} else {
this.editor.loadFromString(source);
this.editor.loadFromString(source)
}
return;
return
}
if (this.urldata.url) {
this.editor.loadFromURL(this.urldata.url);
return;
this.editor.loadFromURL(this.urldata.url)
return
}
}
if (!this.urldata.noStorageOnLoad || this.curConfig.forceStorage) {
this.loadContentAndPrefs();
this.loadContentAndPrefs()
}
} else {
this.setupCurConfig();
this.loadContentAndPrefs();
this.setupCurConfig()
this.loadContentAndPrefs()
}
}
/**
* Where permitted, sets canvas and/or `configObj.defaultPrefs` based on previous
* storage. This will override URL settings (for security reasons) but
@@ -333,7 +337,7 @@ export default class ConfigObj {
!(/(?:^|;\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/).test(document.cookie)
)
) {
return;
return
}
// LOAD CONTENT
@@ -343,32 +347,32 @@ export default class ConfigObj {
(/(?:^|;\s*)svgeditstore=prefsAndContent/).test(document.cookie))
)
) {
const name = 'svgedit-' + this.curConfig.canvasName;
const cached = this.editor.storage.getItem(name);
const name = 'svgedit-' + this.curConfig.canvasName
const cached = this.editor.storage.getItem(name)
if (cached) {
this.editor.loadFromString(cached);
this.editor.loadFromString(cached)
}
}
// LOAD PREFS
Object.keys(this.defaultPrefs).forEach((key) => {
const storeKey = 'svg-edit-' + key;
const storeKey = 'svg-edit-' + key
if (this.editor.storage) {
const val = this.editor.storage.getItem(storeKey);
const val = this.editor.storage.getItem(storeKey)
if (val) {
this.defaultPrefs[key] = String(val); // Convert to string for FF (.value fails in Webkit)
this.defaultPrefs[key] = String(val) // Convert to string for FF (.value fails in Webkit)
}
} else if (window.widget) {
this.defaultPrefs[key] = window.widget.preferenceForKey(storeKey);
this.defaultPrefs[key] = window.widget.preferenceForKey(storeKey)
} else {
const result = document.cookie.match(
new RegExp('(?:^|;\\s*)' + regexEscape(
encodeURIComponent(storeKey)
) + '=([^;]+)')
);
this.defaultPrefs[key] = result ? decodeURIComponent(result[1]) : '';
)
this.defaultPrefs[key] = result ? decodeURIComponent(result[1]) : ''
}
});
})
}
/**
@@ -402,61 +406,62 @@ export default class ConfigObj {
*/
const extendOrAdd = (cfgObj, key, val) => {
if (cfgObj[key] && typeof cfgObj[key] === 'object') {
cfgObj[key] = mergeDeep(cfgObj[key], val);
cfgObj[key] = mergeDeep(cfgObj[key], val)
} else {
cfgObj[key] = val;
cfgObj[key] = val
}
};
Object.entries(opts).forEach(([ key, val ]) => {
}
Object.entries(opts).forEach(([key, val]) => {
// Only allow prefs defined in configObj.defaultPrefs or...
if (this.defaultPrefs[key]) {
if (cfgCfg.overwrite === false && (
this.curConfig.preventAllURLConfig ||
this.curPrefs[key])
) {
return;
return
}
if (cfgCfg.allowInitialUserOverride === true) {
this.defaultPrefs[key] = val;
this.defaultPrefs[key] = val
} else {
this.pref(key, val);
this.pref(key, val)
}
} else if ([ 'extensions', 'userExtensions', 'allowedOrigins' ].includes(key)) {
} else if (['extensions', 'userExtensions', 'allowedOrigins'].includes(key)) {
if (cfgCfg.overwrite === false &&
(
this.curConfig.preventAllURLConfig ||
[ 'allowedOrigins' ].includes(key) ||
['allowedOrigins'].includes(key) ||
(key === 'extensions' && this.curConfig.lockExtensions)
)
) {
return;
return
}
this.curConfig[key] = this.curConfig[key].concat(val); // We will handle any dupes later
this.curConfig[key] = this.curConfig[key].concat(val) // We will handle any dupes later
// Only allow other configObj.curConfig if defined in configObj.defaultConfig
} else if ({}.hasOwnProperty.call(this.defaultConfig, key)) {
if (cfgCfg.overwrite === false && (
this.curConfig.preventAllURLConfig ||
{}.hasOwnProperty.call(this.curConfig, key)
)) {
return;
return
}
// Potentially overwriting of previously set config
if ({}.hasOwnProperty.call(this.curConfig, key)) {
if (cfgCfg.overwrite === false) {
return;
return
}
extendOrAdd(this.curConfig, key, val);
extendOrAdd(this.curConfig, key, val)
} else if (cfgCfg.allowInitialUserOverride === true) {
extendOrAdd(this.defaultConfig, key, val);
extendOrAdd(this.defaultConfig, key, val)
} else if (this.defaultConfig[key] && typeof this.defaultConfig[key] === 'object') {
this.curConfig[key] = Array.isArray(this.defaultConfig[key]) ? [] : {};
this.curConfig[key] = mergeDeep(this.curConfig[key], val);
this.curConfig[key] = Array.isArray(this.defaultConfig[key]) ? [] : {}
this.curConfig[key] = mergeDeep(this.curConfig[key], val)
} else {
this.curConfig[key] = val;
this.curConfig[key] = val
}
}
});
})
}
/**
* Store and retrieve preferences.
* @function pref
@@ -475,17 +480,18 @@ export default class ConfigObj {
*/
pref (key, val, mayBeEmpty) {
if (mayBeEmpty || val) {
this.curPrefs[key] = val;
return undefined;
this.curPrefs[key] = val
return undefined
}
return (key in this.curPrefs) ? this.curPrefs[key] : this.defaultPrefs[key];
return (key in this.curPrefs) ? this.curPrefs[key] : this.defaultPrefs[key]
}
/**
* @function load load Config
* @returns {void}
*/
load () {
this.loadFromURL(this.editor);
this.setupCurPrefs(this.editor);
this.loadFromURL(this.editor)
this.setupCurPrefs(this.editor)
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
/* globals seConfirm, seAlert */
import SvgCanvas from "../svgcanvas/svgcanvas.js";
import { convertUnit, isValidUnit } from '../common/units.js';
import { isChrome } from '../common/browser.js';
import SvgCanvas from '../svgcanvas/svgcanvas.js'
import { convertUnit, isValidUnit } from '../common/units.js'
import { isChrome } from '../common/browser.js'
const { $id } = SvgCanvas;
const homePage = 'https://github.com/SVG-Edit/svgedit';
const { $id } = SvgCanvas
const homePage = 'https://github.com/SVG-Edit/svgedit'
/**
*
@@ -13,89 +13,91 @@ class MainMenu {
/**
* @param {PlainObject} editor svgedit handler
*/
constructor(editor) {
this.editor = editor;
constructor (editor) {
this.editor = editor
/**
* @type {Integer}
*/
this.exportWindowCt = 0;
this.exportWindowCt = 0
}
/**
* @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument
* @returns {void}
*/
async clickClear() {
const [ x, y ] = this.editor.configObj.curConfig.dimensions;
const ok = await seConfirm(this.editor.i18next.t('notification.QwantToClear'));
if (ok === "Cancel") {
return;
async clickClear () {
const [x, y] = this.editor.configObj.curConfig.dimensions
const ok = await seConfirm(this.editor.i18next.t('notification.QwantToClear'))
if (ok === 'Cancel') {
return
}
this.editor.leftPanel.clickSelect();
this.editor.svgCanvas.clear();
this.editor.svgCanvas.setResolution(x, y);
this.editor.updateCanvas(true);
this.editor.zoomImage();
this.editor.layersPanel.populateLayers();
this.editor.topPanel.updateContextPanel();
this.editor.svgCanvas.runExtensions("onNewDocument");
}
/**
*
* @returns {void}
*/
hideDocProperties() {
const $imgDialog = $id("se-img-prop");
$imgDialog.setAttribute("dialog", "close");
$imgDialog.setAttribute("save", this.editor.configObj.pref("img_save"));
this.editor.docprops = false;
this.editor.leftPanel.clickSelect()
this.editor.svgCanvas.clear()
this.editor.svgCanvas.setResolution(x, y)
this.editor.updateCanvas(true)
this.editor.zoomImage()
this.editor.layersPanel.populateLayers()
this.editor.topPanel.updateContextPanel()
this.editor.svgCanvas.runExtensions('onNewDocument')
}
/**
*
* @returns {void}
*/
hidePreferences() {
const $editDialog = $id("se-edit-prefs");
$editDialog.setAttribute("dialog", "close");
this.editor.configObj.preferences = false;
hideDocProperties () {
const $imgDialog = $id('se-img-prop')
$imgDialog.setAttribute('dialog', 'close')
$imgDialog.setAttribute('save', this.editor.configObj.pref('img_save'))
this.editor.docprops = false
}
/**
*
* @returns {void}
*/
hidePreferences () {
const $editDialog = $id('se-edit-prefs')
$editDialog.setAttribute('dialog', 'close')
this.editor.configObj.preferences = false
}
/**
* @param {Event} e
* @returns {boolean} Whether there were problems saving the document properties
*/
saveDocProperties(e) {
saveDocProperties (e) {
// set title
const { title, w, h, save } = e.detail;
const { title, w, h, save } = e.detail
// set document title
this.editor.svgCanvas.setDocumentTitle(title);
this.editor.svgCanvas.setDocumentTitle(title)
if (w !== "fit" && !isValidUnit("width", w)) {
seAlert(this.editor.i18next.t('notification.invalidAttrValGiven'));
return false;
if (w !== 'fit' && !isValidUnit('width', w)) {
seAlert(this.editor.i18next.t('notification.invalidAttrValGiven'))
return false
}
if (h !== "fit" && !isValidUnit("height", h)) {
seAlert(this.editor.i18next.t('notification.invalidAttrValGiven'));
return false;
if (h !== 'fit' && !isValidUnit('height', h)) {
seAlert(this.editor.i18next.t('notification.invalidAttrValGiven'))
return false
}
if (!this.editor.svgCanvas.setResolution(w, h)) {
seAlert(this.editor.i18next.t('notification.noContentToFitTo'));
return false;
seAlert(this.editor.i18next.t('notification.noContentToFitTo'))
return false
}
// Set image save option
this.editor.configObj.pref("img_save", save);
this.editor.updateCanvas();
this.hideDocProperties();
return true;
this.editor.configObj.pref('img_save', save)
this.editor.updateCanvas()
this.hideDocProperties()
return true
}
/**
* Save user preferences based on current values in the UI.
* @param {Event} e
* @function module:SVGthis.savePreferences
* @returns {Promise<void>}
*/
async savePreferences(e) {
async savePreferences (e) {
const {
lang,
bgcolor,
@@ -105,57 +107,58 @@ class MainMenu {
gridcolor,
showrulers,
baseunit
} = e.detail;
} = e.detail
// Set background
this.editor.setBackground(bgcolor, bgurl);
this.editor.setBackground(bgcolor, bgurl)
// set language
if (lang && lang !== this.editor.configObj.pref("lang")) {
this.editor.configObj.pref("lang", lang);
seAlert('Changing the language needs reload');
if (lang && lang !== this.editor.configObj.pref('lang')) {
this.editor.configObj.pref('lang', lang)
seAlert('Changing the language needs reload')
}
// set grid setting
this.editor.configObj.curConfig.gridSnapping = gridsnappingon;
this.editor.configObj.curConfig.snappingStep = gridsnappingstep;
this.editor.configObj.curConfig.gridColor = gridcolor;
this.editor.configObj.curConfig.showRulers = showrulers;
this.editor.configObj.curConfig.gridSnapping = gridsnappingon
this.editor.configObj.curConfig.snappingStep = gridsnappingstep
this.editor.configObj.curConfig.gridColor = gridcolor
this.editor.configObj.curConfig.showRulers = showrulers
if (this.editor.configObj.curConfig.showRulers) {
this.editor.rulers.updateRulers();
this.editor.rulers.updateRulers()
}
this.editor.configObj.curConfig.baseUnit = baseunit;
this.editor.svgCanvas.setConfig(this.editor.configObj.curConfig);
this.editor.updateCanvas();
this.hidePreferences();
this.editor.configObj.curConfig.baseUnit = baseunit
this.editor.svgCanvas.setConfig(this.editor.configObj.curConfig)
this.editor.updateCanvas()
this.hidePreferences()
}
/**
*
* @param e
* @returns {Promise<void>} Resolves to `undefined`
*/
async clickExport(e) {
if (e?.detail?.trigger !== "ok" || e?.detail?.imgType === undefined) {
return;
async clickExport (e) {
if (e?.detail?.trigger !== 'ok' || e?.detail?.imgType === undefined) {
return
}
const imgType = e?.detail?.imgType;
const quality = e?.detail?.quality ? e?.detail?.quality / 100 : 1;
const imgType = e?.detail?.imgType
const quality = e?.detail?.quality ? e?.detail?.quality / 100 : 1
// Open placeholder window (prevents popup)
let exportWindowName;
let exportWindowName
/**
*
* @returns {void}
*/
const openExportWindow = () => {
const loadingImage = this.editor.i18next.t('notification.loadingImage');
if (this.editor.configObj.curConfig.exportWindowType === "new") {
this.editor.exportWindowCt++;
const loadingImage = this.editor.i18next.t('notification.loadingImage')
if (this.editor.configObj.curConfig.exportWindowType === 'new') {
this.editor.exportWindowCt++
}
this.editor.exportWindowName =
this.editor.configObj.curConfig.canvasName + this.editor.exportWindowCt;
let popHTML; let popURL;
this.editor.configObj.curConfig.canvasName + this.editor.exportWindowCt
let popHTML; let popURL
if (this.editor.loadingURL) {
popURL = this.editor.loadingURL;
popURL = this.editor.loadingURL
} else {
popHTML = `<!DOCTYPE html><html>
<head>
@@ -163,35 +166,35 @@ class MainMenu {
<title>${loadingImage}</title>
</head>
<body><h1>${loadingImage}</h1></body>
<html>`;
if (typeof URL !== "undefined" && URL.createObjectURL) {
const blob = new Blob([ popHTML ], { type: "text/html" });
popURL = URL.createObjectURL(blob);
<html>`
if (typeof URL !== 'undefined' && URL.createObjectURL) {
const blob = new Blob([popHTML], { type: 'text/html' })
popURL = URL.createObjectURL(blob)
} else {
popURL = "data:text/html;base64;charset=utf-8," + popHTML;
popURL = 'data:text/html;base64;charset=utf-8,' + popHTML
}
this.editor.loadingURL = popURL;
this.editor.loadingURL = popURL
}
this.editor.exportWindow = window.open(
popURL,
this.editor.exportWindowName
);
};
const chrome = isChrome();
if (imgType === "PDF") {
)
}
const chrome = isChrome()
if (imgType === 'PDF') {
if (!this.editor.customExportPDF && !chrome) {
openExportWindow();
openExportWindow()
}
this.editor.svgCanvas.exportPDF(exportWindowName);
this.editor.svgCanvas.exportPDF(exportWindowName)
} else {
if (!this.editor.customExportImage) {
openExportWindow();
openExportWindow()
}
/* const results = */ await this.editor.svgCanvas.rasterExport(
imgType,
quality,
this.editor.exportWindowName
);
)
}
}
@@ -199,129 +202,129 @@ class MainMenu {
*
* @returns {void}
*/
showDocProperties() {
showDocProperties () {
if (this.editor.docprops) {
return;
return
}
this.editor.docprops = true;
const $imgDialog = $id("se-img-prop");
this.editor.docprops = true
const $imgDialog = $id('se-img-prop')
// update resolution option with actual resolution
const resolution = this.editor.svgCanvas.getResolution();
if (this.editor.configObj.curConfig.baseUnit !== "px") {
const resolution = this.editor.svgCanvas.getResolution()
if (this.editor.configObj.curConfig.baseUnit !== 'px') {
resolution.w =
convertUnit(resolution.w) + this.editor.configObj.curConfig.baseUnit;
convertUnit(resolution.w) + this.editor.configObj.curConfig.baseUnit
resolution.h =
convertUnit(resolution.h) + this.editor.configObj.curConfig.baseUnit;
convertUnit(resolution.h) + this.editor.configObj.curConfig.baseUnit
}
$imgDialog.setAttribute("save", this.editor.configObj.pref("img_save"));
$imgDialog.setAttribute("width", resolution.w);
$imgDialog.setAttribute("height", resolution.h);
$imgDialog.setAttribute("title", this.editor.svgCanvas.getDocumentTitle());
$imgDialog.setAttribute("dialog", "open");
$imgDialog.setAttribute('save', this.editor.configObj.pref('img_save'))
$imgDialog.setAttribute('width', resolution.w)
$imgDialog.setAttribute('height', resolution.h)
$imgDialog.setAttribute('title', this.editor.svgCanvas.getDocumentTitle())
$imgDialog.setAttribute('dialog', 'open')
}
/**
*
* @returns {void}
*/
showPreferences() {
showPreferences () {
if (this.editor.configObj.preferences) {
return;
return
}
this.editor.configObj.preferences = true;
const $editDialog = $id("se-edit-prefs");
this.editor.configObj.preferences = true
const $editDialog = $id('se-edit-prefs')
// Update background color with current one
const canvasBg = this.editor.configObj.curPrefs.bkgd_color;
const url = this.editor.configObj.pref("bkgd_url");
const canvasBg = this.editor.configObj.curPrefs.bkgd_color
const url = this.editor.configObj.pref('bkgd_url')
if (url) {
$editDialog.setAttribute("bgurl", url);
$editDialog.setAttribute('bgurl', url)
}
$editDialog.setAttribute(
"gridsnappingon",
'gridsnappingon',
this.editor.configObj.curConfig.gridSnapping
);
)
$editDialog.setAttribute(
"gridsnappingstep",
'gridsnappingstep',
this.editor.configObj.curConfig.snappingStep
);
)
$editDialog.setAttribute(
"gridcolor",
'gridcolor',
this.editor.configObj.curConfig.gridColor
);
$editDialog.setAttribute("canvasbg", canvasBg);
$editDialog.setAttribute("dialog", "open");
)
$editDialog.setAttribute('canvasbg', canvasBg)
$editDialog.setAttribute('dialog', 'open')
}
/**
*
* @returns {void}
*/
openHomePage() {
window.open(homePage, "_blank");
openHomePage () {
window.open(homePage, '_blank')
}
/**
* @type {module}
*/
init() {
init () {
// add Top panel
const template = document.createElement("template");
const template = document.createElement('template')
template.innerHTML = `
<se-menu id="main_button" label="SVG-Edit" src="logo.svg" alt="logo">
<se-menu-item id="tool_export" label="tools.export_img" src="export.svg"></se-menu-item>
<se-menu-item id="tool_docprops" label="tools.docprops" shortcut="D" src="docprop.svg"></se-menu-item>
<se-menu-item id="tool_editor_prefs" label="config.editor_prefs" src="editPref.svg"></se-menu-item>
<se-menu-item id="tool_editor_homepage" label="tools.editor_homepage" src="logo.svg"></se-menu-item>
</se-menu>`;
this.editor.$svgEditor.append(template.content.cloneNode(true));
</se-menu>`
this.editor.$svgEditor.append(template.content.cloneNode(true))
// register action to main menu entries
/**
* Associate all button actions as well as non-button keyboard shortcuts.
*/
$id("tool_export").addEventListener("click", function() {
$id('tool_export').addEventListener('click', function () {
document
.getElementById("se-export-dialog")
.setAttribute("dialog", "open");
});
$id("se-export-dialog").addEventListener(
"change",
.getElementById('se-export-dialog')
.setAttribute('dialog', 'open')
})
$id('se-export-dialog').addEventListener(
'change',
this.clickExport.bind(this)
);
$id("tool_docprops").addEventListener(
"click",
)
$id('tool_docprops').addEventListener(
'click',
this.showDocProperties.bind(this)
);
$id("tool_editor_prefs").addEventListener(
"click",
)
$id('tool_editor_prefs').addEventListener(
'click',
this.showPreferences.bind(this)
);
$id("tool_editor_homepage").addEventListener(
"click",
)
$id('tool_editor_homepage').addEventListener(
'click',
this.openHomePage.bind(this)
);
$id("se-img-prop").addEventListener(
"change",
function(e) {
if (e.detail.dialog === "closed") {
this.hideDocProperties();
)
$id('se-img-prop').addEventListener(
'change',
function (e) {
if (e.detail.dialog === 'closed') {
this.hideDocProperties()
} else {
this.saveDocProperties(e);
this.saveDocProperties(e)
}
}.bind(this)
);
$id("se-edit-prefs").addEventListener(
"change",
function(e) {
if (e.detail.dialog === "closed") {
this.hidePreferences();
)
$id('se-edit-prefs').addEventListener(
'change',
function (e) {
if (e.detail.dialog === 'closed') {
this.hidePreferences()
} else {
this.savePreferences(e);
this.savePreferences(e)
}
}.bind(this)
);
)
}
}
export default MainMenu;
export default MainMenu

View File

@@ -1,6 +1,6 @@
import { getTypeMap } from '../common/units.js';
import rulersTemplate from './templates/rulersTemplate.html';
import SvgCanvas from '../svgcanvas/svgcanvas.js';
import { getTypeMap } from '../common/units.js'
import rulersTemplate from './templates/rulersTemplate.html'
import SvgCanvas from '../svgcanvas/svgcanvas.js'
/**
*
*/
@@ -10,41 +10,42 @@ class Rulers {
*/
constructor (editor) {
// Make [1,2,5] array
this.rulerIntervals = [];
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.rulerIntervals.push(i)
this.rulerIntervals.push(2 * i)
this.rulerIntervals.push(5 * i)
}
this.svgCanvas = editor.svgCanvas;
this.editor = editor;
this.svgCanvas = editor.svgCanvas
this.editor = editor
// add rulers component to the DOM
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = rulersTemplate;
this.editor.$svgEditor.append(template.content.cloneNode(true));
const { $id } = SvgCanvas;
this.rulerX = $id('ruler_x');
this.rulerY = $id('ruler_y');
this.rulerCorner = $id('ruler_corner');
const template = document.createElement('template')
template.innerHTML = rulersTemplate
this.editor.$svgEditor.append(template.content.cloneNode(true))
const { $id } = SvgCanvas
this.rulerX = $id('ruler_x')
this.rulerY = $id('ruler_y')
this.rulerCorner = $id('ruler_corner')
}
display (on) {
if (on) {
this.rulerX.style.removeProperty('display');
this.rulerY.style.removeProperty('display');
this.rulerCorner.style.removeProperty('display');
this.rulerX.style.removeProperty('display')
this.rulerY.style.removeProperty('display')
this.rulerCorner.style.removeProperty('display')
} else {
this.rulerX.style.display = 'none';
this.rulerY.style.display = 'none';
this.rulerCorner.style.display = 'none';
this.rulerX.style.display = 'none'
this.rulerY.style.display = 'none'
this.rulerCorner.style.display = 'none'
}
}
/**
* @type {Module}
*/
manageScroll () {
if (this.rulerX) this.rulerX.scrollLeft = this.editor.workarea.scrollLeft;
if (this.rulerY) this.rulerY.scrollTop = this.editor.workarea.scrollTop;
if (this.rulerX) this.rulerX.scrollLeft = this.editor.workarea.scrollLeft
if (this.rulerY) this.rulerY.scrollTop = this.editor.workarea.scrollTop
}
/**
@@ -54,165 +55,165 @@ class Rulers {
* @returns {void}
*/
updateRulers (scanvas, zoom) {
if (!zoom) { zoom = this.svgCanvas.getZoom(); }
if (!scanvas) { scanvas = document.getElementById('svgcanvas'); }
if (!zoom) { zoom = this.svgCanvas.getZoom() }
if (!scanvas) { scanvas = document.getElementById('svgcanvas') }
let d; let i;
const limit = 30000;
const contentElem = this.svgCanvas.getSvgContent();
const units = getTypeMap();
const unit = units[this.editor.configObj.curConfig.baseUnit]; // 1 = 1px
let d; let i
const limit = 30000
const contentElem = this.svgCanvas.getSvgContent()
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 { $id } = SvgCanvas;
const $hcanvOrig = $id('ruler_' + dim).querySelector('canvas');
const isX = (d === 0)
const dim = isX ? 'x' : 'y'
const lentype = isX ? 'width' : 'height'
const contentDim = Number(contentElem.getAttribute(dim))
const { $id } = SvgCanvas
const $hcanvOrig = $id('ruler_' + dim).querySelector('canvas')
// Bit of a hack to fully clear the canvas in Safari & IE9
const $hcanv = $hcanvOrig.cloneNode(true);
$hcanvOrig.replaceWith($hcanv);
const $hcanv = $hcanvOrig.cloneNode(true)
$hcanvOrig.replaceWith($hcanv)
const hcanv = $hcanv;
const hcanv = $hcanv
// Set the canvas size to the width of the container
let rulerLen;
if(lentype === 'width'){
rulerLen = parseFloat(getComputedStyle(scanvas, null).width.replace("px", ""));
} else if(lentype === 'height'){
rulerLen = parseFloat(getComputedStyle(scanvas, null).height.replace("px", ""));
let rulerLen
if (lentype === 'width') {
rulerLen = parseFloat(getComputedStyle(scanvas, null).width.replace('px', ''))
} else if (lentype === 'height') {
rulerLen = parseFloat(getComputedStyle(scanvas, null).height.replace('px', ''))
}
const totalLen = rulerLen;
hcanv.parentNode.style[lentype] = totalLen + 'px';
let ctx = hcanv.getContext('2d');
let ctxArr; let num; let ctxArrNum;
const totalLen = rulerLen
hcanv.parentNode.style[lentype] = totalLen + 'px'
let ctx = hcanv.getContext('2d')
let ctxArr; let num; let ctxArrNum
ctx.fillStyle = 'rgb(200,0,0)';
ctx.fillRect(0, 0, hcanv.width, hcanv.height);
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(0, 0, hcanv.width, hcanv.height)
// Remove any existing canvasses
const elements = Array.prototype.filter.call($hcanv.parentNode.children, function(child){
return child !== $hcanv;
});
Array.from(elements).forEach(function(element) {
element.remove();
});
const elements = Array.prototype.filter.call($hcanv.parentNode.children, function (child) {
return child !== $hcanv
})
Array.from(elements).forEach(function (element) {
element.remove()
})
// Create multiple canvases when necessary (due to browser limits)
if (rulerLen >= limit) {
ctxArrNum = Number.parseInt(rulerLen / limit) + 1;
ctxArr = [];
ctxArr[0] = ctx;
let copy;
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');
hcanv[lentype] = limit
copy = hcanv.cloneNode(true)
hcanv.parentNode.append(copy)
ctxArr[i] = copy.getContext('2d')
}
copy[lentype] = rulerLen % limit;
copy[lentype] = rulerLen % limit
// set copy width to last
rulerLen = limit;
rulerLen = limit
}
hcanv[lentype] = rulerLen;
hcanv[lentype] = rulerLen
const uMulti = unit * zoom;
const uMulti = unit * zoom
// Calculate the main number interval
const rawM = 50 / uMulti;
let multi = 1;
const rawM = 50 / uMulti
let multi = 1
for (i = 0; i < this.rulerIntervals.length; i++) {
num = this.rulerIntervals[i];
multi = num;
num = this.rulerIntervals[i]
multi = num
if (rawM <= num) {
break;
break
}
}
const bigInt = multi * uMulti;
const bigInt = multi * uMulti
ctx.font = '9px sans-serif';
ctx.font = '9px sans-serif'
let rulerD = ((contentDim / uMulti) % multi) * uMulti;
let labelPos = rulerD - bigInt;
let rulerD = ((contentDim / uMulti) % multi) * uMulti
let labelPos = rulerD - bigInt
// draw big intervals
let ctxNum = 0;
let ctxNum = 0
while (rulerD < totalLen) {
labelPos += bigInt;
labelPos += bigInt
// const realD = rulerD - contentDim; // Currently unused
const curD = Math.round(rulerD) + 0.5;
const curD = Math.round(rulerD) + 0.5
if (isX) {
ctx.moveTo(curD, 15);
ctx.lineTo(curD, 0);
ctx.moveTo(curD, 15)
ctx.lineTo(curD, 0)
} else {
ctx.moveTo(15, curD);
ctx.lineTo(0, curD);
ctx.moveTo(15, curD)
ctx.lineTo(0, curD)
}
num = (labelPos - contentDim) / uMulti;
let label;
num = (labelPos - contentDim) / uMulti
let label
if (multi >= 1) {
label = Math.round(num);
label = Math.round(num)
} else {
const decs = String(multi).split('.')[1].length;
label = num.toFixed(decs);
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';
label = (label / 1000) + 'K'
}
if (isX) {
ctx.fillText(label, rulerD + 2, 8);
ctx.fillText(label, rulerD + 2, 8)
} else {
// draw label vertically
const str = String(label).split('');
const str = String(label).split('')
for (i = 0; i < str.length; i++) {
ctx.fillText(str[i], 1, (rulerD + 9) + i * 9);
ctx.fillText(str[i], 1, (rulerD + 9) + i * 9)
}
}
const part = bigInt / 10;
const part = bigInt / 10
// draw the small intervals
for (i = 1; i < 10; i++) {
let subD = Math.round(rulerD + part * i) + 0.5;
let subD = Math.round(rulerD + part * i) + 0.5
if (ctxArr && subD > rulerLen) {
ctxNum++;
ctx.stroke();
ctxNum++
ctx.stroke()
if (ctxNum >= ctxArrNum) {
i = 10;
rulerD = totalLen;
continue;
i = 10
rulerD = totalLen
continue
}
ctx = ctxArr[ctxNum];
rulerD -= limit;
subD = Math.round(rulerD + part * i) + 0.5;
ctx = ctxArr[ctxNum]
rulerD -= limit
subD = Math.round(rulerD + part * i) + 0.5
}
// odd lines are slighly longer
const lineNum = (i % 2) ? 12 : 10;
const lineNum = (i % 2) ? 12 : 10
if (isX) {
ctx.moveTo(subD, 15);
ctx.lineTo(subD, lineNum);
ctx.moveTo(subD, 15)
ctx.lineTo(subD, lineNum)
} else {
ctx.moveTo(15, subD);
ctx.lineTo(lineNum, subD);
ctx.moveTo(15, subD)
ctx.lineTo(lineNum, subD)
}
}
rulerD += bigInt;
rulerD += bigInt
}
ctx.strokeStyle = '#000';
ctx.stroke();
ctx.strokeStyle = '#000'
ctx.stroke()
}
}
}
export default Rulers;
export default Rulers

View File

@@ -1,8 +1,8 @@
const supportsSvg = function () {
return Boolean(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
};
return Boolean(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect)
}
if (!supportsSvg()) {
window.location = './browser-not-supported.html';
window.location = './browser-not-supported.html'
}
export {};
export {}

View File

@@ -1,4 +1,4 @@
import { jGraduate } from './jgraduate/jQuery.jGraduate.js';
import { jGraduate } from './jgraduate/jQuery.jGraduate.js'
/**
*
*/
@@ -16,17 +16,17 @@ class PaintBox {
<defs><linearGradient id="gradbox_${PaintBox.ctr++}"/></defs>
</svg>`,
'text/xml'
);
)
let docElem = svgdocbox.documentElement;
docElem = document.importNode(docElem, true);
container.appendChild(docElem);
let docElem = svgdocbox.documentElement
docElem = document.importNode(docElem, true)
container.appendChild(docElem)
this.rect = docElem.firstElementChild;
this.defs = docElem.getElementsByTagName('defs')[0];
this.grad = this.defs.firstElementChild;
this.rect = docElem.firstElementChild
this.defs = docElem.getElementsByTagName('defs')[0]
this.grad = this.defs.firstElementChild
// this.paint = new $.jGraduate.Paint({solidColor: color});
this.type = type;
this.type = type
}
/**
@@ -34,30 +34,31 @@ class PaintBox {
* @returns {void}
*/
setPaint (paint) {
this.paint = paint;
this.paint = paint
const ptype = paint.type;
const opac = paint.alpha / 100;
const ptype = paint.type
const opac = paint.alpha / 100
let fillAttr = 'none';
let fillAttr = 'none'
switch (ptype) {
case 'solidColor':
fillAttr = (paint[ptype] !== 'none') ? '#' + paint[ptype] : paint[ptype];
break;
case 'linearGradient':
case 'radialGradient': {
this.grad.remove();
this.grad = paint[ptype];
this.defs.appendChild(this.grad);
const id = this.grad.id = 'gradbox_' + this.type;
fillAttr = 'url(#' + id + ')';
break;
}
case 'solidColor':
fillAttr = (paint[ptype] !== 'none') ? '#' + paint[ptype] : paint[ptype]
break
case 'linearGradient':
case 'radialGradient': {
this.grad.remove()
this.grad = paint[ptype]
this.defs.appendChild(this.grad)
const id = this.grad.id = 'gradbox_' + this.type
fillAttr = 'url(#' + id + ')'
break
}
}
this.rect.setAttribute('fill', fillAttr);
this.rect.setAttribute('opacity', opac);
this.rect.setAttribute('fill', fillAttr)
this.rect.setAttribute('opacity', opac)
}
/**
* @param {PlainObject} svgCanvas
* @param {string} color
@@ -67,20 +68,20 @@ class PaintBox {
*/
static getPaint (svgCanvas, color, opac, type) {
// update the editor's fill paint
const opts = { alpha: opac };
const opts = { alpha: opac }
if (color.startsWith('url(#')) {
let refElem = svgCanvas.getRefElem(color);
refElem = (refElem) ? refElem.cloneNode(true) : document.querySelectorAll('#' + type + '_color defs *')[0];
let refElem = svgCanvas.getRefElem(color)
refElem = (refElem) ? refElem.cloneNode(true) : document.querySelectorAll('#' + type + '_color defs *')[0]
if (!refElem) {
console.error(`the color ${color} is referenced by an url that can't be identified - using 'none'`);
opts.solidColor = 'none';
console.error(`the color ${color} is referenced by an url that can't be identified - using 'none'`)
opts.solidColor = 'none'
} else {
opts[refElem.tagName] = refElem;
opts[refElem.tagName] = refElem
}
} else if (color.startsWith('#')) {
opts.solidColor = color.substr(1);
opts.solidColor = color.substr(1)
}
return new jGraduate.Paint(opts);
return new jGraduate.Paint(opts)
}
/**
@@ -89,59 +90,59 @@ class PaintBox {
* @returns {any}
*/
update (svgcanvas, selectedElement) {
if (!selectedElement) { return null; }
if (!selectedElement) { return null }
const { type } = this;
const { type } = this
switch (selectedElement.tagName) {
case 'use':
case 'image':
case 'foreignObject':
case 'use':
case 'image':
case 'foreignObject':
// These elements don't have fill or stroke, so don't change
// the current value
return null;
case 'g':
case 'a': {
const childs = selectedElement.getElementsByTagName('*');
return null
case 'g':
case 'a': {
const childs = selectedElement.getElementsByTagName('*')
let gPaint = null;
for (let i = 0, len = childs.length; i < len; i++) {
const elem = childs[i];
const p = elem.getAttribute(type);
if (i === 0) {
gPaint = p;
} else if (gPaint !== p) {
gPaint = null;
break;
let gPaint = null
for (let i = 0, len = childs.length; i < len; i++) {
const elem = childs[i]
const p = elem.getAttribute(type)
if (i === 0) {
gPaint = p
} else if (gPaint !== p) {
gPaint = null
break
}
}
}
if (gPaint === null) {
if (gPaint === null) {
// No common color, don't update anything
this._paintColor = null;
return null;
}
this._paintColor = gPaint;
this._paintOpacity = 1;
break;
} default: {
this._paintOpacity = Number.parseFloat(selectedElement.getAttribute(type + '-opacity'));
if (Number.isNaN(this._paintOpacity)) {
this._paintOpacity = 1.0;
}
this._paintColor = null
return null
}
this._paintColor = gPaint
this._paintOpacity = 1
break
} default: {
this._paintOpacity = Number.parseFloat(selectedElement.getAttribute(type + '-opacity'))
if (Number.isNaN(this._paintOpacity)) {
this._paintOpacity = 1.0
}
const defColor = type === 'fill' ? 'black' : 'none';
this._paintColor = selectedElement.getAttribute(type) || defColor;
}
const defColor = type === 'fill' ? 'black' : 'none'
this._paintColor = selectedElement.getAttribute(type) || defColor
}
}
this._paintOpacity *= 100;
this._paintOpacity *= 100
const paint = PaintBox.getPaint(svgcanvas, this._paintColor, this._paintOpacity, type);
const paint = PaintBox.getPaint(svgcanvas, this._paintColor, this._paintOpacity, type)
// update the rect inside #fill_color/#stroke_color
this.setPaint(paint);
return (paint);
this.setPaint(paint)
return (paint)
}
}
PaintBox.ctr = 0;
PaintBox.ctr = 0
export default PaintBox;
export default PaintBox

View File

@@ -1,15 +1,14 @@
import './seButton.js';
import './seFlyingButton.js';
import './seExplorerButton.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';
import './seSelect.js';
import './seText.js';
import './seButton.js'
import './seFlyingButton.js'
import './seExplorerButton.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'
import './seSelect.js'
import './seText.js'

View File

@@ -8,8 +8,8 @@
* @returns {Float}
*/
function toFixedNumeric (value, precision) {
if (precision === undefined) precision = 0;
return Math.round(value * (10 ** precision)) / (10 ** precision);
if (precision === undefined) precision = 0
return Math.round(value * (10 ** precision)) / (10 ** precision)
}
/**
* Whether a value is `null` or `undefined`.
@@ -17,8 +17,8 @@ function toFixedNumeric (value, precision) {
* @returns {boolean}
*/
const isNullish = (val) => {
return val === null || val === undefined;
};
return val === null || val === undefined
}
/**
* Controls for all the input elements for the typing in color values.
*/
@@ -30,8 +30,8 @@ export default class ColorValuePicker {
* @param {Float} alphaPrecision
*/
constructor (picker, color, bindedHex, alphaPrecision) {
const that = this; // private properties and methods
const inputs = picker.querySelectorAll('td.Text input');
const that = this // private properties and methods
const inputs = picker.querySelectorAll('td.Text input')
// input box key down - use arrows to alter color
/**
*
@@ -39,95 +39,95 @@ export default class ColorValuePicker {
* @returns {Event|false|void}
*/
function keyDown (e) {
if (e.target.value === '' && e.target !== hex && ((!isNullish(bindedHex) && e.target !== bindedHex) || isNullish(bindedHex))) return undefined;
if (!validateKey(e)) return e;
if (e.target.value === '' && e.target !== hex && ((!isNullish(bindedHex) && e.target !== bindedHex) || isNullish(bindedHex))) return undefined
if (!validateKey(e)) return e
switch (e.target) {
case red:
switch (e.keyCode) {
case 38:
red.value = setValueInRange.call(that, (red.value << 0) + 1, 0, 255);
color.val('r', red.value, e.target);
return false;
case 40:
red.value = setValueInRange.call(that, (red.value << 0) - 1, 0, 255);
color.val('r', red.value, e.target);
return false;
}
break;
case green:
switch (e.keyCode) {
case 38:
green.value = setValueInRange.call(that, (green.value << 0) + 1, 0, 255);
color.val('g', green.value, e.target);
return false;
case 40:
green.value = setValueInRange.call(that, (green.value << 0) - 1, 0, 255);
color.val('g', green.value, e.target);
return false;
}
break;
case blue:
switch (e.keyCode) {
case 38:
blue.value = setValueInRange.call(that, (blue.value << 0) + 1, 0, 255);
color.val('b', blue.value, e.target);
return false;
case 40:
blue.value = setValueInRange.call(that, (blue.value << 0) - 1, 0, 255);
color.val('b', blue.value, e.target);
return false;
}
break;
case alpha:
switch (e.keyCode) {
case 38:
alpha.value = setValueInRange.call(that, Number.parseFloat(alpha.value) + 1, 0, 100);
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target);
return false;
case 40:
alpha.value = setValueInRange.call(that, Number.parseFloat(alpha.value) - 1, 0, 100);
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target);
return false;
}
break;
case hue:
switch (e.keyCode) {
case 38:
hue.value = setValueInRange.call(that, (hue.value << 0) + 1, 0, 360);
color.val('h', hue.value, e.target);
return false;
case 40:
hue.value =setValueInRange.call(that, (hue.value << 0) - 1, 0, 360);
color.val('h', hue.value, e.target);
return false;
}
break;
case saturation:
switch (e.keyCode) {
case 38:
saturation.value = setValueInRange.call(that, (saturation.value << 0) + 1, 0, 100);
color.val('s', saturation.value, e.target);
return false;
case 40:
saturation.value = setValueInRange.call(that, (saturation.value << 0) - 1, 0, 100);
color.val('s', saturation.value, e.target);
return false;
}
break;
case value:
switch (e.keyCode) {
case 38:
value.value = setValueInRange.call(that, (value.value << 0) + 1, 0, 100);
color.val('v', value.value, e.target);
return false;
case 40:
value.value = setValueInRange.call(that, (value.value << 0) - 1, 0, 100);
color.val('v', value.value, e.target);
return false;
}
break;
case red:
switch (e.keyCode) {
case 38:
red.value = setValueInRange.call(that, (red.value << 0) + 1, 0, 255)
color.val('r', red.value, e.target)
return false
case 40:
red.value = setValueInRange.call(that, (red.value << 0) - 1, 0, 255)
color.val('r', red.value, e.target)
return false
}
break
case green:
switch (e.keyCode) {
case 38:
green.value = setValueInRange.call(that, (green.value << 0) + 1, 0, 255)
color.val('g', green.value, e.target)
return false
case 40:
green.value = setValueInRange.call(that, (green.value << 0) - 1, 0, 255)
color.val('g', green.value, e.target)
return false
}
break
case blue:
switch (e.keyCode) {
case 38:
blue.value = setValueInRange.call(that, (blue.value << 0) + 1, 0, 255)
color.val('b', blue.value, e.target)
return false
case 40:
blue.value = setValueInRange.call(that, (blue.value << 0) - 1, 0, 255)
color.val('b', blue.value, e.target)
return false
}
break
case alpha:
switch (e.keyCode) {
case 38:
alpha.value = setValueInRange.call(that, Number.parseFloat(alpha.value) + 1, 0, 100)
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target)
return false
case 40:
alpha.value = setValueInRange.call(that, Number.parseFloat(alpha.value) - 1, 0, 100)
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target)
return false
}
break
case hue:
switch (e.keyCode) {
case 38:
hue.value = setValueInRange.call(that, (hue.value << 0) + 1, 0, 360)
color.val('h', hue.value, e.target)
return false
case 40:
hue.value = setValueInRange.call(that, (hue.value << 0) - 1, 0, 360)
color.val('h', hue.value, e.target)
return false
}
break
case saturation:
switch (e.keyCode) {
case 38:
saturation.value = setValueInRange.call(that, (saturation.value << 0) + 1, 0, 100)
color.val('s', saturation.value, e.target)
return false
case 40:
saturation.value = setValueInRange.call(that, (saturation.value << 0) - 1, 0, 100)
color.val('s', saturation.value, e.target)
return false
}
break
case value:
switch (e.keyCode) {
case 38:
value.value = setValueInRange.call(that, (value.value << 0) + 1, 0, 100)
color.val('v', value.value, e.target)
return false
case 40:
value.value = setValueInRange.call(that, (value.value << 0) - 1, 0, 100)
color.val('v', value.value, e.target)
return false
}
break
}
return undefined;
return undefined
}
// input box key up - validate value and set color
/**
@@ -138,53 +138,53 @@ export default class ColorValuePicker {
function keyUp (e) {
if (e.target.value === '' && e.target !== hex &&
((!isNullish(bindedHex) && e.target !== bindedHex) ||
isNullish(bindedHex))) return undefined;
if (!validateKey(e)) return e;
isNullish(bindedHex))) return undefined
if (!validateKey(e)) return e
switch (e.target) {
case red:
red.value = setValueInRange.call(that, red.value, 0, 255);
color.val('r', red.value, e.target);
break;
case green:
green.value = setValueInRange.call(that, green.value, 0, 255);
color.val('g', green.value, e.target);
break;
case blue:
blue.value = setValueInRange.call(that, blue.value, 0, 255);
color.val('b', blue.value, e.target);
break;
case alpha:
alpha.value = setValueInRange.call(that, alpha.value, 0, 100);
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target);
break;
case hue:
hue.value = setValueInRange.call(that, hue.value, 0, 360);
color.val('h', hue.value, e.target);
break;
case saturation:
saturation.value = setValueInRange.call(that, saturation.value, 0, 100);
color.val('s', saturation.value, e.target);
break;
case value:
value.value = setValueInRange.call(that, value.value, 0, 100);
color.val('v', value.value, e.target);
break;
case hex:
hex.value = hex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6);
bindedHex && bindedHex.val(hex.value);
color.val('hex', hex.value !== '' ? hex.value : null, e.target);
break;
case bindedHex:
bindedHex.value = bindedHex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6);
hex.val(bindedHex.value);
color.val('hex', bindedHex.value !== '' ? bindedHex.value : null, e.target);
break;
case ahex:
ahex.value = ahex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2);
color.val('a', !isNullish(ahex.value) ? Number.parseInt(ahex.value, 16) : null, e.target);
break;
case red:
red.value = setValueInRange.call(that, red.value, 0, 255)
color.val('r', red.value, e.target)
break
case green:
green.value = setValueInRange.call(that, green.value, 0, 255)
color.val('g', green.value, e.target)
break
case blue:
blue.value = setValueInRange.call(that, blue.value, 0, 255)
color.val('b', blue.value, e.target)
break
case alpha:
alpha.value = setValueInRange.call(that, alpha.value, 0, 100)
color.val('a', toFixedNumeric((alpha.value * 255) / 100, alphaPrecision), e.target)
break
case hue:
hue.value = setValueInRange.call(that, hue.value, 0, 360)
color.val('h', hue.value, e.target)
break
case saturation:
saturation.value = setValueInRange.call(that, saturation.value, 0, 100)
color.val('s', saturation.value, e.target)
break
case value:
value.value = setValueInRange.call(that, value.value, 0, 100)
color.val('v', value.value, e.target)
break
case hex:
hex.value = hex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)
bindedHex && bindedHex.val(hex.value)
color.val('hex', hex.value !== '' ? hex.value : null, e.target)
break
case bindedHex:
bindedHex.value = bindedHex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)
hex.val(bindedHex.value)
color.val('hex', bindedHex.value !== '' ? bindedHex.value : null, e.target)
break
case ahex:
ahex.value = ahex.value.replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)
color.val('a', !isNullish(ahex.value) ? Number.parseInt(ahex.value, 16) : null, e.target)
break
}
return undefined;
return undefined
}
// input box blur - reset to original if value empty
/**
@@ -194,44 +194,44 @@ export default class ColorValuePicker {
function blur (e) {
if (!isNullish(color.value)) {
switch (e.target) {
case red:
color.value = 'r';
red.value = color.value;
break;
case green:
color.value = 'g';
green.value = color.value;
break;
case blue:
color.value = 'b';
blue.value = color.value;
break;
case alpha:
color.value = 'a';
alpha.value = toFixedNumeric((color.value * 100) / 255, alphaPrecision);
break;
case hue:
color.value = 'h';
hue.value = color.value;
break;
case saturation:
color.value = 's';
saturation.value = color.value;
break;
case value:
color.value = 'v';
value.value = color.value;
break;
case hex:
case bindedHex:
color.value = 'hex';
hex.value = color.value;
bindedHex.value = color.value;
break;
case ahex:
color.value = 'ahex';
ahex.value = color.value.substring(6);
break;
case red:
color.value = 'r'
red.value = color.value
break
case green:
color.value = 'g'
green.value = color.value
break
case blue:
color.value = 'b'
blue.value = color.value
break
case alpha:
color.value = 'a'
alpha.value = toFixedNumeric((color.value * 100) / 255, alphaPrecision)
break
case hue:
color.value = 'h'
hue.value = color.value
break
case saturation:
color.value = 's'
saturation.value = color.value
break
case value:
color.value = 'v'
value.value = color.value
break
case hex:
case bindedHex:
color.value = 'hex'
hex.value = color.value
bindedHex.value = color.value
break
case ahex:
color.value = 'ahex'
ahex.value = color.value.substring(6)
break
}
}
}
@@ -241,17 +241,17 @@ export default class ColorValuePicker {
*/
function validateKey (e) {
switch (e.keyCode) {
case 9:
case 16:
case 29:
case 37:
case 39:
return false;
case 'c'.charCodeAt():
case 'v'.charCodeAt():
if (e.ctrlKey) return false;
case 9:
case 16:
case 29:
case 37:
case 39:
return false
case 'c'.charCodeAt():
case 'v'.charCodeAt():
if (e.ctrlKey) return false
}
return true;
return true
}
/**
@@ -262,10 +262,10 @@ export default class ColorValuePicker {
* @returns {Float|string} Returns a number or numeric string
*/
function setValueInRange (value, min, max) {
if (value === '' || isNaN(value)) return min;
if (value > max) return max;
if (value < min) return min;
return value;
if (value === '' || isNaN(value)) return min
if (value > max) return max
if (value < min) return min
return value
}
/**
* @param {external:jQuery} ui
@@ -273,117 +273,117 @@ export default class ColorValuePicker {
* @returns {void}
*/
function colorChanged (ui, context) {
const all = ui.val('all');
if (context !== red) red.value = (!isNullish(all) ? all.r : '');
if (context !== green) green.value = (!isNullish(all) ? all.g : '');
if (context !== blue) blue.value = (!isNullish(all) ? all.b : '');
if (alpha && context !== alpha) alpha.value = (!isNullish(all) ? toFixedNumeric((all.a * 100) / 255, alphaPrecision) : '');
if (context !== hue) hue.value = (!isNullish(all) ? all.h : '');
if (context !== saturation) saturation.value = (!isNullish(all) ? all.s : '');
if (context !== value) value.value = (!isNullish(all) ? all.v : '');
if (context !== hex && ((bindedHex && context !== bindedHex) || !bindedHex)) hex.value = (!isNullish(all) ? all.hex : '');
if (bindedHex && context !== bindedHex && context !== hex) bindedHex.value = (!isNullish(all) ? all.hex : '');
if (ahex && context !== ahex) ahex.value = (!isNullish(all) ? all.ahex.substring(6) : '');
const all = ui.val('all')
if (context !== red) red.value = (!isNullish(all) ? all.r : '')
if (context !== green) green.value = (!isNullish(all) ? all.g : '')
if (context !== blue) blue.value = (!isNullish(all) ? all.b : '')
if (alpha && context !== alpha) alpha.value = (!isNullish(all) ? toFixedNumeric((all.a * 100) / 255, alphaPrecision) : '')
if (context !== hue) hue.value = (!isNullish(all) ? all.h : '')
if (context !== saturation) saturation.value = (!isNullish(all) ? all.s : '')
if (context !== value) value.value = (!isNullish(all) ? all.v : '')
if (context !== hex && ((bindedHex && context !== bindedHex) || !bindedHex)) hex.value = (!isNullish(all) ? all.hex : '')
if (bindedHex && context !== bindedHex && context !== hex) bindedHex.value = (!isNullish(all) ? all.hex : '')
if (ahex && context !== ahex) ahex.value = (!isNullish(all) ? all.ahex.substring(6) : '')
}
/**
* Unbind all events and null objects.
* @returns {void}
*/
function destroy () {
red.removeEventListener('keyup', keyUp);
green.removeEventListener('keyup', keyUp);
blue.removeEventListener('keyup', keyUp);
hue.removeEventListener('keyup', keyUp);
saturation.removeEventListener('keyup', keyUp);
value.removeEventListener('keyup', keyUp);
hex.removeEventListener('keyup', keyUp);
red.removeEventListener('keyup', keyUp)
green.removeEventListener('keyup', keyUp)
blue.removeEventListener('keyup', keyUp)
hue.removeEventListener('keyup', keyUp)
saturation.removeEventListener('keyup', keyUp)
value.removeEventListener('keyup', keyUp)
hex.removeEventListener('keyup', keyUp)
red.removeEventListener('blur', blur);
green.removeEventListener('blur', blur);
blue.removeEventListener('blur', blur);
hue.removeEventListener('blur', blur);
saturation.removeEventListener('blur', blur);
value.removeEventListener('blur', blur);
hex.removeEventListener('blur', blur);
red.removeEventListener('blur', blur)
green.removeEventListener('blur', blur)
blue.removeEventListener('blur', blur)
hue.removeEventListener('blur', blur)
saturation.removeEventListener('blur', blur)
value.removeEventListener('blur', blur)
hex.removeEventListener('blur', blur)
red.removeEventListener('keydown', keyDown);
green.removeEventListener('keydown', keyDown);
blue.removeEventListener('keydown', keyDown);
hue.removeEventListener('keydown', keyDown);
saturation.removeEventListener('keydown', keyDown);
value.removeEventListener('keydown', keyDown);
red.removeEventListener('keydown', keyDown)
green.removeEventListener('keydown', keyDown)
blue.removeEventListener('keydown', keyDown)
hue.removeEventListener('keydown', keyDown)
saturation.removeEventListener('keydown', keyDown)
value.removeEventListener('keydown', keyDown)
if (alpha !== null) {
alpha.removeEventListener('keyup', keyUp);
alpha.removeEventListener('blur', blur);
alpha.removeEventListener('keydown', keyDown);
alpha.removeEventListener('keyup', keyUp)
alpha.removeEventListener('blur', blur)
alpha.removeEventListener('keydown', keyDown)
}
if (ahex !== null) {
ahex.removeEventListener('keyup', keyUp);
ahex.removeEventListener('blur', blur);
ahex.removeEventListener('keyup', keyUp)
ahex.removeEventListener('blur', blur)
}
if (bindedHex !== null) {
bindedHex.removeEventListener('keyup', keyUp);
bindedHex.removeEventListener('blur', blur);
bindedHex.removeEventListener('keyup', keyUp)
bindedHex.removeEventListener('blur', blur)
}
color.unbind(colorChanged);
red = null;
green = null;
blue = null;
alpha = null;
hue = null;
saturation = null;
value = null;
hex = null;
ahex = null;
color.unbind(colorChanged)
red = null
green = null
blue = null
alpha = null
hue = null
saturation = null
value = null
hex = null
ahex = null
}
let
red = inputs[3];
let green = inputs[4];
let blue = inputs[5];
let alpha = inputs.length > 7 ? inputs[6] : null;
let hue = inputs[0];
let saturation = inputs[1];
let value = inputs[2];
let hex = inputs[(inputs.length > 7) ? 7 : 6];
let ahex = inputs.length > 7 ? inputs[8] : null;
Object.assign(that, { destroy });
red.addEventListener('keyup', keyUp);
green.addEventListener('keyup', keyUp);
blue.addEventListener('keyup', keyUp);
hue.addEventListener('keyup', keyUp);
saturation.addEventListener('keyup', keyUp);
value.addEventListener('keyup', keyUp);
hex.addEventListener('keyup', keyUp);
red = inputs[3]
let green = inputs[4]
let blue = inputs[5]
let alpha = inputs.length > 7 ? inputs[6] : null
let hue = inputs[0]
let saturation = inputs[1]
let value = inputs[2]
let hex = inputs[(inputs.length > 7) ? 7 : 6]
let ahex = inputs.length > 7 ? inputs[8] : null
Object.assign(that, { destroy })
red.addEventListener('keyup', keyUp)
green.addEventListener('keyup', keyUp)
blue.addEventListener('keyup', keyUp)
hue.addEventListener('keyup', keyUp)
saturation.addEventListener('keyup', keyUp)
value.addEventListener('keyup', keyUp)
hex.addEventListener('keyup', keyUp)
red.addEventListener('blur', blur);
green.addEventListener('blur', blur);
blue.addEventListener('blur', blur);
hue.addEventListener('blur', blur);
saturation.addEventListener('blur', blur);
value.addEventListener('blur', blur);
hex.addEventListener('blur', blur);
red.addEventListener('blur', blur)
green.addEventListener('blur', blur)
blue.addEventListener('blur', blur)
hue.addEventListener('blur', blur)
saturation.addEventListener('blur', blur)
value.addEventListener('blur', blur)
hex.addEventListener('blur', blur)
red.addEventListener('keydown', keyDown);
green.addEventListener('keydown', keyDown);
blue.addEventListener('keydown', keyDown);
hue.addEventListener('keydown', keyDown);
saturation.addEventListener('keydown', keyDown);
value.addEventListener('keydown', keyDown);
red.addEventListener('keydown', keyDown)
green.addEventListener('keydown', keyDown)
blue.addEventListener('keydown', keyDown)
hue.addEventListener('keydown', keyDown)
saturation.addEventListener('keydown', keyDown)
value.addEventListener('keydown', keyDown)
if (alpha !== null) {
alpha.addEventListener('keyup', keyUp);
alpha.addEventListener('blur', blur);
alpha.addEventListener('keydown', keyDown);
alpha.addEventListener('keyup', keyUp)
alpha.addEventListener('blur', blur)
alpha.addEventListener('keydown', keyDown)
}
if (ahex !== null) {
ahex.addEventListener('keyup', keyUp);
ahex.addEventListener('blur', blur);
ahex.addEventListener('keyup', keyUp)
ahex.addEventListener('blur', blur)
}
if (bindedHex !== null) {
bindedHex.addEventListener('keyup', keyUp);
bindedHex.addEventListener('blur', blur);
bindedHex.addEventListener('keyup', keyUp)
bindedHex.addEventListener('blur', blur)
}
color.bind(colorChanged);
color.bind(colorChanged)
}
}

View File

@@ -1,12 +1,12 @@
import { findPos } from './Util.js';
import { findPos } from './Util.js'
/**
* Whether a value is `null` or `undefined`.
* @param {any} val
* @returns {boolean}
*/
const isNullish = (val) => {
return val === null || val === undefined;
};
return val === null || val === undefined
}
/**
* Encapsulate slider functionality for the ColorMap and ColorBar -
* could be useful to use a jQuery UI draggable for this with certain extensions.
@@ -18,7 +18,7 @@ export default class Slider {
* @param {module:jPicker.SliderOptions} options
*/
constructor (bar, options) {
const that = this;
const that = this
/**
* Fire events on the supplied `context`
* @param {module:jPicker.JPickerInit} context
@@ -26,8 +26,8 @@ export default class Slider {
*/
function fireChangeEvents (context) {
changeEvents.forEach((changeEvent) => {
changeEvent.call(that, that, context);
});
changeEvent.call(that, that, context)
})
}
/**
@@ -36,17 +36,17 @@ export default class Slider {
* @returns {void}
*/
function mouseDown (e) {
const off = findPos(bar);
offset = { l: off.left | 0, t: off.top | 0 };
clearTimeout(timeout);
const off = findPos(bar)
offset = { l: off.left | 0, t: off.top | 0 }
clearTimeout(timeout)
// using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run
timeout = setTimeout(function () {
setValuesFromMousePosition.call(that, e);
}, 0);
setValuesFromMousePosition.call(that, e)
}, 0)
// Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing
document.addEventListener('mousemove', mouseMove);
document.addEventListener('mouseup', mouseUp);
e.preventDefault(); // don't try to select anything or drag the image to the desktop
document.addEventListener('mousemove', mouseMove)
document.addEventListener('mouseup', mouseUp)
e.preventDefault() // don't try to select anything or drag the image to the desktop
}
/**
* Set the values as the mouse moves.
@@ -54,13 +54,13 @@ export default class Slider {
* @returns {false}
*/
function mouseMove (e) {
clearTimeout(timeout);
clearTimeout(timeout)
timeout = setTimeout(function () {
setValuesFromMousePosition.call(that, e);
}, 0);
e.stopPropagation();
e.preventDefault();
return false;
setValuesFromMousePosition.call(that, e)
}, 0)
e.stopPropagation()
e.preventDefault()
return false
}
/**
* Unbind the document events - they aren't needed when not dragging.
@@ -68,11 +68,11 @@ export default class Slider {
* @returns {false}
*/
function mouseUp (e) {
document.removeEventListener('mousemove', mouseMove);
document.removeEventListener('mouseup', mouseUp);
e.stopPropagation();
e.preventDefault();
return false;
document.removeEventListener('mousemove', mouseMove)
document.removeEventListener('mouseup', mouseUp)
e.stopPropagation()
e.preventDefault()
return false
}
/**
@@ -81,19 +81,19 @@ export default class Slider {
* @returns {void}
*/
function setValuesFromMousePosition (e) {
const barW = bar.w; // local copies for YUI compressor
const barH = bar.h;
let locX = e.pageX - offset.l;
let locY = e.pageY - offset.t;
const barW = bar.w // local copies for YUI compressor
const barH = bar.h
let locX = e.pageX - offset.l
let locY = e.pageY - offset.t
// keep the arrow within the bounds of the bar
if (locX < 0) locX = 0;
else if (locX > barW) locX = barW;
if (locY < 0) locY = 0;
else if (locY > barH) locY = barH;
if (locX < 0) locX = 0
else if (locX > barW) locX = barW
if (locY < 0) locY = 0
else if (locY > barH) locY = barH
val.call(that, 'xy', {
x: ((locX / barW) * rangeX) + minX,
y: ((locY / barH) * rangeY) + minY
});
})
}
/**
*
@@ -101,33 +101,33 @@ export default class Slider {
*/
function draw () {
const
barW = bar.w;
const barH = bar.h;
const arrowW = arrow.w;
const arrowH = arrow.h;
let arrowOffsetX = 0;
let arrowOffsetY = 0;
barW = bar.w
const barH = bar.h
const arrowW = arrow.w
const arrowH = arrow.h
let arrowOffsetX = 0
let arrowOffsetY = 0
setTimeout(function () {
if (rangeX > 0) { // range is greater than zero
// constrain to bounds
if (x === maxX) arrowOffsetX = barW;
else arrowOffsetX = ((x / rangeX) * barW) | 0;
if (x === maxX) arrowOffsetX = barW
else arrowOffsetX = ((x / rangeX) * barW) | 0
}
if (rangeY > 0) { // range is greater than zero
// constrain to bounds
if (y === maxY) arrowOffsetY = barH;
else arrowOffsetY = ((y / rangeY) * barH) | 0;
if (y === maxY) arrowOffsetY = barH
else arrowOffsetY = ((y / rangeY) * barH) | 0
}
// if arrow width is greater than bar width, center arrow and prevent horizontal dragging
if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest)
else arrowOffsetX -= arrowW >> 1;
if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1) // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest)
else arrowOffsetX -= arrowW >> 1
// if arrow height is greater than bar height, center arrow and prevent vertical dragging
if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1);
else arrowOffsetY -= arrowH >> 1;
if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1)
else arrowOffsetY -= arrowH >> 1
// set the arrow position based on these offsets
arrow.style.left = arrowOffsetX + 'px';
arrow.style.top = arrowOffsetY + 'px';
});
arrow.style.left = arrowOffsetX + 'px'
arrow.style.top = arrowOffsetY + 'px'
})
}
/**
@@ -138,52 +138,52 @@ export default class Slider {
* @returns {module:math.XYObject|Float|void}
*/
function val (name, value, context) {
const set = value !== undefined;
const set = value !== undefined
if (!set) {
if (isNullish(name)) name = 'xy';
if (isNullish(name)) name = 'xy'
switch (name.toLowerCase()) {
case 'x': return x;
case 'y': return y;
case 'xy':
default: return { x, y };
case 'x': return x
case 'y': return y
case 'xy':
default: return { x, y }
}
}
if (!isNullish(context) && context === that) return undefined;
let changed = false;
if (!isNullish(context) && context === that) return undefined
let changed = false
let newX; let newY;
if (isNullish(name)) name = 'xy';
let newX; let newY
if (isNullish(name)) name = 'xy'
switch (name.toLowerCase()) {
case 'x':
newX = (value && ((value.x && value.x | 0) || value | 0)) || 0;
break;
case 'y':
newY = (value && ((value.y && value.y | 0) || value | 0)) || 0;
break;
case 'xy':
default:
newX = (value && value.x && value.x | 0) || 0;
newY = (value && value.y && value.y | 0) || 0;
break;
case 'x':
newX = (value && ((value.x && value.x | 0) || value | 0)) || 0
break
case 'y':
newY = (value && ((value.y && value.y | 0) || value | 0)) || 0
break
case 'xy':
default:
newX = (value && value.x && value.x | 0) || 0
newY = (value && value.y && value.y | 0) || 0
break
}
if (!isNullish(newX)) {
if (newX < minX) newX = minX;
else if (newX > maxX) newX = maxX;
if (newX < minX) newX = minX
else if (newX > maxX) newX = maxX
if (x !== newX) {
x = newX;
changed = true;
x = newX
changed = true
}
}
if (!isNullish(newY)) {
if (newY < minY) newY = minY;
else if (newY > maxY) newY = maxY;
if (newY < minY) newY = minY
else if (newY > maxY) newY = maxY
if (y !== newY) {
y = newY;
changed = true;
y = newY
changed = true
}
}
changed && fireChangeEvents.call(that, context || that);
return undefined;
changed && fireChangeEvents.call(that, context || that)
return undefined
}
/**
@@ -209,89 +209,89 @@ export default class Slider {
* @returns {module:jPicker.MinMaxRangeXY|module:jPicker.MinMaxRangeX|module:jPicker.MinMaxRangeY|void}
*/
function range (name, value) {
const set = value !== undefined;
const set = value !== undefined
if (!set) {
if (isNullish(name)) name = 'all';
if (isNullish(name)) name = 'all'
switch (name.toLowerCase()) {
case 'minx': return minX;
case 'maxx': return maxX;
case 'rangex': return { minX, maxX, rangeX };
case 'miny': return minY;
case 'maxy': return maxY;
case 'rangey': return { minY, maxY, rangeY };
case 'all':
default: return { minX, maxX, rangeX, minY, maxY, rangeY };
case 'minx': return minX
case 'maxx': return maxX
case 'rangex': return { minX, maxX, rangeX }
case 'miny': return minY
case 'maxy': return maxY
case 'rangey': return { minY, maxY, rangeY }
case 'all':
default: return { minX, maxX, rangeX, minY, maxY, rangeY }
}
}
let // changed = false,
newMinX;
let newMaxX;
let newMinY;
let newMaxY;
if (isNullish(name)) name = 'all';
newMinX
let newMaxX
let newMinY
let newMaxY
if (isNullish(name)) name = 'all'
switch (name.toLowerCase()) {
case 'minx':
newMinX = (value && ((value.minX && value.minX | 0) || value | 0)) || 0;
break;
case 'maxx':
newMaxX = (value && ((value.maxX && value.maxX | 0) || value | 0)) || 0;
break;
case 'rangex':
newMinX = (value && value.minX && value.minX | 0) || 0;
newMaxX = (value && value.maxX && value.maxX | 0) || 0;
break;
case 'miny':
newMinY = (value && ((value.minY && value.minY | 0) || value | 0)) || 0;
break;
case 'maxy':
newMaxY = (value && ((value.maxY && value.maxY | 0) || value | 0)) || 0;
break;
case 'rangey':
newMinY = (value && value.minY && value.minY | 0) || 0;
newMaxY = (value && value.maxY && value.maxY | 0) || 0;
break;
case 'all':
default:
newMinX = (value && value.minX && value.minX | 0) || 0;
newMaxX = (value && value.maxX && value.maxX | 0) || 0;
newMinY = (value && value.minY && value.minY | 0) || 0;
newMaxY = (value && value.maxY && value.maxY | 0) || 0;
break;
case 'minx':
newMinX = (value && ((value.minX && value.minX | 0) || value | 0)) || 0
break
case 'maxx':
newMaxX = (value && ((value.maxX && value.maxX | 0) || value | 0)) || 0
break
case 'rangex':
newMinX = (value && value.minX && value.minX | 0) || 0
newMaxX = (value && value.maxX && value.maxX | 0) || 0
break
case 'miny':
newMinY = (value && ((value.minY && value.minY | 0) || value | 0)) || 0
break
case 'maxy':
newMaxY = (value && ((value.maxY && value.maxY | 0) || value | 0)) || 0
break
case 'rangey':
newMinY = (value && value.minY && value.minY | 0) || 0
newMaxY = (value && value.maxY && value.maxY | 0) || 0
break
case 'all':
default:
newMinX = (value && value.minX && value.minX | 0) || 0
newMaxX = (value && value.maxX && value.maxX | 0) || 0
newMinY = (value && value.minY && value.minY | 0) || 0
newMaxY = (value && value.maxY && value.maxY | 0) || 0
break
}
if (!isNullish(newMinX) && minX !== newMinX) {
minX = newMinX;
rangeX = maxX - minX;
minX = newMinX
rangeX = maxX - minX
}
if (!isNullish(newMaxX) && maxX !== newMaxX) {
maxX = newMaxX;
rangeX = maxX - minX;
maxX = newMaxX
rangeX = maxX - minX
}
if (!isNullish(newMinY) && minY !== newMinY) {
minY = newMinY;
rangeY = maxY - minY;
minY = newMinY
rangeY = maxY - minY
}
if (!isNullish(newMaxY) && maxY !== newMaxY) {
maxY = newMaxY;
rangeY = maxY - minY;
maxY = newMaxY
rangeY = maxY - minY
}
return undefined;
return undefined
}
/**
* @param {GenericCallback} callback
* @returns {void}
*/
function bind (callback) {
if (typeof callback === 'function') changeEvents.push(callback);
if (typeof callback === 'function') changeEvents.push(callback)
}
/**
* @param {GenericCallback} callback
* @returns {void}
*/
function unbind (callback) {
if (typeof callback !== 'function') return;
let i;
while ((i = changeEvents.includes(callback))) changeEvents.splice(i, 1);
if (typeof callback !== 'function') return
let i
while ((i = changeEvents.includes(callback))) changeEvents.splice(i, 1)
}
/**
*
@@ -299,39 +299,39 @@ export default class Slider {
*/
function destroy () {
// unbind all possible events and null objects
document.removeEventListener('mousemove', mouseMove);
document.removeEventListener('mouseup', mouseUp);
bar.removeEventListener('mousedown', mouseDown);
bar = null;
arrow = null;
changeEvents = null;
document.removeEventListener('mousemove', mouseMove)
document.removeEventListener('mouseup', mouseUp)
bar.removeEventListener('mousedown', mouseDown)
bar = null
arrow = null
changeEvents = null
}
let offset;
let timeout;
let x = 0;
let y = 0;
let minX = 0;
let maxX = 100;
let rangeX = 100;
let minY = 0;
let maxY = 100;
let rangeY = 100;
let arrow = bar.querySelector('img'); // the arrow image to drag
let changeEvents = [];
let offset
let timeout
let x = 0
let y = 0
let minX = 0
let maxX = 100
let rangeX = 100
let minY = 0
let maxY = 100
let rangeY = 100
let arrow = bar.querySelector('img') // the arrow image to drag
let changeEvents = []
Object.assign(that, {
val,
range,
bind,
unbind,
destroy
});
})
// initialize this control
arrow.src = options.arrow && options.arrow.image;
arrow.w = (options.arrow && options.arrow.width) || parseFloat(getComputedStyle(arrow, null).width.replace("px", ""));
arrow.h = (options.arrow && options.arrow.height) || parseFloat(getComputedStyle(arrow, null).height.replace("px", ""));
bar.w = (options.map && options.map.width) || parseFloat(getComputedStyle(bar, null).width.replace("px", ""));
bar.h = (options.map && options.map.height) || parseFloat(getComputedStyle(bar, null).height.replace("px", ""));
bar.addEventListener('mousedown', mouseDown);
bind.call(that, draw);
arrow.src = options.arrow && options.arrow.image
arrow.w = (options.arrow && options.arrow.width) || parseFloat(getComputedStyle(arrow, null).width.replace('px', ''))
arrow.h = (options.arrow && options.arrow.height) || parseFloat(getComputedStyle(arrow, null).height.replace('px', ''))
bar.w = (options.map && options.map.width) || parseFloat(getComputedStyle(bar, null).width.replace('px', ''))
bar.h = (options.map && options.map.height) || parseFloat(getComputedStyle(bar, null).height.replace('px', ''))
bar.addEventListener('mousedown', mouseDown)
bind.call(that, draw)
}
}

View File

@@ -2,39 +2,36 @@
* @param {any} obj
* @returns {any}
*/
export function findPos(obj) {
let curleft = 0;
let curtop = 0;
export function findPos (obj) {
let curleft = 0
let curtop = 0
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
curleft += obj.offsetLeft
curtop += obj.offsetTop
// eslint-disable-next-line no-cond-assign
} while (obj = obj.offsetParent);
return { left: curleft, top: curtop };
} while (obj = obj.offsetParent)
return { left: curleft, top: curtop }
}
return { left: curleft, top: curtop };
return { left: curleft, top: curtop }
}
export function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
export function isObject (item) {
return (item && typeof item === 'object' && !Array.isArray(item))
}
export function mergeDeep(target, source) {
const output = Object.assign({}, target);
export function mergeDeep (target, source) {
const output = Object.assign({}, target)
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target))
Object.assign(output, { [key]: source[key] });
else
output[key] = mergeDeep(target[key], source[key]);
if (!(key in target)) { Object.assign(output, { [key]: source[key] }) } else { output[key] = mergeDeep(target[key], source[key]) }
} else {
Object.assign(output, { [key]: source[key] });
Object.assign(output, { [key]: source[key] })
}
});
})
}
return output;
return output
}
/**
@@ -43,17 +40,17 @@ export function mergeDeep(target, source) {
* @param {String} selector Selector to match against (class, ID, data attribute, or tag)
* @return {Boolean|Element} Returns null if not match found
*/
export function getClosest(elem, selector) {
const firstChar = selector.charAt(0);
const supports = 'classList' in document.documentElement;
let attribute; let value;
export function getClosest (elem, selector) {
const firstChar = selector.charAt(0)
const supports = 'classList' in document.documentElement
let attribute; let value
// If selector is a data attribute, split attribute from value
if (firstChar === '[') {
selector = selector.substr(1, selector.length - 2);
attribute = selector.split('=');
selector = selector.substr(1, selector.length - 2)
attribute = selector.split('=')
if (attribute.length > 1) {
value = true;
attribute[1] = attribute[1].replace(/"/g, '').replace(/'/g, '');
value = true
attribute[1] = attribute[1].replace(/"/g, '').replace(/'/g, '')
}
}
// Get closest match
@@ -62,18 +59,18 @@ export function getClosest(elem, selector) {
if (firstChar === '.') {
if (supports) {
if (elem.classList.contains(selector.substr(1))) {
return elem;
return elem
}
} else {
if (new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test(elem.className)) {
return elem;
return elem
}
}
}
// If selector is an ID
if (firstChar === '#') {
if (elem.id === selector.substr(1)) {
return elem;
return elem
}
}
// If selector is a data attribute
@@ -81,19 +78,19 @@ export function getClosest(elem, selector) {
if (elem.hasAttribute(attribute[0])) {
if (value) {
if (elem.getAttribute(attribute[0]) === attribute[1]) {
return elem;
return elem
}
} else {
return elem;
return elem
}
}
}
// If selector is a tag
if (elem.tagName.toLowerCase() === selector) {
return elem;
return elem
}
}
return null;
return null
}
/**
@@ -102,100 +99,100 @@ export function getClosest(elem, selector) {
* @param {String} selector The class, id, data attribute, or tag to look for
* @return {Array} Null if no match
*/
export function getParents(elem, selector) {
const parents = [];
const firstChar = selector?.charAt(0);
export function getParents (elem, selector) {
const parents = []
const firstChar = selector?.charAt(0)
// Get matches
for ( ; elem && elem !== document; elem = elem.parentNode ) {
if ( selector ) {
for (; elem && elem !== document; elem = elem.parentNode) {
if (selector) {
// If selector is a class
if ( firstChar === '.' ) {
if ( elem.classList.contains( selector.substr(1) ) ) {
parents.push( elem );
if (firstChar === '.') {
if (elem.classList.contains(selector.substr(1))) {
parents.push(elem)
}
}
// If selector is an ID
if ( firstChar === '#' ) {
if ( elem.id === selector.substr(1) ) {
parents.push( elem );
if (firstChar === '#') {
if (elem.id === selector.substr(1)) {
parents.push(elem)
}
}
// If selector is a data attribute
if ( firstChar === '[' ) {
if ( elem.hasAttribute( selector.substr(1, selector.length - 1) ) ) {
parents.push( elem );
if (firstChar === '[') {
if (elem.hasAttribute(selector.substr(1, selector.length - 1))) {
parents.push(elem)
}
}
// If selector is a tag
if ( elem.tagName.toLowerCase() === selector ) {
parents.push( elem );
if (elem.tagName.toLowerCase() === selector) {
parents.push(elem)
}
} else {
parents.push( elem );
parents.push(elem)
}
}
// Return parents if any exist
return parents.length? parents : null;
return parents.length ? parents : null
}
export function getParentsUntil(elem, parent, selector) {
const parents = [];
const parentType = parent?.charAt(0);
const selectorType = selector?.selector.charAt(0);
export function getParentsUntil (elem, parent, selector) {
const parents = []
const parentType = parent?.charAt(0)
const selectorType = selector?.selector.charAt(0)
// Get matches
for ( ; elem && elem !== document; elem = elem.parentNode ) {
for (; elem && elem !== document; elem = elem.parentNode) {
// Check if parent has been reached
if ( parent ) {
if (parent) {
// If parent is a class
if ( parentType === '.' ) {
if ( elem.classList.contains( parent.substr(1) ) ) {
break;
if (parentType === '.') {
if (elem.classList.contains(parent.substr(1))) {
break
}
}
// If parent is an ID
if ( parentType === '#' ) {
if ( elem.id === parent.substr(1) ) {
break;
if (parentType === '#') {
if (elem.id === parent.substr(1)) {
break
}
}
// If parent is a data attribute
if ( parentType === '[' ) {
if ( elem.hasAttribute( parent.substr(1, parent.length - 1) ) ) {
break;
if (parentType === '[') {
if (elem.hasAttribute(parent.substr(1, parent.length - 1))) {
break
}
}
// If parent is a tag
if ( elem.tagName.toLowerCase() === parent ) {
break;
if (elem.tagName.toLowerCase() === parent) {
break
}
}
if ( selector ) {
if (selector) {
// If selector is a class
if ( selectorType === '.' ) {
if ( elem.classList.contains( selector.substr(1) ) ) {
parents.push( elem );
if (selectorType === '.') {
if (elem.classList.contains(selector.substr(1))) {
parents.push(elem)
}
}
// If selector is an ID
if ( selectorType === '#' ) {
if ( elem.id === selector.substr(1) ) {
parents.push( elem );
if (selectorType === '#') {
if (elem.id === selector.substr(1)) {
parents.push(elem)
}
}
// If selector is a data attribute
if ( selectorType === '[' ) {
if ( elem.hasAttribute( selector.substr(1, selector.length - 1) ) ) {
parents.push( elem );
if (selectorType === '[') {
if (elem.hasAttribute(selector.substr(1, selector.length - 1))) {
parents.push(elem)
}
}
// If selector is a tag
if ( elem.tagName.toLowerCase() === selector ) {
parents.push( elem );
if (elem.tagName.toLowerCase() === selector) {
parents.push(elem)
}
} else {
parents.push( elem );
parents.push(elem)
}
}
// Return parents if any exist
return parents.length? parents : null;
}
return parents.length ? parents : null
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,83 +6,83 @@ export default class Paint {
* @param {module:jGraduate.jGraduatePaintOptions} [opt]
*/
constructor (opt) {
const options = opt || {};
this.alpha = isNaN(options.alpha) ? 100 : options.alpha;
const options = opt || {}
this.alpha = isNaN(options.alpha) ? 100 : options.alpha
// copy paint object
if (options.copy) {
/**
* @name module:jGraduate~Paint#type
* @type {"none"|"solidColor"|"linearGradient"|"radialGradient"}
*/
this.type = options.copy.type;
this.type = options.copy.type
/**
* Represents opacity (0-100).
* @name module:jGraduate~Paint#alpha
* @type {Float}
*/
this.alpha = options.copy.alpha;
this.alpha = options.copy.alpha
/**
* Represents #RRGGBB hex of color.
* @name module:jGraduate~Paint#solidColor
* @type {string}
*/
this.solidColor = null;
this.solidColor = null
/**
* @name module:jGraduate~Paint#linearGradient
* @type {SVGLinearGradientElement}
*/
this.linearGradient = null;
this.linearGradient = null
/**
* @name module:jGraduate~Paint#radialGradient
* @type {SVGRadialGradientElement}
*/
this.radialGradient = null;
this.radialGradient = null
switch (this.type) {
case 'none':
break;
case 'solidColor':
this.solidColor = options.copy.solidColor;
break;
case 'linearGradient':
this.linearGradient = options.copy.linearGradient.cloneNode(true);
break;
case 'radialGradient':
this.radialGradient = options.copy.radialGradient.cloneNode(true);
break;
case 'none':
break
case 'solidColor':
this.solidColor = options.copy.solidColor
break
case 'linearGradient':
this.linearGradient = options.copy.linearGradient.cloneNode(true)
break
case 'radialGradient':
this.radialGradient = options.copy.radialGradient.cloneNode(true)
break
}
// create linear gradient paint
} else if (options.linearGradient) {
this.type = 'linearGradient';
this.solidColor = null;
this.radialGradient = null;
if(options.linearGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.linearGradient.getAttribute('xlink:href').substr(1));
this.linearGradient = xhref.cloneNode(true);
this.type = 'linearGradient'
this.solidColor = null
this.radialGradient = null
if (options.linearGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.linearGradient.getAttribute('xlink:href').substr(1))
this.linearGradient = xhref.cloneNode(true)
} else {
this.linearGradient = options.linearGradient.cloneNode(true);
this.linearGradient = options.linearGradient.cloneNode(true)
}
// create linear gradient paint
} else if (options.radialGradient) {
this.type = 'radialGradient';
this.solidColor = null;
this.linearGradient = null;
if(options.radialGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.radialGradient.getAttribute('xlink:href').substr(1));
this.radialGradient = xhref.cloneNode(true);
this.type = 'radialGradient'
this.solidColor = null
this.linearGradient = null
if (options.radialGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.radialGradient.getAttribute('xlink:href').substr(1))
this.radialGradient = xhref.cloneNode(true)
} else {
this.radialGradient = options.radialGradient.cloneNode(true);
this.radialGradient = options.radialGradient.cloneNode(true)
}
// create solid color paint
} else if (options.solidColor) {
this.type = 'solidColor';
this.solidColor = options.solidColor;
this.type = 'solidColor'
this.solidColor = options.solidColor
// create empty paint
} else {
this.type = 'none';
this.solidColor = null;
this.linearGradient = null;
this.radialGradient = null;
this.type = 'none'
this.solidColor = null
this.linearGradient = null
this.radialGradient = null
}
}
}
}

View File

@@ -1,6 +1,6 @@
/* globals svgEditor */
import { t } from '../locale.js';
const template = document.createElement('template');
import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
:host(:hover) :not(.disabled)
@@ -39,7 +39,7 @@ template.innerHTML = `
<div title="title">
<img alt="icon">
</div>
`;
`
/**
* @class ToolButton
*/
@@ -48,22 +48,24 @@ export class ToolButton extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$div = this._shadowRoot.querySelector('div');
this.$img = this._shadowRoot.querySelector('img');
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this.$div = this._shadowRoot.querySelector('div')
this.$img = this._shadowRoot.querySelector('img')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'src', 'pressed', 'disabled', 'size', 'style' ];
return ['title', 'src', 'pressed', 'disabled', 'size', 'style']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -72,56 +74,57 @@ export class ToolButton extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
{
const shortcut = this.getAttribute('shortcut');
this.$div.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`);
}
break;
case 'style':
this.$div.style = newValue;
break;
case 'src':
if (newValue.indexOf("data:") !== -1) {
this.$img.setAttribute('src', newValue);
} else {
this.$img.setAttribute('src', this.imgPath + "/" + newValue);
}
break;
case 'pressed':
if (newValue === null) {
this.$div.classList.remove('pressed');
} else {
this.$div.classList.add('pressed');
}
break;
case 'size':
if (newValue === 'small') {
this.$div.classList.add('small');
} else {
this.$div.classList.remove('small');
}
break;
case 'disabled':
if (newValue) {
this.$div.classList.add('disabled');
} else {
this.$div.classList.remove('disabled');
}
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'title':
{
const shortcut = this.getAttribute('shortcut')
this.$div.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`)
}
break
case 'style':
this.$div.style = newValue
break
case 'src':
if (newValue.indexOf('data:') !== -1) {
this.$img.setAttribute('src', newValue)
} else {
this.$img.setAttribute('src', this.imgPath + '/' + newValue)
}
break
case 'pressed':
if (newValue === null) {
this.$div.classList.remove('pressed')
} else {
this.$div.classList.add('pressed')
}
break
case 'size':
if (newValue === 'small') {
this.$div.classList.add('small')
} else {
this.$div.classList.remove('small')
}
break
case 'disabled':
if (newValue) {
this.$div.classList.add('disabled')
} else {
this.$div.classList.remove('disabled')
}
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -129,14 +132,15 @@ export class ToolButton extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get pressed () {
return this.hasAttribute('pressed');
return this.hasAttribute('pressed')
}
/**
@@ -146,17 +150,18 @@ export class ToolButton extends HTMLElement {
set pressed (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('pressed', 'true');
this.setAttribute('pressed', 'true')
} else {
this.removeAttribute('pressed');
this.removeAttribute('pressed')
}
}
/**
* @function get
* @returns {any}
*/
get disabled () {
return this.hasAttribute('disabled');
return this.hasAttribute('disabled')
}
/**
@@ -166,17 +171,18 @@ export class ToolButton extends HTMLElement {
set disabled (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('disabled', 'true');
this.setAttribute('disabled', 'true')
} else {
this.removeAttribute('disabled');
this.removeAttribute('disabled')
}
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -184,7 +190,7 @@ export class ToolButton extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
@@ -192,7 +198,7 @@ export class ToolButton extends HTMLElement {
* @returns {any}
*/
get size () {
return this.getAttribute('size');
return this.getAttribute('size')
}
/**
@@ -200,7 +206,7 @@ export class ToolButton extends HTMLElement {
* @returns {void}
*/
set size (value) {
this.setAttribute('size', value);
this.setAttribute('size', value)
}
/**
@@ -209,22 +215,22 @@ export class ToolButton extends HTMLElement {
*/
connectedCallback () {
// capture shortcuts
const shortcut = this.getAttribute('shortcut');
const shortcut = this.getAttribute('shortcut')
if (shortcut) {
// register the keydown event
document.addEventListener('keydown', (e) => {
// only track keyboard shortcuts for the body containing the SVG-Editor
if (e.target.nodeName !== 'BODY') return;
if (e.target.nodeName !== 'BODY') return
// normalize key
const key = `${(e.metaKey) ? 'meta+' : ''}${(e.ctrlKey) ? 'ctrl+' : ''}${e.key.toUpperCase()}`;
if (shortcut !== key) return;
const key = `${(e.metaKey) ? 'meta+' : ''}${(e.ctrlKey) ? 'ctrl+' : ''}${e.key.toUpperCase()}`
if (shortcut !== key) return
// launch the click event
this.click();
e.preventDefault();
});
this.click()
e.preventDefault()
})
}
}
}
// Register
customElements.define('se-button', ToolButton);
customElements.define('se-button', ToolButton)

View File

@@ -1,9 +1,9 @@
/* globals svgEditor */
import { jGraduate, jGraduateMethod } from './jgraduate/jQuery.jGraduate.js';
import PaintBox from './PaintBox.js';
import { t } from '../locale.js';
import { jGraduate, jGraduateMethod } from './jgraduate/jQuery.jGraduate.js'
import PaintBox from './PaintBox.js'
import { t } from '../locale.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
.jPicker .Icon {
@@ -645,7 +645,7 @@ div.jGraduate_Slider img {
</div>
<!-- hidden div -->
<div id="color_picker"></div>
`;
`
/**
* @class SeColorPicker
*/
@@ -654,35 +654,38 @@ export class SeColorPicker extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$logo = this._shadowRoot.getElementById('logo');
this.$label = this._shadowRoot.getElementById('label');
this.$block = this._shadowRoot.getElementById('block');
this.paintBox = null;
this.i18next = null;
this.$picker = this._shadowRoot.getElementById('picker');
this.$color_picker = this._shadowRoot.getElementById('color_picker');
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$logo = this._shadowRoot.getElementById('logo')
this.$label = this._shadowRoot.getElementById('label')
this.$block = this._shadowRoot.getElementById('block')
this.paintBox = null
this.i18next = null
this.$picker = this._shadowRoot.getElementById('picker')
this.$color_picker = this._shadowRoot.getElementById('color_picker')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.i18next = i18next;
this.setAttribute('config-change_xxx_color', t('config.change_xxx_color'));
this.i18next = i18next
this.setAttribute('config-change_xxx_color', t('config.change_xxx_color'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'label', 'src', 'type', 'config-change_xxx_color' ];
return ['label', 'src', 'type', 'config-change_xxx_color']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -691,31 +694,32 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'src':
this.$logo.setAttribute('src', this.imgPath + '/' + newValue);
break;
case 'label':
this.setAttribute('title', t(newValue));
break;
case 'type':
this.$label.setAttribute('title', 'config.pick_paint_opavity');
break;
case 'config-change_xxx_color':
this.$label.setAttribute('title', newValue);
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'src':
this.$logo.setAttribute('src', this.imgPath + '/' + newValue)
break
case 'label':
this.setAttribute('title', t(newValue))
break
case 'type':
this.$label.setAttribute('title', 'config.pick_paint_opavity')
break
case 'config-change_xxx_color':
this.$label.setAttribute('title', newValue)
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.$label.getAttribute('title');
return this.$label.getAttribute('title')
}
/**
@@ -723,14 +727,15 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get type () {
return this.getAttribute('type');
return this.getAttribute('type')
}
/**
@@ -738,14 +743,15 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
set type (value) {
this.setAttribute('type', value);
this.setAttribute('type', value)
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -753,7 +759,7 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
@@ -763,20 +769,23 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
update (svgCanvas, selectedElement, apply) {
const paint = this.paintBox.update(svgCanvas, selectedElement);
const paint = this.paintBox.update(svgCanvas, selectedElement)
if (paint && apply) {
const changeEvent = new CustomEvent('change', { detail: {
paint
} });
this.dispatchEvent(changeEvent);
const changeEvent = new CustomEvent('change', {
detail: {
paint
}
})
this.dispatchEvent(changeEvent)
}
}
/**
* @param {PlainObject} paint
* @returns {void}
*/
setPaint (paint) {
this.paintBox.setPaint(paint);
this.paintBox.setPaint(paint)
}
/**
@@ -784,9 +793,9 @@ export class SeColorPicker extends HTMLElement {
* @returns {void}
*/
connectedCallback () {
this.paintBox = new PaintBox(this.$block, this.type);
this.paintBox = new PaintBox(this.$block, this.type)
this.$picker.addEventListener('click', () => {
let { paint } = this.paintBox;
let { paint } = this.paintBox
jGraduateMethod(
this.$color_picker,
{
@@ -796,22 +805,24 @@ export class SeColorPicker extends HTMLElement {
newstop: 'inverse'
},
(p) => {
paint = new jGraduate.Paint(p);
this.setPaint(paint);
const changeEvent = new CustomEvent('change', { detail: {
paint
} });
this.dispatchEvent(changeEvent);
this.$color_picker.style.display = 'none';
paint = new jGraduate.Paint(p)
this.setPaint(paint)
const changeEvent = new CustomEvent('change', {
detail: {
paint
}
})
this.dispatchEvent(changeEvent)
this.$color_picker.style.display = 'none'
},
() => {
this.$color_picker.style.display = 'none';
this.$color_picker.style.display = 'none'
},
this.i18next
);
});
)
})
}
}
// Register
customElements.define('se-colorpicker', SeColorPicker);
customElements.define('se-colorpicker', SeColorPicker)

View File

@@ -1,8 +1,8 @@
import ListComboBox from 'elix/define/ListComboBox.js';
import { defaultState } from 'elix/src/base/internal.js';
import { templateFrom, fragmentFrom } from 'elix/src/core/htmlLiterals.js';
import { internal } from 'elix';
import NumberSpinBox from '../dialogs/se-elix/define/NumberSpinBox.js';
import ListComboBox from 'elix/define/ListComboBox.js'
import { defaultState } from 'elix/src/base/internal.js'
import { templateFrom, fragmentFrom } from 'elix/src/core/htmlLiterals.js'
import { internal } from 'elix'
import NumberSpinBox from '../dialogs/se-elix/define/NumberSpinBox.js'
/**
* @class Dropdown
@@ -15,21 +15,22 @@ class Dropdown extends ListComboBox {
get [defaultState] () {
return Object.assign(super[defaultState], {
inputPartType: NumberSpinBox,
src: "logo.svg",
src: 'logo.svg',
inputsize: '100%'
});
})
}
/**
* @function get
* @returns {PlainObject}
*/
get [internal.template] () {
const result = super[internal.template];
const source = result.content.getElementById('source');
const result = super[internal.template]
const source = result.content.getElementById('source')
// add a icon before our dropdown
source.prepend(fragmentFrom.html`
<img src="dropdown.svg" alt="icon" width="18" height="18"></img>
`.cloneNode(true));
`.cloneNode(true))
// change the style so it fits in our toolbar
result.content.append(
templateFrom.html`
@@ -48,16 +49,18 @@ class Dropdown extends ListComboBox {
}
</style>
`.content
);
return result;
)
return result
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'src', 'inputsize', 'value' ];
return ['title', 'src', 'inputsize', 'value']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -66,97 +69,104 @@ class Dropdown extends ListComboBox {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
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;
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);
super[internal.render](changed)
if (this[internal.firstRender]) {
this.$img = this.shadowRoot.querySelector('img');
this.$input = this.shadowRoot.getElementById('input');
this.$img = this.shadowRoot.querySelector('img')
this.$input = this.shadowRoot.getElementById('input')
}
if (changed.src) {
this.$img.setAttribute('src', this[internal.state].src);
this.$img.setAttribute('src', this[internal.state].src)
}
if (changed.inputsize) {
this.$input.shadowRoot.querySelector('[part~="input"]').style.width = this[internal.state].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');
e.preventDefault()
const value = e.detail?.closeResult?.getAttribute('value')
if (value) {
const closeEvent = new CustomEvent('change', { detail: { value } });
this.dispatchEvent(closeEvent);
const closeEvent = new CustomEvent('change', { detail: { value } })
this.dispatchEvent(closeEvent)
}
});
})
}
}
/**
* @function src
* @returns {string} src
*/
get src () {
return this[internal.state].src;
return this[internal.state].src
}
/**
* @function src
* @returns {void}
*/
set src (src) {
this[internal.setState]({ src });
this[internal.setState]({ src })
}
/**
* @function inputsize
* @returns {string} src
*/
get inputsize () {
return this[internal.state].inputsize;
return this[internal.state].inputsize
}
/**
* @function src
* @returns {void}
*/
set inputsize (inputsize) {
this[internal.setState]({ inputsize });
this[internal.setState]({ inputsize })
}
/**
* @function value
* @returns {string} src
*/
get value () {
return this[internal.state].value;
return this[internal.state].value
}
/**
* @function value
* @returns {void}
*/
set value (value) {
this[internal.setState]({ value });
this[internal.setState]({ value })
}
}
// Register
customElements.define('se-dropdown', Dropdown);
customElements.define('se-dropdown', Dropdown)
/*
{TODO

View File

@@ -1,6 +1,5 @@
/* globals svgEditor */
/* eslint-disable no-unsanitized/property */
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
:host {
@@ -98,7 +97,7 @@ template.innerHTML = `
</div>
</div>
`;
`
/**
* @class ExplorerButton
*/
@@ -107,28 +106,30 @@ export class ExplorerButton extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$button = this._shadowRoot.querySelector('.menu-button');
this.$overall = this._shadowRoot.querySelector('.overall');
this.$img = this._shadowRoot.querySelector('.menu-button img');
this.$menu = this._shadowRoot.querySelector('.menu');
this.$handle = this._shadowRoot.querySelector('.handle');
this.$lib = this._shadowRoot.querySelector('.image-lib');
this.files = [];
this.request = new XMLHttpRequest();
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this.$button = this._shadowRoot.querySelector('.menu-button')
this.$overall = this._shadowRoot.querySelector('.overall')
this.$img = this._shadowRoot.querySelector('.menu-button img')
this.$menu = this._shadowRoot.querySelector('.menu')
this.$handle = this._shadowRoot.querySelector('.handle')
this.$lib = this._shadowRoot.querySelector('.image-lib')
this.files = []
this.request = new XMLHttpRequest()
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'pressed', 'disabled', 'lib', 'src' ];
return ['title', 'pressed', 'disabled', 'lib', 'src']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -137,55 +138,56 @@ export class ExplorerButton extends HTMLElement {
* @returns {void}
*/
async attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
{
const shortcut = this.getAttribute('shortcut');
this.$button.setAttribute('title', `${newValue} [${shortcut}]`);
}
break;
case 'pressed':
if (newValue) {
this.$overall.classList.add('pressed');
} else {
this.$overall.classList.remove('pressed');
}
break;
case 'disabled':
if (newValue) {
this.$overall.classList.add('disabled');
} else {
this.$overall.classList.remove('disabled');
}
break;
case 'lib':
try {
const response = await fetch(`${newValue}index.json`);
const json = await response.json();
const { lib } = json;
this.$menu.innerHTML = lib.map((menu, i) => (
case 'title':
{
const shortcut = this.getAttribute('shortcut')
this.$button.setAttribute('title', `${newValue} [${shortcut}]`)
}
break
case 'pressed':
if (newValue) {
this.$overall.classList.add('pressed')
} else {
this.$overall.classList.remove('pressed')
}
break
case 'disabled':
if (newValue) {
this.$overall.classList.add('disabled')
} else {
this.$overall.classList.remove('disabled')
}
break
case 'lib':
try {
const response = await fetch(`${newValue}index.json`)
const json = await response.json()
const { lib } = json
this.$menu.innerHTML = lib.map((menu, i) => (
`<div data-menu="${menu}" class="menu-item ${(i === 0) ? 'pressed' : ''} ">${menu}</div>`
)).join('');
await this.updateLib(lib[0]);
} catch (error) {
console.error(error);
}
break;
case 'src':
this.$img.setAttribute('src', this.imgPath + '/' + newValue);
break;
default:
console.error(`unknown attribute: ${name}`);
break;
)).join('')
await this.updateLib(lib[0])
} catch (error) {
console.error(error)
}
break
case 'src':
this.$img.setAttribute('src', this.imgPath + '/' + newValue)
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -193,14 +195,15 @@ export class ExplorerButton extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get pressed () {
return this.hasAttribute('pressed');
return this.hasAttribute('pressed')
}
/**
@@ -210,17 +213,18 @@ export class ExplorerButton extends HTMLElement {
set pressed (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('pressed', 'true');
this.setAttribute('pressed', 'true')
} else {
this.removeAttribute('pressed', '');
this.removeAttribute('pressed', '')
}
}
/**
* @function get
* @returns {any}
*/
get disabled () {
return this.hasAttribute('disabled');
return this.hasAttribute('disabled')
}
/**
@@ -230,11 +234,12 @@ export class ExplorerButton extends HTMLElement {
set disabled (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('disabled', 'true');
this.setAttribute('disabled', 'true')
} else {
this.removeAttribute('disabled', '');
this.removeAttribute('disabled', '')
}
}
/**
* @function connectedCallback
* @returns {void}
@@ -242,73 +247,74 @@ export class ExplorerButton extends HTMLElement {
connectedCallback () {
// capture click event on the button to manage the logic
const onClickHandler = (ev) => {
ev.stopPropagation();
ev.stopPropagation()
switch (ev.target.nodeName) {
case 'SE-EXPLORERBUTTON':
this.$menu.classList.add('open');
this.$lib.classList.add('open-lib');
break;
case 'SE-BUTTON':
case 'SE-EXPLORERBUTTON':
this.$menu.classList.add('open')
this.$lib.classList.add('open-lib')
break
case 'SE-BUTTON':
// change to the current action
this.currentAction = ev.target;
this.$img.setAttribute('src', this.currentAction.getAttribute('src'));
this.dataset.draw = this.data[this.currentAction.dataset.shape];
this._shadowRoot.querySelectorAll('.image-lib [pressed]').forEach((b) => { b.pressed = false; });
this.currentAction.setAttribute('pressed', 'pressed');
// and close the menu
this.$menu.classList.remove('open');
this.$lib.classList.remove('open-lib');
break;
case 'DIV':
if (ev.target.classList[0] === 'handle') {
this.currentAction = ev.target
this.$img.setAttribute('src', this.currentAction.getAttribute('src'))
this.dataset.draw = this.data[this.currentAction.dataset.shape]
this._shadowRoot.querySelectorAll('.image-lib [pressed]').forEach((b) => { b.pressed = false })
this.currentAction.setAttribute('pressed', 'pressed')
// and close the menu
this.$menu.classList.remove('open')
this.$lib.classList.remove('open-lib')
break
case 'DIV':
if (ev.target.classList[0] === 'handle') {
// this is a click on the handle so let's open/close the menu.
this.$menu.classList.toggle('open');
this.$lib.classList.toggle('open-lib');
} else {
this._shadowRoot.querySelectorAll('.menu > .pressed').forEach((b) => { b.classList.remove('pressed'); });
ev.target.classList.add('pressed');
this.updateLib(ev.target.dataset.menu);
}
break;
default:
console.error('unknown nodeName for:', ev.target, ev.target.className);
this.$menu.classList.toggle('open')
this.$lib.classList.toggle('open-lib')
} else {
this._shadowRoot.querySelectorAll('.menu > .pressed').forEach((b) => { b.classList.remove('pressed') })
ev.target.classList.add('pressed')
this.updateLib(ev.target.dataset.menu)
}
break
default:
console.error('unknown nodeName for:', ev.target, ev.target.className)
}
};
}
// capture event from slots
this.addEventListener('click', onClickHandler);
this.$menu.addEventListener('click', onClickHandler);
this.$lib.addEventListener('click', onClickHandler);
this.$handle.addEventListener('click', onClickHandler);
this.addEventListener('click', onClickHandler)
this.$menu.addEventListener('click', onClickHandler)
this.$lib.addEventListener('click', onClickHandler)
this.$handle.addEventListener('click', onClickHandler)
}
/**
* @function updateLib
* @param {string} lib
* @returns {void}
*/
async updateLib (lib) {
const libDir = this.getAttribute('lib');
const libDir = this.getAttribute('lib')
try {
// initialize buttons for all shapes defined for this library
const response = await fetch(`${libDir}${lib}.json`);
const json = await response.json();
this.data = json.data;
const size = json.size ?? 300;
const fill = json.fill ? '#333' : 'none';
const off = size * 0.05;
const vb = [ -off, -off, size + off * 2, size + off * 2 ].join(' ');
const stroke = json.fill ? 0 : (size / 30);
this.$lib.innerHTML = Object.entries(this.data).map(([ key, path ]) => {
const response = await fetch(`${libDir}${lib}.json`)
const json = await response.json()
this.data = json.data
const size = json.size ?? 300
const fill = json.fill ? '#333' : 'none'
const off = size * 0.05
const vb = [-off, -off, size + off * 2, size + off * 2].join(' ')
const stroke = json.fill ? 0 : (size / 30)
this.$lib.innerHTML = Object.entries(this.data).map(([key, path]) => {
const encoded = btoa(`
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
<svg viewBox="${vb}"><path fill="${fill}" stroke="#f8bb00" stroke-width="${stroke}" d="${path}"></path></svg>
</svg>`);
return `<se-button data-shape="${key}"src="data:image/svg+xml;base64,${encoded}"></se-button>`;
}).join('');
</svg>`)
return `<se-button data-shape="${key}"src="data:image/svg+xml;base64,${encoded}"></se-button>`
}).join('')
} catch (error) {
console.error(`could not read file:${libDir}${lib}.json`, error);
console.error(`could not read file:${libDir}${lib}.json`, error)
}
}
}
// Register
customElements.define('se-explorerbutton', ExplorerButton);
customElements.define('se-explorerbutton', ExplorerButton)

View File

@@ -1,6 +1,6 @@
/* globals svgEditor */
import { t } from '../locale.js';
const template = document.createElement('template');
import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
:host {
@@ -79,7 +79,7 @@ template.innerHTML = `
</div>
`;
`
/**
* @class FlyingButton
*/
@@ -88,28 +88,30 @@ export class FlyingButton extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$button = this._shadowRoot.querySelector('.menu-button');
this.$handle = this._shadowRoot.querySelector('.handle');
this.$overall = this._shadowRoot.querySelector('.overall');
this.$img = this._shadowRoot.querySelector('img');
this.$menu = this._shadowRoot.querySelector('.menu');
this.$button = this._shadowRoot.querySelector('.menu-button')
this.$handle = this._shadowRoot.querySelector('.handle')
this.$overall = this._shadowRoot.querySelector('.overall')
this.$img = this._shadowRoot.querySelector('img')
this.$menu = this._shadowRoot.querySelector('.menu')
// the last element of the div is the slot
// we retrieve all elements added in the slot (i.e. se-buttons)
this.$elements = this.$menu.lastElementChild.assignedElements();
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this.$elements = this.$menu.lastElementChild.assignedElements()
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'pressed', 'disabled', 'opened' ];
return ['title', 'pressed', 'disabled', 'opened']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -118,46 +120,47 @@ export class FlyingButton extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
{
const shortcut = this.getAttribute('shortcut');
this.$button.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`);
}
break;
case 'pressed':
if (newValue) {
this.$overall.classList.add('pressed');
} else {
this.$overall.classList.remove('pressed');
}
break;
case 'opened':
if (newValue) {
this.$menu.classList.add('open');
} else {
this.$menu.classList.remove('open');
}
break;
case 'disabled':
if (newValue) {
this.$overall.classList.add('disabled');
} else {
this.$overall.classList.remove('disabled');
}
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'title':
{
const shortcut = this.getAttribute('shortcut')
this.$button.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`)
}
break
case 'pressed':
if (newValue) {
this.$overall.classList.add('pressed')
} else {
this.$overall.classList.remove('pressed')
}
break
case 'opened':
if (newValue) {
this.$menu.classList.add('open')
} else {
this.$menu.classList.remove('open')
}
break
case 'disabled':
if (newValue) {
this.$overall.classList.add('disabled')
} else {
this.$overall.classList.remove('disabled')
}
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -165,14 +168,15 @@ export class FlyingButton extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get pressed () {
return this.hasAttribute('pressed');
return this.hasAttribute('pressed')
}
/**
@@ -182,19 +186,20 @@ export class FlyingButton extends HTMLElement {
set pressed (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('pressed', 'true');
this.setAttribute('pressed', 'true')
} else {
this.removeAttribute('pressed', '');
this.removeAttribute('pressed', '')
// close also the menu if open
this.removeAttribute('opened');
this.removeAttribute('opened')
}
}
/**
* @function get
* @returns {any}
*/
get opened () {
return this.hasAttribute('opened');
return this.hasAttribute('opened')
}
/**
@@ -204,17 +209,18 @@ export class FlyingButton extends HTMLElement {
set opened (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('opened', 'opened');
this.setAttribute('opened', 'opened')
} else {
this.removeAttribute('opened');
this.removeAttribute('opened')
}
}
/**
* @function get
* @returns {any}
*/
get disabled () {
return this.hasAttribute('disabled');
return this.hasAttribute('disabled')
}
/**
@@ -224,59 +230,60 @@ export class FlyingButton extends HTMLElement {
set disabled (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('disabled', 'true');
this.setAttribute('disabled', 'true')
} else {
this.removeAttribute('disabled', '');
this.removeAttribute('disabled', '')
}
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
this.activeSlot = this.shadowRoot.querySelector('slot').assignedElements()[0];
this.$img.setAttribute('src', this.imgPath + '/' + this.activeSlot.getAttribute('src'));
this.activeSlot = this.shadowRoot.querySelector('slot').assignedElements()[0]
this.$img.setAttribute('src', this.imgPath + '/' + this.activeSlot.getAttribute('src'))
// capture click event on the button to manage the logic
const onClickHandler = (ev) => {
ev.stopPropagation();
ev.stopPropagation()
switch (ev.target.nodeName) {
case 'SE-FLYINGBUTTON':
if (this.pressed) {
this.setAttribute('opened', 'opened');
} else {
case 'SE-FLYINGBUTTON':
if (this.pressed) {
this.setAttribute('opened', 'opened')
} else {
// launch current action
this.activeSlot.click();
this.setAttribute('pressed', 'pressed');
}
break;
case 'SE-BUTTON':
this.activeSlot.click()
this.setAttribute('pressed', 'pressed')
}
break
case 'SE-BUTTON':
// change to the current action
this.$img.setAttribute('src', this.imgPath + '/' + ev.target.getAttribute('src'));
this.activeSlot = ev.target;
this.setAttribute('pressed', 'pressed');
// and close the menu
this.$menu.classList.remove('open');
break;
case 'DIV':
this.$img.setAttribute('src', this.imgPath + '/' + ev.target.getAttribute('src'))
this.activeSlot = ev.target
this.setAttribute('pressed', 'pressed')
// and close the menu
this.$menu.classList.remove('open')
break
case 'DIV':
// this is a click on the handle so let's open/close the menu.
if (this.opened) {
this.removeAttribute('opened');
} else {
this.setAttribute('opened', 'opened');
// In case menu scroll on top or bottom position based popup position set
const rect = this.getBoundingClientRect();
this.$menu.style.top = rect.top + "px";
}
break;
default:
console.error('unkonw nodeName for:', ev.target, ev.target.className);
if (this.opened) {
this.removeAttribute('opened')
} else {
this.setAttribute('opened', 'opened')
// In case menu scroll on top or bottom position based popup position set
const rect = this.getBoundingClientRect()
this.$menu.style.top = rect.top + 'px'
}
break
default:
console.error('unkonw nodeName for:', ev.target, ev.target.className)
}
};
}
// capture event from slots
this.addEventListener('click', onClickHandler);
this.$handle.addEventListener('click', onClickHandler);
this.addEventListener('click', onClickHandler)
this.$handle.addEventListener('click', onClickHandler)
}
}
// Register
customElements.define('se-flyingbutton', FlyingButton);
customElements.define('se-flyingbutton', FlyingButton)

View File

@@ -1,7 +1,7 @@
import 'elix/define/Input.js';
import { t } from '../locale.js';
import 'elix/define/Input.js'
import { t } from '../locale.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
div {
@@ -32,7 +32,7 @@ template.innerHTML = `
<span id="label">label</span>
<elix-input></elix-input>
</div>
`;
`
/**
* @class SEInput
@@ -42,24 +42,26 @@ export class SEInput extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$div = this._shadowRoot.querySelector('div');
this.$img = this._shadowRoot.querySelector('img');
this.$label = this.shadowRoot.getElementById('label');
this.$event = new CustomEvent('change');
this.$input = this._shadowRoot.querySelector('elix-input');
this.$div = this._shadowRoot.querySelector('div')
this.$img = this._shadowRoot.querySelector('img')
this.$label = this.shadowRoot.getElementById('label')
this.$event = new CustomEvent('change')
this.$input = this._shadowRoot.querySelector('elix-input')
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'value', 'label', 'src', 'size', 'title' ];
return ['value', 'label', 'src', 'size', 'title']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -68,36 +70,37 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
this.$div.setAttribute('title', `${t(newValue)}`);
break;
case 'src':
this.$img.setAttribute('src', newValue);
this.$label.remove();
break;
case 'size':
this.$input.setAttribute('size', newValue);
break;
case 'label':
this.$label.textContent = t(newValue);
this.$img.remove();
break;
case 'value':
this.$input.value = newValue;
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'title':
this.$div.setAttribute('title', `${t(newValue)}`)
break
case 'src':
this.$img.setAttribute('src', newValue)
this.$label.remove()
break
case 'size':
this.$input.setAttribute('size', newValue)
break
case 'label':
this.$label.textContent = t(newValue)
this.$img.remove()
break
case 'value':
this.$input.value = newValue
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -105,14 +108,15 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -120,14 +124,15 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get value () {
return this.$input.value;
return this.$input.value
}
/**
@@ -135,14 +140,15 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
set value (value) {
this.$input.value = value;
this.$input.value = value
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -150,7 +156,7 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
@@ -158,7 +164,7 @@ export class SEInput extends HTMLElement {
* @returns {any}
*/
get size () {
return this.getAttribute('size');
return this.getAttribute('size')
}
/**
@@ -166,7 +172,7 @@ export class SEInput extends HTMLElement {
* @returns {void}
*/
set size (value) {
this.setAttribute('size', value);
this.setAttribute('size', value)
}
/**
@@ -175,16 +181,16 @@ export class SEInput extends HTMLElement {
*/
connectedCallback () {
this.$input.addEventListener('change', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
e.preventDefault()
this.value = e.target.value
this.dispatchEvent(this.$event)
})
this.$input.addEventListener('keyup', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
e.preventDefault()
this.value = e.target.value
this.dispatchEvent(this.$event)
})
}
}
// Register
customElements.define('se-input', SEInput);
customElements.define('se-input', SEInput)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import 'elix/define/DropdownList.js';
import { t } from '../locale.js';
import 'elix/define/DropdownList.js'
import { t } from '../locale.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
elix-dropdown-list {
@@ -30,7 +30,7 @@ elix-dropdown-list::part(popup-toggle) {
<slot></slot>
</elix-dropdown-list>
`;
`
/**
* @class SeList
*/
@@ -39,22 +39,23 @@ export class SeList extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$dropdown = this._shadowRoot.querySelector('elix-dropdown-list');
this.$label = this._shadowRoot.querySelector('label');
this.$selection = this.$dropdown.shadowRoot.querySelector('#value');
this.items = this.querySelectorAll("se-list-item");
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$dropdown = this._shadowRoot.querySelector('elix-dropdown-list')
this.$label = this._shadowRoot.querySelector('label')
this.$selection = this.$dropdown.shadowRoot.querySelector('#value')
this.items = this.querySelectorAll('se-list-item')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'label', 'width', 'height', 'title', 'value' ];
return ['label', 'width', 'height', 'title', 'value']
}
/**
@@ -65,51 +66,51 @@ export class SeList extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
const currentObj = this;
if (oldValue === newValue) return;
const currentObj = this
if (oldValue === newValue) return
switch (name) {
case 'title':
this.$dropdown.setAttribute('title', t(newValue));
break;
case 'label':
this.$label.textContent = t(newValue);
break;
case 'height':
this.$dropdown.style.height = newValue;
break;
case 'width':
this.$dropdown.style.width = newValue;
break;
case 'value':
Array.from(this.items).forEach(function (element) {
if(element.getAttribute("value") === newValue) {
if (element.hasAttribute("src")) {
case 'title':
this.$dropdown.setAttribute('title', t(newValue))
break
case 'label':
this.$label.textContent = t(newValue)
break
case 'height':
this.$dropdown.style.height = newValue
break
case 'width':
this.$dropdown.style.width = newValue
break
case 'value':
Array.from(this.items).forEach(function (element) {
if (element.getAttribute('value') === newValue) {
if (element.hasAttribute('src')) {
// empty current selection children
while(currentObj.$selection.firstChild)
currentObj.$selection.removeChild(currentObj.$selection.firstChild);
// replace selection child with image of new value
const img = document.createElement('img');
img.src = currentObj.imgPath + '/' + element.getAttribute("src");
img.style.height = element.getAttribute("img-height");
img.setAttribute('title', t(element.getAttribute("title")));
currentObj.$selection.append(img);
} else {
currentObj.$selection.textContent = t(element.getAttribute('option'));
while (currentObj.$selection.firstChild) { currentObj.$selection.removeChild(currentObj.$selection.firstChild) }
// replace selection child with image of new value
const img = document.createElement('img')
img.src = currentObj.imgPath + '/' + element.getAttribute('src')
img.style.height = element.getAttribute('img-height')
img.setAttribute('title', t(element.getAttribute('title')))
currentObj.$selection.append(img)
} else {
currentObj.$selection.textContent = t(element.getAttribute('option'))
}
}
}
});
break;
default:
console.error(`unknown attribute: ${name}`);
break;
})
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -117,14 +118,15 @@ export class SeList extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -132,14 +134,15 @@ export class SeList extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get width () {
return this.getAttribute('width');
return this.getAttribute('width')
}
/**
@@ -147,14 +150,15 @@ export class SeList extends HTMLElement {
* @returns {void}
*/
set width (value) {
this.setAttribute('width', value);
this.setAttribute('width', value)
}
/**
* @function get
* @returns {any}
*/
get height () {
return this.getAttribute('height');
return this.getAttribute('height')
}
/**
@@ -162,31 +166,32 @@ export class SeList extends HTMLElement {
* @returns {void}
*/
set height (value) {
this.setAttribute('height', value);
this.setAttribute('height', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const currentObj = this;
const currentObj = this
this.$dropdown.addEventListener('selectedindexchange', (e) => {
if (e?.detail?.selectedIndex !== undefined) {
const value = this.$dropdown.selectedItem.getAttribute('value');
const closeEvent = new CustomEvent('change', { detail: { value } });
currentObj.dispatchEvent(closeEvent);
currentObj.value = value;
currentObj.setAttribute("value", value);
const value = this.$dropdown.selectedItem.getAttribute('value')
const closeEvent = new CustomEvent('change', { detail: { value } })
currentObj.dispatchEvent(closeEvent)
currentObj.value = value
currentObj.setAttribute('value', value)
}
});
})
this.$dropdown.addEventListener('close', (_e) => {
/** with Chrome, selectedindexchange does not fire consistently
* unless you forec change in this close event
*/
this.$dropdown.selectedIndex = this.$dropdown.currentIndex;
});
this.$dropdown.selectedIndex = this.$dropdown.currentIndex
})
}
}
// Register
customElements.define('se-list', SeList);
customElements.define('se-list', SeList)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import 'elix/define/Option.js';
import { t } from '../locale.js';
import 'elix/define/Option.js'
import { t } from '../locale.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
elix-option{
@@ -17,7 +17,7 @@ template.innerHTML = `
<img alt="icon" />
<slot></slot>
</elix-option>
`;
`
/**
* @class SeMenu
*/
@@ -26,23 +26,24 @@ export class SeListItem extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$menuitem = this._shadowRoot.querySelector('elix-option');
this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark');
this.$svg.setAttribute('style', 'display: none;');
this.$img = this._shadowRoot.querySelector('img');
this.$img.setAttribute('style', 'display: none;');
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$menuitem = this._shadowRoot.querySelector('elix-option')
this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark')
this.$svg.setAttribute('style', 'display: none;')
this.$img = this._shadowRoot.querySelector('img')
this.$img.setAttribute('style', 'display: none;')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'option', 'src', 'title', 'img-height' ];
return ['option', 'src', 'title', 'img-height']
}
/**
@@ -53,33 +54,34 @@ export class SeListItem extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'option':
this.$menuitem.setAttribute('option', newValue);
this.$menuitem.textContent = t(newValue);
break;
case 'src':
this.$img.setAttribute('style', 'display: block;');
this.$img.setAttribute('src', this.imgPath + '/' + newValue);
break;
case 'title':
this.$img.setAttribute('title', t(newValue));
break;
case 'img-height':
this.$img.setAttribute('height', newValue);
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'option':
this.$menuitem.setAttribute('option', newValue)
this.$menuitem.textContent = t(newValue)
break
case 'src':
this.$img.setAttribute('style', 'display: block;')
this.$img.setAttribute('src', this.imgPath + '/' + newValue)
break
case 'title':
this.$img.setAttribute('title', t(newValue))
break
case 'img-height':
this.$img.setAttribute('height', newValue)
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get option () {
return this.getAttribute('option');
return this.getAttribute('option')
}
/**
@@ -87,14 +89,15 @@ export class SeListItem extends HTMLElement {
* @returns {void}
*/
set option (value) {
this.setAttribute('option', value);
this.setAttribute('option', value)
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -102,14 +105,15 @@ export class SeListItem extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get imgHeight () {
return this.getAttribute('img-height');
return this.getAttribute('img-height')
}
/**
@@ -117,14 +121,15 @@ export class SeListItem extends HTMLElement {
* @returns {void}
*/
set imgHeight (value) {
this.setAttribute('img-height', value);
this.setAttribute('img-height', value)
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -132,9 +137,9 @@ export class SeListItem extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
}
// Register
customElements.define('se-list-item', SeListItem);
customElements.define('se-list-item', SeListItem)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import 'elix/define/MenuItem.js';
import './sePlainMenuButton.js';
import 'elix/define/MenuItem.js'
import './sePlainMenuButton.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
:host {
@@ -29,7 +29,7 @@ template.innerHTML = `
<slot></slot>
</elix-menu-button>
`;
`
/**
* @class SeMenu
*/
@@ -38,20 +38,21 @@ export class SeMenu extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$menu = this._shadowRoot.querySelector('elix-menu-button');
this.$label = this.$menu.shadowRoot.querySelector('#popupToggle').shadowRoot;
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$menu = this._shadowRoot.querySelector('elix-menu-button')
this.$label = this.$menu.shadowRoot.querySelector('#popupToggle').shadowRoot
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'label', 'src' ];
return ['label', 'src']
}
/**
@@ -62,29 +63,30 @@ export class SeMenu extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
const image = new Image();
if (oldValue === newValue) return;
const image = new Image()
if (oldValue === newValue) return
switch (name) {
case 'src':
image.src = this.imgPath + '/' + newValue;
image.width = 24;
image.height = 24;
this.$label.prepend(image);
break;
case 'label':
this.$label.prepend(newValue);
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'src':
image.src = this.imgPath + '/' + newValue
image.width = 24
image.height = 24
this.$label.prepend(image)
break
case 'label':
this.$label.prepend(newValue)
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -92,14 +94,15 @@ export class SeMenu extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -107,7 +110,7 @@ export class SeMenu extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
* @function connectedCallback
@@ -125,4 +128,4 @@ export class SeMenu extends HTMLElement {
}
// Register
customElements.define('se-menu', SeMenu);
customElements.define('se-menu', SeMenu)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import 'elix/define/Menu.js';
import 'elix/define/MenuItem.js';
import { t } from '../locale.js';
const template = document.createElement('template');
import 'elix/define/Menu.js'
import 'elix/define/MenuItem.js'
import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
</style>
@@ -12,7 +12,7 @@ template.innerHTML = `
<span style="margin-left: 7px;"></span>
</div>
</elix-menu-item>
`;
`
/**
* @class SeMenuItem
*/
@@ -21,24 +21,26 @@ export class SeMenuItem extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$img = this._shadowRoot.querySelector('img');
this.$label = this._shadowRoot.querySelector('span');
this.$menuitem = this._shadowRoot.querySelector('elix-menu-item');
this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark');
this.$svg.setAttribute('style', 'display: none;');
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$img = this._shadowRoot.querySelector('img')
this.$label = this._shadowRoot.querySelector('span')
this.$menuitem = this._shadowRoot.querySelector('elix-menu-item')
this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark')
this.$svg.setAttribute('style', 'display: none;')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'label', 'src' ];
return ['label', 'src']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -47,28 +49,29 @@ export class SeMenuItem extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let shortcut = '';
if (oldValue === newValue) return;
let shortcut = ''
if (oldValue === newValue) return
switch (name) {
case 'src':
this.$img.style.display = 'inline-block';
this.$img.setAttribute('src', this.imgPath + '/' + newValue);
break;
case 'label':
shortcut = this.getAttribute('shortcut');
this.$label.textContent = `${t(newValue)} ${shortcut ? `(${shortcut})` : ''}`;
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'src':
this.$img.style.display = 'inline-block'
this.$img.setAttribute('src', this.imgPath + '/' + newValue)
break
case 'label':
shortcut = this.getAttribute('shortcut')
this.$label.textContent = `${t(newValue)} ${shortcut ? `(${shortcut})` : ''}`
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -76,14 +79,15 @@ export class SeMenuItem extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -91,7 +95,7 @@ export class SeMenuItem extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
@@ -100,24 +104,24 @@ export class SeMenuItem extends HTMLElement {
*/
connectedCallback () {
// capture shortcuts
const shortcut = this.getAttribute('shortcut');
const shortcut = this.getAttribute('shortcut')
if (shortcut) {
// register the keydown event
document.addEventListener('keydown', (e) => {
// only track keyboard shortcuts for the body containing the SVG-Editor
if (e.target.nodeName !== 'BODY') return;
if (e.target.nodeName !== 'BODY') return
// normalize key
const key = `${(e.metaKey) ? 'meta+' : ''}${(e.ctrlKey) ? 'ctrl+' : ''}${e.key.toUpperCase()}`;
if (shortcut !== key) return;
const key = `${(e.metaKey) ? 'meta+' : ''}${(e.ctrlKey) ? 'ctrl+' : ''}${e.key.toUpperCase()}`
if (shortcut !== key) return
// launch the click event
if (this.id) {
document.getElementById(this.id).click();
document.getElementById(this.id).click()
}
e.preventDefault();
});
e.preventDefault()
})
}
}
}
// Register
customElements.define('se-menu-item', SeMenuItem);
customElements.define('se-menu-item', SeMenuItem)

View File

@@ -11,9 +11,9 @@ const palette = [
'#ffaaaa', '#ffd4aa', '#ffffaa', '#d4ffaa',
'#aaffaa', '#aaffd4', '#aaffff', '#aad4ff',
'#aaaaff', '#d4aaff', '#ffaaff', '#ffaad4'
];
]
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
.square {
@@ -50,7 +50,7 @@ template.innerHTML = `
<div id="js-se-palette">
</div>
</div>
`;
`
/**
* @class SEPalette
@@ -60,38 +60,38 @@ export class SEPalette extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$strip = this._shadowRoot.querySelector('#js-se-palette');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$strip = this._shadowRoot.querySelector('#js-se-palette')
palette.forEach((rgb) => {
const newDiv = document.createElement('div');
newDiv.classList.add('square');
if(rgb === 'none') {
const img = document.createElement('img');
img.src = `data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgY2xhc3M9InN2Z19pY29uIj48c3ZnIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNkNDAwMDAiIGlkPSJzdmdfOTAiIHkyPSIyNCIgeDI9IjI0IiB5MT0iMCIgeDE9IjAiLz4KICAgIDxsaW5lIGlkPSJzdmdfOTIiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q0MDAwMCIgeTI9IjI0IiB4Mj0iMCIgeTE9IjAiIHgxPSIyNCIvPgogIDwvc3ZnPjwvc3ZnPg==`;
img.style.width = "15px";
img.style.height = "15px";
newDiv.append(img);
const newDiv = document.createElement('div')
newDiv.classList.add('square')
if (rgb === 'none') {
const img = document.createElement('img')
img.src = 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgY2xhc3M9InN2Z19pY29uIj48c3ZnIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNkNDAwMDAiIGlkPSJzdmdfOTAiIHkyPSIyNCIgeDI9IjI0IiB5MT0iMCIgeDE9IjAiLz4KICAgIDxsaW5lIGlkPSJzdmdfOTIiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q0MDAwMCIgeTI9IjI0IiB4Mj0iMCIgeTE9IjAiIHgxPSIyNCIvPgogIDwvc3ZnPjwvc3ZnPg=='
img.style.width = '15px'
img.style.height = '15px'
newDiv.append(img)
} else {
newDiv.style.backgroundColor = rgb;
newDiv.style.backgroundColor = rgb
}
newDiv.dataset.rgb = rgb;
newDiv.dataset.rgb = rgb
newDiv.addEventListener('click', (evt) => {
evt.preventDefault();
evt.preventDefault()
// shift key or right click for stroke
const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill';
let color = newDiv.dataset.rgb;
const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill'
let color = newDiv.dataset.rgb
// Webkit-based browsers returned 'initial' here for no stroke
if (color === 'none' || color === 'transparent' || color === 'initial') {
color = 'none';
color = 'none'
}
const paletteEvent = new CustomEvent('change', { detail: { picker, color }, bubbles: false });
this.dispatchEvent(paletteEvent);
});
this.$strip.append(newDiv);
});
const paletteEvent = new CustomEvent('change', { detail: { picker, color }, bubbles: false })
this.dispatchEvent(paletteEvent)
})
this.$strip.append(newDiv)
})
}
/**
@@ -100,15 +100,17 @@ export class SEPalette extends HTMLElement {
* @returns {void}
*/
init (i18next) {
this.setAttribute('ui-palette_info', i18next.t('ui.palette_info'));
this.setAttribute('ui-palette_info', i18next.t('ui.palette_info'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'ui-palette_info' ];
return ['ui-palette_info']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -117,12 +119,13 @@ export class SEPalette extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let node;
let node
if (name === 'ui-palette_info') {
node = this._shadowRoot.querySelector('#palette_holder');
node.setAttribute('title', newValue);
node = this._shadowRoot.querySelector('#palette_holder')
node.setAttribute('title', newValue)
}
}
/**
* @function connectedCallback
* @returns {void}
@@ -132,4 +135,4 @@ export class SEPalette extends HTMLElement {
}
// Register
customElements.define('se-palette', SEPalette);
customElements.define('se-palette', SEPalette)

View File

@@ -1,6 +1,6 @@
import { template } from 'elix/src/base/internal.js';
import { fragmentFrom } from 'elix/src/core/htmlLiterals.js';
import PlainButton from 'elix/src/plain/PlainButton.js';
import { template } from 'elix/src/base/internal.js'
import { fragmentFrom } from 'elix/src/core/htmlLiterals.js'
import PlainButton from 'elix/src/plain/PlainButton.js'
/**
* @class SePlainBorderButton
@@ -13,7 +13,7 @@ class SePlainBorderButton extends PlainButton {
* @returns {PlainObject}
*/
get [template] () {
const result = super[template];
const result = super[template]
result.content.append(
fragmentFrom.html`
<style>
@@ -23,9 +23,9 @@ class SePlainBorderButton extends PlainButton {
}
</style>
`
);
return result;
)
return result
}
}
export default SePlainBorderButton;
export default SePlainBorderButton

View File

@@ -1,6 +1,6 @@
import PlainMenuButton from 'elix/src/plain/PlainMenuButton.js';
import { defaultState } from 'elix/src/base/internal.js';
import sePlainBorderButton from './sePlainBorderButton.js';
import PlainMenuButton from 'elix/src/plain/PlainMenuButton.js'
import { defaultState } from 'elix/src/base/internal.js'
import sePlainBorderButton from './sePlainBorderButton.js'
/**
* @class ElixMenuButton
@@ -13,8 +13,8 @@ export default class ElixMenuButton extends PlainMenuButton {
get [defaultState] () {
return Object.assign(super[defaultState], {
sourcePartType: sePlainBorderButton
});
})
}
}
customElements.define('elix-menu-button', ElixMenuButton);
customElements.define('elix-menu-button', ElixMenuButton)

View File

@@ -1,5 +1,5 @@
import { t } from '../locale.js';
const template = document.createElement('template');
import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
select {
@@ -21,7 +21,7 @@ label {
<select>
</select>
`;
`
/**
* @class SeList
*/
@@ -30,19 +30,20 @@ export class SeSelect extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$select = this._shadowRoot.querySelector('select');
this.$label = this._shadowRoot.querySelector('label');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$select = this._shadowRoot.querySelector('select')
this.$label = this._shadowRoot.querySelector('label')
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'label', 'width', 'height', 'options', 'values', 'title', 'disabled' ];
return ['label', 'width', 'height', 'options', 'values', 'title', 'disabled']
}
/**
@@ -53,64 +54,63 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let options;
if (oldValue === newValue) return;
let options
if (oldValue === newValue) return
switch (name) {
case 'label':
this.$label.textContent = t(newValue);
break;
case 'title':
this.$select.setAttribute("title", t(newValue));
break;
case 'disabled':
if(newValue === null) {
this.$select.removeAttribute("disabled");
} else {
this.$select.setAttribute("disabled", newValue);
}
break;
case 'height':
this.$select.style.height = newValue;
break;
case 'width':
this.$select.style.width = newValue;
break;
case 'options':
if(newValue === "") {
while(this.$select.firstChild)
this.$select.removeChild(this.$select.firstChild);
} else {
options = newValue.split(',');
options.forEach((option) => {
const optionNode = document.createElement("OPTION");
const text = document.createTextNode(t(option));
optionNode.appendChild(text);
this.$select.appendChild(optionNode);
});
}
break;
case 'values':
if(newValue === "") {
while(this.$select.firstChild)
this.$select.removeChild(this.$select.firstChild);
} else {
options = newValue.split('::');
options.forEach((option, index) => {
this.$select.children[index].setAttribute('value', option);
});
}
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'label':
this.$label.textContent = t(newValue)
break
case 'title':
this.$select.setAttribute('title', t(newValue))
break
case 'disabled':
if (newValue === null) {
this.$select.removeAttribute('disabled')
} else {
this.$select.setAttribute('disabled', newValue)
}
break
case 'height':
this.$select.style.height = newValue
break
case 'width':
this.$select.style.width = newValue
break
case 'options':
if (newValue === '') {
while (this.$select.firstChild) { this.$select.removeChild(this.$select.firstChild) }
} else {
options = newValue.split(',')
options.forEach((option) => {
const optionNode = document.createElement('OPTION')
const text = document.createTextNode(t(option))
optionNode.appendChild(text)
this.$select.appendChild(optionNode)
})
}
break
case 'values':
if (newValue === '') {
while (this.$select.firstChild) { this.$select.removeChild(this.$select.firstChild) }
} else {
options = newValue.split('::')
options.forEach((option, index) => {
this.$select.children[index].setAttribute('value', option)
})
}
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -118,14 +118,15 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get width () {
return this.getAttribute('width');
return this.getAttribute('width')
}
/**
@@ -133,14 +134,15 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
set width (value) {
this.setAttribute('width', value);
this.setAttribute('width', value)
}
/**
* @function get
* @returns {any}
*/
get height () {
return this.getAttribute('height');
return this.getAttribute('height')
}
/**
@@ -148,14 +150,15 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
set height (value) {
this.setAttribute('height', value);
this.setAttribute('height', value)
}
/**
* @function get
* @returns {any}
*/
get value () {
return this.$select.value;
return this.$select.value
}
/**
@@ -163,14 +166,15 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
set value (value) {
this.$select.value = value;
this.$select.value = value
}
/**
* @function get
* @returns {any}
*/
get disabled () {
return this.$select.getAttribute('disabled');
return this.$select.getAttribute('disabled')
}
/**
@@ -178,22 +182,23 @@ export class SeSelect extends HTMLElement {
* @returns {void}
*/
set disabled (value) {
this.$select.setAttribute('disabled', value);
this.$select.setAttribute('disabled', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const currentObj = this;
const currentObj = this
this.$select.addEventListener('change', () => {
const value = this.$select.value;
const closeEvent = new CustomEvent('change', { detail: { value } });
currentObj.dispatchEvent(closeEvent);
currentObj.value = value;
});
const value = this.$select.value
const closeEvent = new CustomEvent('change', { detail: { value } })
currentObj.dispatchEvent(closeEvent)
currentObj.value = value
})
}
}
// Register
customElements.define('se-select', SeSelect);
customElements.define('se-select', SeSelect)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import '../dialogs/se-elix/define/NumberSpinBox.js';
import { t } from '../locale.js';
import '../dialogs/se-elix/define/NumberSpinBox.js'
import { t } from '../locale.js'
const template = document.createElement('template');
const template = document.createElement('template')
template.innerHTML = `
<style>
div {
@@ -49,7 +49,7 @@ template.innerHTML = `
<span id="label">label</span>
<elix-number-spin-box min="1" step="1"></elix-number-spin-box>
</div>
`;
`
/**
* @class SESpinInput
@@ -59,25 +59,27 @@ export class SESpinInput extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$div = this._shadowRoot.querySelector('div');
this.$img = this._shadowRoot.querySelector('img');
this.$label = this.shadowRoot.getElementById('label');
this.$event = new CustomEvent('change');
this.$input = this._shadowRoot.querySelector('elix-number-spin-box');
this.imgPath = svgEditor.configObj.curConfig.imgPath;
this.$div = this._shadowRoot.querySelector('div')
this.$img = this._shadowRoot.querySelector('img')
this.$label = this.shadowRoot.getElementById('label')
this.$event = new CustomEvent('change')
this.$input = this._shadowRoot.querySelector('elix-number-spin-box')
this.imgPath = svgEditor.configObj.curConfig.imgPath
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'value', 'label', 'src', 'size', 'min', 'max', 'step', 'title' ];
return ['value', 'label', 'src', 'size', 'min', 'max', 'step', 'title']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -86,52 +88,53 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'title':
{
const shortcut = this.getAttribute('shortcut');
this.$div.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`);
}
break;
case 'src':
this.$img.setAttribute('src', this.imgPath + '/' + newValue);
this.$label.remove();
this.$div.classList.add('imginside');
break;
case 'size':
case 'title':
{
const shortcut = this.getAttribute('shortcut')
this.$div.setAttribute('title', `${t(newValue)} ${shortcut ? `[${t(shortcut)}]` : ''}`)
}
break
case 'src':
this.$img.setAttribute('src', this.imgPath + '/' + newValue)
this.$label.remove()
this.$div.classList.add('imginside')
break
case 'size':
// access to the underlying input box
this.$input.shadowRoot.getElementById('input').size = newValue;
// below seems mandatory to override the default width style that takes precedence on size
this.$input.shadowRoot.getElementById('input').style.width = 'unset';
break;
case 'step':
this.$input.setAttribute('step', newValue);
break;
case 'min':
this.$input.setAttribute('min', newValue);
break;
case 'max':
this.$input.setAttribute('max', newValue);
break;
case 'label':
this.$label.textContent = t(newValue);
this.$img.remove();
break;
case 'value':
this.$input.value = newValue;
break;
default:
console.error(`unknown attribute: ${name}`);
break;
this.$input.shadowRoot.getElementById('input').size = newValue
// below seems mandatory to override the default width style that takes precedence on size
this.$input.shadowRoot.getElementById('input').style.width = 'unset'
break
case 'step':
this.$input.setAttribute('step', newValue)
break
case 'min':
this.$input.setAttribute('min', newValue)
break
case 'max':
this.$input.setAttribute('max', newValue)
break
case 'label':
this.$label.textContent = t(newValue)
this.$img.remove()
break
case 'value':
this.$input.value = newValue
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -139,14 +142,15 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get label () {
return this.getAttribute('label');
return this.getAttribute('label')
}
/**
@@ -154,14 +158,15 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
set label (value) {
this.setAttribute('label', value);
this.setAttribute('label', value)
}
/**
* @function get
* @returns {any}
*/
get value () {
return this.$input.value;
return this.$input.value
}
/**
@@ -169,14 +174,15 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
set value (value) {
this.$input.value = value;
this.$input.value = value
}
/**
* @function get
* @returns {any}
*/
get src () {
return this.getAttribute('src');
return this.getAttribute('src')
}
/**
@@ -184,7 +190,7 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
set src (value) {
this.setAttribute('src', value);
this.setAttribute('src', value)
}
/**
@@ -192,7 +198,7 @@ export class SESpinInput extends HTMLElement {
* @returns {any}
*/
get size () {
return this.getAttribute('size');
return this.getAttribute('size')
}
/**
@@ -200,7 +206,7 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
set size (value) {
this.setAttribute('size', value);
this.setAttribute('size', value)
}
/**
@@ -208,31 +214,31 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
connectedCallback () {
const shadow = this.$input.shadowRoot;
const childNodes = Array.from(shadow.childNodes);
childNodes.forEach( (childNode) => {
if(childNode?.id === "input") {
const shadow = this.$input.shadowRoot
const childNodes = Array.from(shadow.childNodes)
childNodes.forEach((childNode) => {
if (childNode?.id === 'input') {
childNode.addEventListener('keyup', (e) => {
e.preventDefault();
e.preventDefault()
if (!isNaN(e.target.value)) {
this.value = e.target.value;
this.dispatchEvent(this.$event);
this.value = e.target.value
this.dispatchEvent(this.$event)
}
});
})
}
});
})
this.$input.addEventListener('change', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
e.preventDefault()
this.value = e.target.value
this.dispatchEvent(this.$event)
})
this.$input.addEventListener('click', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
e.preventDefault()
this.value = e.target.value
this.dispatchEvent(this.$event)
})
}
}
// Register
customElements.define('se-spin-input', SESpinInput);
customElements.define('se-spin-input', SESpinInput)

View File

@@ -1,5 +1,5 @@
import { t } from '../locale.js';
const template = document.createElement('template');
import { t } from '../locale.js'
const template = document.createElement('template')
template.innerHTML = `
<style>
#layersLabel {
@@ -9,7 +9,7 @@ template.innerHTML = `
}
</style>
<div></div>
`;
`
/**
* @class SeText
*/
@@ -18,20 +18,22 @@ export class SeText extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
// locate the component
this.$div = this._shadowRoot.querySelector('div');
this.$div = this._shadowRoot.querySelector('div')
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'text', 'value', 'style', 'title', 'id' ];
return ['text', 'value', 'style', 'title', 'id']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -40,35 +42,36 @@ export class SeText extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'text':
this.$div.textContent = t(newValue);
break;
case 'title':
this.$div.setAttribute("title", t(newValue));
break;
case 'style':
this.$div.style = newValue;
break;
case 'id':
this.$div.id = newValue;
break;
case 'value':
this.$div.value = newValue;
//this.$div.setAttribute("value", newValue);
break;
default:
console.error(`unknown attribute: ${name}`);
break;
case 'text':
this.$div.textContent = t(newValue)
break
case 'title':
this.$div.setAttribute('title', t(newValue))
break
case 'style':
this.$div.style = newValue
break
case 'id':
this.$div.id = newValue
break
case 'value':
this.$div.value = newValue
// this.$div.setAttribute("value", newValue);
break
default:
console.error(`unknown attribute: ${name}`)
break
}
}
/**
* @function get
* @returns {any}
*/
get text () {
return this.$div.textContent;
return this.$div.textContent
}
/**
@@ -76,14 +79,15 @@ export class SeText extends HTMLElement {
* @returns {void}
*/
set text (value) {
this.$div.setAttribute("title", t(value));
this.$div.setAttribute('title', t(value))
}
/**
* @function get
* @returns {any}
*/
get value () {
return this.value;
return this.value
}
/**
@@ -91,14 +95,15 @@ export class SeText extends HTMLElement {
* @returns {void}
*/
set value (value) {
this.value = value;
this.value = value
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -106,8 +111,9 @@ export class SeText extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function connectedCallback
* @returns {void}
@@ -118,4 +124,4 @@ export class SeText extends HTMLElement {
}
// Register
customElements.define('se-text', SeText);
customElements.define('se-text', SeText)

View File

@@ -1,8 +1,8 @@
/* globals svgEditor */
import ListComboBox from 'elix/define/ListComboBox.js';
import * as internal from 'elix/src/base/internal.js';
import { templateFrom, fragmentFrom } from 'elix/src/core/htmlLiterals.js';
import NumberSpinBox from '../dialogs/se-elix/define/NumberSpinBox.js';
import ListComboBox from 'elix/define/ListComboBox.js'
import * as internal from 'elix/src/base/internal.js'
import { templateFrom, fragmentFrom } from 'elix/src/core/htmlLiterals.js'
import NumberSpinBox from '../dialogs/se-elix/define/NumberSpinBox.js'
/**
* @class Dropdown
@@ -17,20 +17,21 @@ class Zoom extends ListComboBox {
inputPartType: NumberSpinBox,
src: 'logo.svg',
inputsize: '100%'
});
})
}
/**
* @function get
* @returns {PlainObject}
*/
get [internal.template] () {
const result = super[internal.template];
const source = result.content.getElementById('source');
const result = super[internal.template]
const source = result.content.getElementById('source')
// add a icon before our dropdown
source.prepend(fragmentFrom.html`
<img src="zoom" alt="icon" width="18" height="18">
</img>
`.cloneNode(true));
`.cloneNode(true))
// change the style so it fits in our toolbar
result.content.append(
templateFrom.html`
@@ -57,16 +58,18 @@ class Zoom extends ListComboBox {
</style>
`.content
);
return result;
)
return result
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'src', 'inputsize', 'value' ];
return ['title', 'src', 'inputsize', 'value']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -75,97 +78,104 @@ class Zoom extends ListComboBox {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue && name !== "src") return;
if (oldValue === newValue && name !== 'src') return
switch (name) {
case 'title':
case 'title':
// this.$span.setAttribute('title', `${newValue} ${shortcut ? `[${shortcut}]` : ''}`);
break;
case 'src':
{
const { imgPath } = svgEditor.configObj.curConfig;
this.src = imgPath + '/' + newValue;
}
break;
case 'inputsize':
this.inputsize = newValue;
break;
default:
super.attributeChangedCallback(name, oldValue, newValue);
break;
break
case 'src':
{
const { imgPath } = svgEditor.configObj.curConfig
this.src = imgPath + '/' + 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);
super[internal.render](changed)
if (this[internal.firstRender]) {
this.$img = this.shadowRoot.querySelector('img');
this.$input = this.shadowRoot.getElementById('input');
this.$img = this.shadowRoot.querySelector('img')
this.$input = this.shadowRoot.getElementById('input')
}
if (changed.src) {
this.$img.setAttribute('src', this[internal.state].src);
this.$img.setAttribute('src', this[internal.state].src)
}
if (changed.inputsize) {
this.$input.shadowRoot.querySelector('[part~="input"]').style.width = this[internal.state].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');
e.preventDefault()
const value = e.detail?.closeResult?.getAttribute('value')
if (value) {
const closeEvent = new CustomEvent('change', { detail: { value } });
this.dispatchEvent(closeEvent);
const closeEvent = new CustomEvent('change', { detail: { value } })
this.dispatchEvent(closeEvent)
}
});
})
}
}
/**
* @function src
* @returns {string} src
*/
get src () {
return this[internal.state].src;
return this[internal.state].src
}
/**
* @function src
* @returns {void}
*/
set src (src) {
this[internal.setState]({ src });
this[internal.setState]({ src })
}
/**
* @function inputsize
* @returns {string} src
*/
get inputsize () {
return this[internal.state].inputsize;
return this[internal.state].inputsize
}
/**
* @function src
* @returns {void}
*/
set inputsize (inputsize) {
this[internal.setState]({ inputsize });
this[internal.setState]({ inputsize })
}
/**
* @function value
* @returns {string} src
*/
get value () {
return this[internal.state].value;
return this[internal.state].value
}
/**
* @function value
* @returns {void}
*/
set value (value) {
this[internal.setState]({ value });
this[internal.setState]({ value })
}
}
// Register
customElements.define('se-zoom', Zoom);
customElements.define('se-zoom', Zoom)

View File

@@ -5,7 +5,7 @@
* @author Adam Bender
*/
let contextMenuExtensions = {};
let contextMenuExtensions = {}
/**
* Signature depends on what the user adds; in the case of our uses with
@@ -27,8 +27,8 @@ let contextMenuExtensions = {};
* @returns {boolean}
*/
const menuItemIsValid = function (menuItem) {
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function';
};
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function'
}
/**
* @function module:contextmenu.add
@@ -42,15 +42,15 @@ export const add = function (menuItem) {
throw new TypeError(
'Menu items must be defined and have at least properties: ' +
'id, label, action, where action must be a function'
);
)
}
if (menuItem.id in contextMenuExtensions) {
throw new Error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
throw new Error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"')
}
// Register menuItem action, see below for deferred menu dom injection
contextMenuExtensions[menuItem.id] = menuItem;
contextMenuExtensions[menuItem.id] = menuItem
// TODO: Need to consider how to handle custom enable/disable behavior
};
}
/**
* @function module:contextmenu.hasCustomHandler
@@ -58,8 +58,8 @@ export const add = function (menuItem) {
* @returns {boolean}
*/
export const hasCustomHandler = function (handlerKey) {
return Boolean(contextMenuExtensions[handlerKey]);
};
return Boolean(contextMenuExtensions[handlerKey])
}
/**
* @function module:contextmenu.getCustomHandler
@@ -67,8 +67,8 @@ export const hasCustomHandler = function (handlerKey) {
* @returns {module:contextmenu.MenuItemAction}
*/
export const getCustomHandler = function (handlerKey) {
return contextMenuExtensions[handlerKey].action;
};
return contextMenuExtensions[handlerKey].action
}
/**
* @param {module:contextmenu.MenuItem} menuItem
@@ -78,12 +78,12 @@ const injectExtendedContextMenuItemIntoDom = function (menuItem) {
if (!Object.keys(contextMenuExtensions).length) {
// all menuItems appear at the bottom of the menu in their own container.
// if this is the first extension menu we need to add the separator.
document.getElementById('cmenu_canvas').appendChild(`<li class='separator'>`);
document.getElementById('cmenu_canvas').appendChild('<li class=\'separator\'>')
}
const shortcut = menuItem.shortcut || '';
const shortcut = menuItem.shortcut || ''
document.getElementById('cmenu_canvas').appendChild(`
<li class='disabled'><a href='#${menuItem.id}'>${menuItem.label}<span class='shortcut'>${shortcut}</span></a></li>`);
};
<li class='disabled'><a href='#${menuItem.id}'>${menuItem.label}<span class='shortcut'>${shortcut}</span></a></li>`)
}
/**
* @function module:contextmenu.injectExtendedContextMenuItemsIntoDom
@@ -91,11 +91,11 @@ const injectExtendedContextMenuItemIntoDom = function (menuItem) {
*/
export const injectExtendedContextMenuItemsIntoDom = function () {
Object.values(contextMenuExtensions).forEach((menuItem) => {
injectExtendedContextMenuItemIntoDom(menuItem);
});
};
injectExtendedContextMenuItemIntoDom(menuItem)
})
}
/**
* @function module:contextmenu.resetCustomMenus
* @returns {void}
*/
export const resetCustomMenus = function () { contextMenuExtensions = {}; };
export const resetCustomMenus = function () { contextMenuExtensions = {} }

View File

@@ -1,6 +1,6 @@
import PlainAlertDialog from 'elix/src/plain/PlainAlertDialog.js';
import { template } from 'elix/src/base/internal.js';
import { fragmentFrom } from 'elix/src/core/htmlLiterals.js';
import PlainAlertDialog from 'elix/src/plain/PlainAlertDialog.js'
import { template } from 'elix/src/base/internal.js'
import { fragmentFrom } from 'elix/src/core/htmlLiterals.js'
/**
* @class SePlainAlertDialog
@@ -11,9 +11,9 @@ export default class SePlainAlertDialog extends PlainAlertDialog {
* @returns {PlainObject}
*/
get [template] () {
const result = super[template];
const result = super[template]
// Replace the default slot with a new default slot and a button container.
const defaultSlot = result.content.querySelector('#frameContent');
const defaultSlot = result.content.querySelector('#frameContent')
if (defaultSlot) {
defaultSlot.replaceWith(fragmentFrom.html`
<div id="alertDialogContent">
@@ -22,7 +22,7 @@ export default class SePlainAlertDialog extends PlainAlertDialog {
</div>
<div id="choiceButtonContainer" part="choice-button-container"></div>
</div>
`);
`)
}
result.content.append(
fragmentFrom.html`
@@ -60,9 +60,9 @@ export default class SePlainAlertDialog extends PlainAlertDialog {
}
</style>
`
);
return result;
)
return result
}
}
customElements.define('se-elix-alert-dialog', SePlainAlertDialog);
customElements.define('se-elix-alert-dialog', SePlainAlertDialog)

View File

@@ -1,7 +1,6 @@
import cMenuDialogHTML from './cmenuDialog.html';
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = cMenuDialogHTML;
import cMenuDialogHTML from './cmenuDialog.html'
const template = document.createElement('template')
template.innerHTML = cMenuDialogHTML
/**
* @class SeCMenuDialog
*/
@@ -10,52 +9,55 @@ export class SeCMenuDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this._workarea = document.getElementById('workarea');
this.$dialog = this._shadowRoot.querySelector('#cmenu_canvas');
this.$copyLink = this._shadowRoot.querySelector('#se-copy');
this.$cutLink = this._shadowRoot.querySelector('#se-cut');
this.$pasteLink = this._shadowRoot.querySelector('#se-paste');
this.$pasteInPlaceLink = this._shadowRoot.querySelector('#se-paste-in-place');
this.$deleteLink = this._shadowRoot.querySelector('#se-delete');
this.$groupLink = this._shadowRoot.querySelector('#se-group');
this.$ungroupLink = this._shadowRoot.querySelector('#se-ungroup');
this.$moveFrontLink = this._shadowRoot.querySelector('#se-move-front');
this.$moveUpLink = this._shadowRoot.querySelector('#se-move-up');
this.$moveDownLink = this._shadowRoot.querySelector('#se-move-down');
this.$moveBackLink = this._shadowRoot.querySelector('#se-move-back');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this._workarea = document.getElementById('workarea')
this.$dialog = this._shadowRoot.querySelector('#cmenu_canvas')
this.$copyLink = this._shadowRoot.querySelector('#se-copy')
this.$cutLink = this._shadowRoot.querySelector('#se-cut')
this.$pasteLink = this._shadowRoot.querySelector('#se-paste')
this.$pasteInPlaceLink = this._shadowRoot.querySelector('#se-paste-in-place')
this.$deleteLink = this._shadowRoot.querySelector('#se-delete')
this.$groupLink = this._shadowRoot.querySelector('#se-group')
this.$ungroupLink = this._shadowRoot.querySelector('#se-ungroup')
this.$moveFrontLink = this._shadowRoot.querySelector('#se-move-front')
this.$moveUpLink = this._shadowRoot.querySelector('#se-move-up')
this.$moveDownLink = this._shadowRoot.querySelector('#se-move-down')
this.$moveBackLink = this._shadowRoot.querySelector('#se-move-back')
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('tools-cut', i18next.t('tools.cut'));
this.setAttribute('tools-copy', i18next.t('tools.copy'));
this.setAttribute('tools-paste', i18next.t('tools.paste'));
this.setAttribute('tools-paste_in_place', i18next.t('tools.paste_in_place'));
this.setAttribute('tools-delete', i18next.t('tools.delete'));
this.setAttribute('tools-group', i18next.t('tools.group'));
this.setAttribute('tools-ungroup', i18next.t('tools.ungroup'));
this.setAttribute('tools-move_front', i18next.t('tools.move_front'));
this.setAttribute('tools-move_up', i18next.t('tools.move_up'));
this.setAttribute('tools-move_down', i18next.t('tools.move_down'));
this.setAttribute('tools-move_back', i18next.t('tools.move_back'));
this.setAttribute('tools-cut', i18next.t('tools.cut'))
this.setAttribute('tools-copy', i18next.t('tools.copy'))
this.setAttribute('tools-paste', i18next.t('tools.paste'))
this.setAttribute('tools-paste_in_place', i18next.t('tools.paste_in_place'))
this.setAttribute('tools-delete', i18next.t('tools.delete'))
this.setAttribute('tools-group', i18next.t('tools.group'))
this.setAttribute('tools-ungroup', i18next.t('tools.ungroup'))
this.setAttribute('tools-move_front', i18next.t('tools.move_front'))
this.setAttribute('tools-move_up', i18next.t('tools.move_up'))
this.setAttribute('tools-move_down', i18next.t('tools.move_down'))
this.setAttribute('tools-move_back', i18next.t('tools.move_back'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'disableallmenu', 'enablemenuitems', 'disablemenuitems', 'tools-cut',
return ['disableallmenu', 'enablemenuitems', 'disablemenuitems', 'tools-cut',
'tools-copy', 'tools-paste', 'tools-paste_in_place', 'tools-delete', 'tools-group',
'tools-ungroup', 'tools-move_front', 'tools-move_up', 'tools-move_down',
'tools-move_back' ];
'tools-move_back']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -64,85 +66,86 @@ export class SeCMenuDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let eles = [];
let textnode;
const sdowRoot = this._shadowRoot;
let eles = []
let textnode
const sdowRoot = this._shadowRoot
switch (name) {
case 'disableallmenu':
if (newValue === 'true') {
const elesli = sdowRoot.querySelectorAll('li');
elesli.forEach(function (eleli) {
eleli.classList.add('disabled');
});
}
break;
case 'enablemenuitems':
eles = newValue.split(',');
eles.forEach(function (ele) {
const selEle = sdowRoot.querySelector('a[href*="' + ele + '"]');
selEle.parentElement.classList.remove('disabled');
});
break;
case 'disablemenuitems':
eles = newValue.split(',');
eles.forEach(function (ele) {
const selEle = sdowRoot.querySelector('a[href*="' + ele + '"]');
selEle.parentElement.classList.add('disabled');
});
break;
case 'tools-cut':
textnode = document.createTextNode(newValue);
this.$cutLink.prepend(textnode);
break;
case 'tools-copy':
textnode = document.createTextNode(newValue);
this.$copyLink.prepend(textnode);
break;
case 'tools-paste':
this.$pasteLink.textContent = newValue;
break;
case 'tools-paste_in_place':
this.$pasteInPlaceLink.textContent = newValue;
break;
case 'tools-delete':
textnode = document.createTextNode(newValue);
this.$deleteLink.prepend(textnode);
break;
case 'tools-group':
textnode = document.createTextNode(newValue);
this.$groupLink.prepend(textnode);
break;
case 'tools-ungroup':
textnode = document.createTextNode(newValue);
this.$ungroupLink.prepend(textnode);
break;
case 'tools-move_front':
textnode = document.createTextNode(newValue);
this.$moveFrontLink.prepend(textnode);
break;
case 'tools-move_up':
textnode = document.createTextNode(newValue);
this.$moveUpLink.prepend(textnode);
break;
case 'tools-move_down':
textnode = document.createTextNode(newValue);
this.$moveDownLink.prepend(textnode);
break;
case 'tools-move_back':
textnode = document.createTextNode(newValue);
this.$moveBackLink.prepend(textnode);
break;
default:
case 'disableallmenu':
if (newValue === 'true') {
const elesli = sdowRoot.querySelectorAll('li')
elesli.forEach(function (eleli) {
eleli.classList.add('disabled')
})
}
break
case 'enablemenuitems':
eles = newValue.split(',')
eles.forEach(function (ele) {
const selEle = sdowRoot.querySelector('a[href*="' + ele + '"]')
selEle.parentElement.classList.remove('disabled')
})
break
case 'disablemenuitems':
eles = newValue.split(',')
eles.forEach(function (ele) {
const selEle = sdowRoot.querySelector('a[href*="' + ele + '"]')
selEle.parentElement.classList.add('disabled')
})
break
case 'tools-cut':
textnode = document.createTextNode(newValue)
this.$cutLink.prepend(textnode)
break
case 'tools-copy':
textnode = document.createTextNode(newValue)
this.$copyLink.prepend(textnode)
break
case 'tools-paste':
this.$pasteLink.textContent = newValue
break
case 'tools-paste_in_place':
this.$pasteInPlaceLink.textContent = newValue
break
case 'tools-delete':
textnode = document.createTextNode(newValue)
this.$deleteLink.prepend(textnode)
break
case 'tools-group':
textnode = document.createTextNode(newValue)
this.$groupLink.prepend(textnode)
break
case 'tools-ungroup':
textnode = document.createTextNode(newValue)
this.$ungroupLink.prepend(textnode)
break
case 'tools-move_front':
textnode = document.createTextNode(newValue)
this.$moveFrontLink.prepend(textnode)
break
case 'tools-move_up':
textnode = document.createTextNode(newValue)
this.$moveUpLink.prepend(textnode)
break
case 'tools-move_down':
textnode = document.createTextNode(newValue)
this.$moveDownLink.prepend(textnode)
break
case 'tools-move_back':
textnode = document.createTextNode(newValue)
this.$moveBackLink.prepend(textnode)
break
default:
// super.attributeChangedCallback(name, oldValue, newValue);
break;
break
}
}
/**
* @function get
* @returns {any}
*/
get disableallmenu () {
return this.getAttribute('disableallmenu');
return this.getAttribute('disableallmenu')
}
/**
@@ -150,14 +153,15 @@ export class SeCMenuDialog extends HTMLElement {
* @returns {void}
*/
set disableallmenu (value) {
this.setAttribute('disableallmenu', value);
this.setAttribute('disableallmenu', value)
}
/**
* @function get
* @returns {any}
*/
get enablemenuitems () {
return this.getAttribute('enablemenuitems');
return this.getAttribute('enablemenuitems')
}
/**
@@ -165,14 +169,15 @@ export class SeCMenuDialog extends HTMLElement {
* @returns {void}
*/
set enablemenuitems (value) {
this.setAttribute('enablemenuitems', value);
this.setAttribute('enablemenuitems', value)
}
/**
* @function get
* @returns {any}
*/
get disablemenuitems () {
return this.getAttribute('disablemenuitems');
return this.getAttribute('disablemenuitems')
}
/**
@@ -180,59 +185,62 @@ export class SeCMenuDialog extends HTMLElement {
* @returns {void}
*/
set disablemenuitems (value) {
this.setAttribute('disablemenuitems', value);
this.setAttribute('disablemenuitems', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const current = this;
const current = this
const onMenuOpenHandler = (e) => {
e.preventDefault();
e.preventDefault()
// Detect mouse position
let x = e.pageX;
let y = e.pageY;
let x = e.pageX
let y = e.pageY
const xOff = screen.width - 250; // menu width
const yOff = screen.height - (276 + 150); // menu height + bottom panel height and scroll bar
const xOff = screen.width - 250 // menu width
const yOff = screen.height - (276 + 150) // menu height + bottom panel height and scroll bar
if (x > xOff) {
x = xOff;
x = xOff
}
if (y > yOff) {
y = yOff;
y = yOff
}
current.$dialog.style.top = y + 'px';
current.$dialog.style.left = x + 'px';
current.$dialog.style.display = 'block';
};
current.$dialog.style.top = y + 'px'
current.$dialog.style.left = x + 'px'
current.$dialog.style.display = 'block'
}
const onMenuCloseHandler = (e) => {
if (e.button !== 2) {
current.$dialog.style.display = 'none';
current.$dialog.style.display = 'none'
}
};
}
const onMenuClickHandler = (e, action) => {
const triggerEvent = new CustomEvent('change', { detail: {
trigger: action
} });
this.dispatchEvent(triggerEvent);
};
this._workarea.addEventListener('contextmenu', onMenuOpenHandler);
this._workarea.addEventListener('mousedown', onMenuCloseHandler);
this.$cutLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'cut'));
this.$copyLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'copy'));
this.$pasteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'paste'));
this.$pasteInPlaceLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'paste_in_place'));
this.$deleteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'delete'));
this.$groupLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'group'));
this.$ungroupLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'ungroup'));
this.$moveFrontLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_front'));
this.$moveUpLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_up'));
this.$moveDownLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_down'));
this.$moveBackLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_back'));
const triggerEvent = new CustomEvent('change', {
detail: {
trigger: action
}
})
this.dispatchEvent(triggerEvent)
}
this._workarea.addEventListener('contextmenu', onMenuOpenHandler)
this._workarea.addEventListener('mousedown', onMenuCloseHandler)
this.$cutLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'cut'))
this.$copyLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'copy'))
this.$pasteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'paste'))
this.$pasteInPlaceLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'paste_in_place'))
this.$deleteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'delete'))
this.$groupLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'group'))
this.$ungroupLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'ungroup'))
this.$moveFrontLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_front'))
this.$moveUpLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_up'))
this.$moveDownLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_down'))
this.$moveBackLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'move_back'))
}
}
// Register
customElements.define('se-cmenu_canvas-dialog', SeCMenuDialog);
customElements.define('se-cmenu_canvas-dialog', SeCMenuDialog)

View File

@@ -1,8 +1,7 @@
import cMenuLayersDialog from './cmenuLayersDialog.html';
import cMenuLayersDialog from './cmenuLayersDialog.html'
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = cMenuLayersDialog;
const template = document.createElement('template')
template.innerHTML = cMenuLayersDialog
/**
* @class SeCMenuLayerDialog
*/
@@ -11,37 +10,40 @@ export class SeCMenuLayerDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.source = '';
this._workarea = undefined;
this.$sidePanels = document.getElementById('sidepanels');
this.$dialog = this._shadowRoot.querySelector('#cmenu_layers');
this.$duplicateLink = this._shadowRoot.querySelector('#se-dupe');
this.$deleteLink = this._shadowRoot.querySelector('#se-layer-delete');
this.$mergeDownLink = this._shadowRoot.querySelector('#se-merge-down');
this.$mergeAllLink = this._shadowRoot.querySelector('#se-merge-all');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.source = ''
this._workarea = undefined
this.$sidePanels = document.getElementById('sidepanels')
this.$dialog = this._shadowRoot.querySelector('#cmenu_layers')
this.$duplicateLink = this._shadowRoot.querySelector('#se-dupe')
this.$deleteLink = this._shadowRoot.querySelector('#se-layer-delete')
this.$mergeDownLink = this._shadowRoot.querySelector('#se-merge-down')
this.$mergeAllLink = this._shadowRoot.querySelector('#se-merge-all')
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('layers-dupe', i18next.t('layers.dupe'));
this.setAttribute('layers-del', i18next.t('layers.del'));
this.setAttribute('layers-merge_down', i18next.t('layers.merge_down'));
this.setAttribute('layers-merge_all', i18next.t('layers.merge_all'));
this.setAttribute('layers-dupe', i18next.t('layers.dupe'))
this.setAttribute('layers-del', i18next.t('layers.del'))
this.setAttribute('layers-merge_down', i18next.t('layers.merge_down'))
this.setAttribute('layers-merge_all', i18next.t('layers.merge_all'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'value', 'leftclick', 'layers-dupe', 'layers-del', 'layers-merge_down', 'layers-merge_all' ];
return ['value', 'leftclick', 'layers-dupe', 'layers-del', 'layers-merge_down', 'layers-merge_all']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -50,37 +52,38 @@ export class SeCMenuLayerDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
if (oldValue === newValue) return
switch (name) {
case 'value':
this.source = newValue;
if (newValue !== '' && newValue !== undefined) {
this._workarea = document.getElementById(this.source);
}
break;
case 'layers-dupe':
this.$duplicateLink.textContent = newValue;
break;
case 'layers-del':
this.$deleteLink.textContent = newValue;
break;
case 'layers-merge_down':
this.$mergeDownLink.textContent = newValue;
break;
case 'layers-merge_all':
this.$mergeAllLink.textContent = newValue;
break;
default:
case 'value':
this.source = newValue
if (newValue !== '' && newValue !== undefined) {
this._workarea = document.getElementById(this.source)
}
break
case 'layers-dupe':
this.$duplicateLink.textContent = newValue
break
case 'layers-del':
this.$deleteLink.textContent = newValue
break
case 'layers-merge_down':
this.$mergeDownLink.textContent = newValue
break
case 'layers-merge_all':
this.$mergeAllLink.textContent = newValue
break
default:
// super.attributeChangedCallback(name, oldValue, newValue);
break;
break
}
}
/**
* @function get
* @returns {any}
*/
get value () {
return this.getAttribute('value');
return this.getAttribute('value')
}
/**
@@ -88,14 +91,15 @@ export class SeCMenuLayerDialog extends HTMLElement {
* @returns {void}
*/
set value (value) {
this.setAttribute('value', value);
this.setAttribute('value', value)
}
/**
* @function get
* @returns {any}
*/
get leftclick () {
return this.getAttribute('leftclick');
return this.getAttribute('leftclick')
}
/**
@@ -103,47 +107,50 @@ export class SeCMenuLayerDialog extends HTMLElement {
* @returns {void}
*/
set leftclick (value) {
this.setAttribute('leftclick', value);
this.setAttribute('leftclick', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const current = this;
const current = this
const onMenuOpenHandler = (e) => {
e.preventDefault();
current.$dialog.style.top = e.pageY + 'px';
current.$dialog.style.left = e.pageX - 126 + 'px';
current.$dialog.style.display = 'block';
};
e.preventDefault()
current.$dialog.style.top = e.pageY + 'px'
current.$dialog.style.left = e.pageX - 126 + 'px'
current.$dialog.style.display = 'block'
}
const onMenuCloseHandler = (e) => {
if (e.button !== 2) {
current.$dialog.style.display = 'none';
current.$dialog.style.display = 'none'
}
};
const onMenuClickHandler = (e, action, id) => {
const triggerEvent = new CustomEvent('change', { detail: {
trigger: action,
source: id
} });
this.dispatchEvent(triggerEvent);
current.$dialog.style.display = 'none';
};
if (this._workarea !== undefined) {
this._workarea.addEventListener('contextmenu', onMenuOpenHandler);
if (this.getAttribute('leftclick') === 'true') {
this._workarea.addEventListener('click', onMenuOpenHandler);
}
this._workarea.addEventListener('mousedown', onMenuCloseHandler);
this.$sidePanels.addEventListener('mousedown', onMenuCloseHandler);
}
this.$duplicateLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'dupe', this.source));
this.$deleteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'delete', this.source));
this.$mergeDownLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'merge_down', this.source));
this.$mergeAllLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'merge_all', this.source));
const onMenuClickHandler = (e, action, id) => {
const triggerEvent = new CustomEvent('change', {
detail: {
trigger: action,
source: id
}
})
this.dispatchEvent(triggerEvent)
current.$dialog.style.display = 'none'
}
if (this._workarea !== undefined) {
this._workarea.addEventListener('contextmenu', onMenuOpenHandler)
if (this.getAttribute('leftclick') === 'true') {
this._workarea.addEventListener('click', onMenuOpenHandler)
}
this._workarea.addEventListener('mousedown', onMenuCloseHandler)
this.$sidePanels.addEventListener('mousedown', onMenuCloseHandler)
}
this.$duplicateLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'dupe', this.source))
this.$deleteLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'delete', this.source))
this.$mergeDownLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'merge_down', this.source))
this.$mergeAllLink.addEventListener('click', (evt) => onMenuClickHandler(evt, 'merge_all', this.source))
}
}
// Register
customElements.define('se-cmenu-layers', SeCMenuLayerDialog);
customElements.define('se-cmenu-layers', SeCMenuLayerDialog)

View File

@@ -1,7 +1,6 @@
import editorPreferencesDialog from './editorPreferencesDialog.html';
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = editorPreferencesDialog;
import editorPreferencesDialog from './editorPreferencesDialog.html'
const template = document.createElement('template')
template.innerHTML = editorPreferencesDialog
/**
* @class SeEditPrefsDialog
*/
@@ -10,52 +9,55 @@ export class SeEditPrefsDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this.colorBlocks = [ '#FFF', '#888', '#000', 'chessboard' ];
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$dialog = this._shadowRoot.querySelector('#svg_prefs');
this.$saveBtn = this._shadowRoot.querySelector('#tool_prefs_save');
this.$cancelBtn = this._shadowRoot.querySelector('#tool_prefs_cancel');
this.$langSelect = this._shadowRoot.querySelector('#lang_select');
this.$bgBlocks = this._shadowRoot.querySelector('#bg_blocks');
this.$bgURL = this._shadowRoot.querySelector('#canvas_bg_url');
this.$gridSnappingOn = this._shadowRoot.querySelector('#grid_snapping_on');
this.$gridSnappingStep = this._shadowRoot.querySelector('#grid_snapping_step');
this.$gridColor = this._shadowRoot.querySelector('#grid_color');
this.$showRulers = this._shadowRoot.querySelector('#show_rulers');
this.$baseUnit = this._shadowRoot.querySelector('#base_unit');
this.colorBlocks = ['#FFF', '#888', '#000', 'chessboard']
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$dialog = this._shadowRoot.querySelector('#svg_prefs')
this.$saveBtn = this._shadowRoot.querySelector('#tool_prefs_save')
this.$cancelBtn = this._shadowRoot.querySelector('#tool_prefs_cancel')
this.$langSelect = this._shadowRoot.querySelector('#lang_select')
this.$bgBlocks = this._shadowRoot.querySelector('#bg_blocks')
this.$bgURL = this._shadowRoot.querySelector('#canvas_bg_url')
this.$gridSnappingOn = this._shadowRoot.querySelector('#grid_snapping_on')
this.$gridSnappingStep = this._shadowRoot.querySelector('#grid_snapping_step')
this.$gridColor = this._shadowRoot.querySelector('#grid_color')
this.$showRulers = this._shadowRoot.querySelector('#show_rulers')
this.$baseUnit = this._shadowRoot.querySelector('#base_unit')
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('common-ok', i18next.t('common.ok'));
this.setAttribute('common-cancel', i18next.t('common.cancel'));
this.setAttribute('config-editor_prefs', i18next.t('config.editor_prefs'));
this.setAttribute('config-language', i18next.t('config.language'));
this.setAttribute('config-background', i18next.t('config.background'));
this.setAttribute('common-url', i18next.t('common.url'));
this.setAttribute('config-editor_bg_note', i18next.t('config.editor_bg_note'));
this.setAttribute('config-grid', i18next.t('config.grid'));
this.setAttribute('config-snapping_onoff', i18next.t('config.snapping_onoff'));
this.setAttribute('config-snapping_stepsize', i18next.t('config.snapping_stepsize'));
this.setAttribute('config-grid_color', i18next.t('config.grid_color'));
this.setAttribute('config-units_and_rulers', i18next.t('config.units_and_rulers'));
this.setAttribute('config-show_rulers', i18next.t('config.show_rulers'));
this.setAttribute('config-base_unit', i18next.t('config.base_unit'));
this.setAttribute('common-ok', i18next.t('common.ok'))
this.setAttribute('common-cancel', i18next.t('common.cancel'))
this.setAttribute('config-editor_prefs', i18next.t('config.editor_prefs'))
this.setAttribute('config-language', i18next.t('config.language'))
this.setAttribute('config-background', i18next.t('config.background'))
this.setAttribute('common-url', i18next.t('common.url'))
this.setAttribute('config-editor_bg_note', i18next.t('config.editor_bg_note'))
this.setAttribute('config-grid', i18next.t('config.grid'))
this.setAttribute('config-snapping_onoff', i18next.t('config.snapping_onoff'))
this.setAttribute('config-snapping_stepsize', i18next.t('config.snapping_stepsize'))
this.setAttribute('config-grid_color', i18next.t('config.grid_color'))
this.setAttribute('config-units_and_rulers', i18next.t('config.units_and_rulers'))
this.setAttribute('config-show_rulers', i18next.t('config.show_rulers'))
this.setAttribute('config-base_unit', i18next.t('config.base_unit'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
// eslint-disable-next-line max-len
return [ 'dialog', 'lang', 'canvasbg', 'bgurl', 'gridsnappingon', 'gridsnappingstep', 'gridcolor', 'showrulers', 'baseunit', 'common-ok', 'common-cancel', 'config-editor_prefs', 'config-language', 'config-background', 'common-url', 'config-editor_bg_note', 'config-grid', 'config-snapping_onoff', 'config-snapping_stepsize', 'config-grid_color', 'config-units_and_rulers', 'config-show_rulers', 'config-base_unit' ];
return ['dialog', 'lang', 'canvasbg', 'bgurl', 'gridsnappingon', 'gridsnappingstep', 'gridcolor', 'showrulers', 'baseunit', 'common-ok', 'common-cancel', 'config-editor_prefs', 'config-language', 'config-background', 'common-url', 'config-editor_bg_note', 'config-grid', 'config-snapping_onoff', 'config-snapping_stepsize', 'config-grid_color', 'config-units_and_rulers', 'config-show_rulers', 'config-base_unit']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -64,128 +66,129 @@ export class SeEditPrefsDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
const blocks = this.$bgBlocks.querySelectorAll('div');
const curBg = 'cur_background';
let node;
if (oldValue === newValue) return
const blocks = this.$bgBlocks.querySelectorAll('div')
const curBg = 'cur_background'
let node
switch (name) {
case 'dialog':
if (newValue === 'open') {
this.$dialog.open();
} else {
this.$dialog.close();
}
break;
case 'lang':
this.$langSelect.value = newValue;
break;
case 'canvasbg':
if (!newValue) {
if (blocks.length > 0) {
blocks[0].classList.add(curBg);
case 'dialog':
if (newValue === 'open') {
this.$dialog.open()
} else {
this.$dialog.close()
}
} else {
blocks.forEach(function (blk) {
const isBg = blk.dataset.bgColor === newValue;
if (isBg) {
blk.classList.add(curBg);
} else {
blk.classList.remove(curBg);
break
case 'lang':
this.$langSelect.value = newValue
break
case 'canvasbg':
if (!newValue) {
if (blocks.length > 0) {
blocks[0].classList.add(curBg)
}
});
}
break;
case 'bgurl':
this.$bgURL.value = newValue;
break;
case 'gridsnappingon':
if (newValue === 'true') {
this.$gridSnappingOn.checked = true;
} else if (newValue === 'false') {
this.$gridSnappingOn.checked = false;
}
break;
case 'gridsnappingstep':
this.$gridSnappingStep.value = newValue;
break;
case 'gridcolor':
this.$gridColor.value = newValue;
break;
case 'showrulers':
if (newValue === 'true') {
this.$showRulers.checked = true;
} else if (newValue === 'false') {
this.$showRulers.checked = false;
}
break;
case 'baseunit':
this.$baseUnit.value = newValue;
break;
case 'common-ok':
this.$saveBtn.textContent = newValue;
break;
case 'common-cancel':
this.$cancelBtn.textContent = newValue;
break;
case 'config-editor_prefs':
node = this._shadowRoot.querySelector('#svginfo_editor_prefs');
node.textContent = newValue;
break;
case 'config-language':
node = this._shadowRoot.querySelector('#svginfo_lang');
node.textContent = newValue;
break;
case 'config-background':
node = this._shadowRoot.querySelector('#svginfo_change_background');
node.textContent = newValue;
break;
case 'common-url':
node = this._shadowRoot.querySelector('#svginfo_bg_url');
node.textContent = newValue;
break;
case 'config-editor_bg_note':
node = this._shadowRoot.querySelector('#svginfo_bg_note');
node.textContent = newValue;
break;
case 'config-grid':
node = this._shadowRoot.querySelector('#svginfo_grid_settings');
node.textContent = newValue;
break;
case 'config-snapping_onoff':
node = this._shadowRoot.querySelector('#svginfo_snap_onoff');
node.textContent = newValue;
break;
case 'config-snapping_stepsize':
node = this._shadowRoot.querySelector('#svginfo_snap_step');
node.textContent = newValue;
break;
case 'config-grid_color':
node = this._shadowRoot.querySelector('#svginfo_grid_color');
node.textContent = newValue;
break;
case 'config-units_and_rulers':
node = this._shadowRoot.querySelector('#svginfo_units_rulers');
node.textContent = newValue;
break;
case 'config-show_rulers':
node = this._shadowRoot.querySelector('#svginfo_rulers_onoff');
node.textContent = newValue;
break;
case 'config-base_unit':
node = this._shadowRoot.querySelector('#svginfo_unit');
node.textContent = newValue;
break;
default:
super.attributeChangedCallback(name, oldValue, newValue);
break;
} else {
blocks.forEach(function (blk) {
const isBg = blk.dataset.bgColor === newValue
if (isBg) {
blk.classList.add(curBg)
} else {
blk.classList.remove(curBg)
}
})
}
break
case 'bgurl':
this.$bgURL.value = newValue
break
case 'gridsnappingon':
if (newValue === 'true') {
this.$gridSnappingOn.checked = true
} else if (newValue === 'false') {
this.$gridSnappingOn.checked = false
}
break
case 'gridsnappingstep':
this.$gridSnappingStep.value = newValue
break
case 'gridcolor':
this.$gridColor.value = newValue
break
case 'showrulers':
if (newValue === 'true') {
this.$showRulers.checked = true
} else if (newValue === 'false') {
this.$showRulers.checked = false
}
break
case 'baseunit':
this.$baseUnit.value = newValue
break
case 'common-ok':
this.$saveBtn.textContent = newValue
break
case 'common-cancel':
this.$cancelBtn.textContent = newValue
break
case 'config-editor_prefs':
node = this._shadowRoot.querySelector('#svginfo_editor_prefs')
node.textContent = newValue
break
case 'config-language':
node = this._shadowRoot.querySelector('#svginfo_lang')
node.textContent = newValue
break
case 'config-background':
node = this._shadowRoot.querySelector('#svginfo_change_background')
node.textContent = newValue
break
case 'common-url':
node = this._shadowRoot.querySelector('#svginfo_bg_url')
node.textContent = newValue
break
case 'config-editor_bg_note':
node = this._shadowRoot.querySelector('#svginfo_bg_note')
node.textContent = newValue
break
case 'config-grid':
node = this._shadowRoot.querySelector('#svginfo_grid_settings')
node.textContent = newValue
break
case 'config-snapping_onoff':
node = this._shadowRoot.querySelector('#svginfo_snap_onoff')
node.textContent = newValue
break
case 'config-snapping_stepsize':
node = this._shadowRoot.querySelector('#svginfo_snap_step')
node.textContent = newValue
break
case 'config-grid_color':
node = this._shadowRoot.querySelector('#svginfo_grid_color')
node.textContent = newValue
break
case 'config-units_and_rulers':
node = this._shadowRoot.querySelector('#svginfo_units_rulers')
node.textContent = newValue
break
case 'config-show_rulers':
node = this._shadowRoot.querySelector('#svginfo_rulers_onoff')
node.textContent = newValue
break
case 'config-base_unit':
node = this._shadowRoot.querySelector('#svginfo_unit')
node.textContent = newValue
break
default:
super.attributeChangedCallback(name, oldValue, newValue)
break
}
}
/**
* @function get
* @returns {any}
*/
get lang () {
return this.getAttribute('lang');
return this.getAttribute('lang')
}
/**
@@ -193,173 +196,194 @@ export class SeEditPrefsDialog extends HTMLElement {
* @returns {void}
*/
set lang (value) {
this.setAttribute('lang', value);
this.setAttribute('lang', value)
}
/**
* @function get
* @returns {any}
*/
get canvasbg () {
return this.getAttribute('canvasbg');
return this.getAttribute('canvasbg')
}
/**
* @function set
* @returns {void}
*/
set canvasbg (value) {
this.setAttribute('canvasbg', value);
this.setAttribute('canvasbg', value)
}
/**
* @function get
* @returns {any}
*/
get bgurl () {
return this.getAttribute('bgurl');
return this.getAttribute('bgurl')
}
/**
* @function set
* @returns {void}
*/
set bgurl (value) {
this.setAttribute('bgurl', value);
this.setAttribute('bgurl', value)
}
/**
* @function get
* @returns {any}
*/
get dialog () {
return this.getAttribute('dialog');
return this.getAttribute('dialog')
}
/**
* @function set
* @returns {void}
*/
set dialog (value) {
this.setAttribute('dialog', value);
this.setAttribute('dialog', value)
}
/**
* @function get
* @returns {any}
*/
get gridsnappingon () {
return this.getAttribute('gridsnappingon');
return this.getAttribute('gridsnappingon')
}
/**
* @function set
* @returns {void}
*/
set gridsnappingon (value) {
this.setAttribute('gridsnappingon', value);
this.setAttribute('gridsnappingon', value)
}
/**
* @function get
* @returns {any}
*/
get gridsnappingstep () {
return this.getAttribute('gridsnappingstep');
return this.getAttribute('gridsnappingstep')
}
/**
* @function set
* @returns {void}
*/
set gridsnappingstep (value) {
this.setAttribute('gridsnappingstep', value);
this.setAttribute('gridsnappingstep', value)
}
/**
* @function get
* @returns {any}
*/
get gridcolor () {
return this.getAttribute('gridcolor');
return this.getAttribute('gridcolor')
}
/**
* @function set
* @returns {void}
*/
set gridcolor (value) {
this.setAttribute('gridcolor', value);
this.setAttribute('gridcolor', value)
}
/**
* @function get
* @returns {any}
*/
get showrulers () {
return this.getAttribute('showrulers');
return this.getAttribute('showrulers')
}
/**
* @function set
* @returns {void}
*/
set showrulers (value) {
this.setAttribute('showrulers', value);
this.setAttribute('showrulers', value)
}
/**
* @function get
* @returns {any}
*/
get baseunit () {
return this.getAttribute('baseunit');
return this.getAttribute('baseunit')
}
/**
* @function set
* @returns {void}
*/
set baseunit (value) {
this.setAttribute('baseunit', value);
this.setAttribute('baseunit', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const onCancelHandler = () => {
const closeEvent = new CustomEvent('change', { detail: {
dialog: 'closed'
} });
this.dispatchEvent(closeEvent);
};
const closeEvent = new CustomEvent('change', {
detail: {
dialog: 'closed'
}
})
this.dispatchEvent(closeEvent)
}
const onSaveHandler = () => {
const color = this.$bgBlocks.querySelector('.cur_background').dataset.bgColor || '#FFF';
const closeEvent = new CustomEvent('change', { detail: {
lang: this.$langSelect.value,
dialog: 'close',
bgcolor: color,
bgurl: this.$bgURL.value,
gridsnappingon: this.$gridSnappingOn.checked,
gridsnappingstep: this.$gridSnappingStep.value,
showrulers: this.$showRulers.checked,
baseunit: this.$baseUnit.value
} });
this.dispatchEvent(closeEvent);
};
const color = this.$bgBlocks.querySelector('.cur_background').dataset.bgColor || '#FFF'
const closeEvent = new CustomEvent('change', {
detail: {
lang: this.$langSelect.value,
dialog: 'close',
bgcolor: color,
bgurl: this.$bgURL.value,
gridsnappingon: this.$gridSnappingOn.checked,
gridsnappingstep: this.$gridSnappingStep.value,
showrulers: this.$showRulers.checked,
baseunit: this.$baseUnit.value
}
})
this.dispatchEvent(closeEvent)
}
// Set up editor background functionality
const currentObj = this;
const currentObj = this
this.colorBlocks.forEach(function (e) {
const newdiv = document.createElement('div');
const newdiv = document.createElement('div')
if (e === 'chessboard') {
newdiv.dataset.bgColor = e;
newdiv.style.backgroundImage = 'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7)';
newdiv.classList.add('color_block');
newdiv.dataset.bgColor = e
newdiv.style.backgroundImage = 'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7)'
newdiv.classList.add('color_block')
} else {
newdiv.dataset.bgColor = e; // setAttribute('data-bgcolor', e);
newdiv.style.backgroundColor = e;
newdiv.classList.add('color_block');
newdiv.dataset.bgColor = e // setAttribute('data-bgcolor', e);
newdiv.style.backgroundColor = e
newdiv.classList.add('color_block')
}
currentObj.$bgBlocks.append(newdiv);
});
const blocks = this.$bgBlocks.querySelectorAll('div');
const curBg = 'cur_background';
currentObj.$bgBlocks.append(newdiv)
})
const blocks = this.$bgBlocks.querySelectorAll('div')
const curBg = 'cur_background'
blocks.forEach(function (blk) {
blk.addEventListener('click', function () {
blocks.forEach((el) => el.classList.remove(curBg));
blk.classList.add(curBg);
});
});
this.$saveBtn.addEventListener('click', onSaveHandler);
this.$cancelBtn.addEventListener('click', onCancelHandler);
this.$dialog.addEventListener('close', onCancelHandler);
blocks.forEach((el) => el.classList.remove(curBg))
blk.classList.add(curBg)
})
})
this.$saveBtn.addEventListener('click', onSaveHandler)
this.$cancelBtn.addEventListener('click', onCancelHandler)
this.$dialog.addEventListener('close', onCancelHandler)
}
}
// Register
customElements.define('se-edit-prefs-dialog', SeEditPrefsDialog);
customElements.define('se-edit-prefs-dialog', SeEditPrefsDialog)

View File

@@ -1,9 +1,8 @@
import './se-elix/define/NumberSpinBox.js';
import './se-elix/define/NumberSpinBox.js'
import exportDialogHTML from './exportDialog.html';
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = exportDialogHTML;
import exportDialogHTML from './exportDialog.html'
const template = document.createElement('template')
template.innerHTML = exportDialogHTML
/**
* @class SeExportDialog
*/
@@ -12,36 +11,39 @@ export class SeExportDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$dialog = this._shadowRoot.querySelector('#export_box');
this.$okBtn = this._shadowRoot.querySelector('#export_ok');
this.$cancelBtn = this._shadowRoot.querySelector('#export_cancel');
this.$exportOption = this._shadowRoot.querySelector('#se-storage-pref');
this.$qualityCont = this._shadowRoot.querySelector('#se-quality');
this.$input = this._shadowRoot.querySelector('elix-number-spin-box');
this.value = 1;
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$dialog = this._shadowRoot.querySelector('#export_box')
this.$okBtn = this._shadowRoot.querySelector('#export_ok')
this.$cancelBtn = this._shadowRoot.querySelector('#export_cancel')
this.$exportOption = this._shadowRoot.querySelector('#se-storage-pref')
this.$qualityCont = this._shadowRoot.querySelector('#se-quality')
this.$input = this._shadowRoot.querySelector('elix-number-spin-box')
this.value = 1
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('common-ok', i18next.t('common.ok'));
this.setAttribute('common-cancel', i18next.t('common.cancel'));
this.setAttribute('ui-quality', i18next.t('ui.quality'));
this.setAttribute('ui-export_type_label', i18next.t('ui.export_type_label'));
this.setAttribute('common-ok', i18next.t('common.ok'))
this.setAttribute('common-cancel', i18next.t('common.cancel'))
this.setAttribute('ui-quality', i18next.t('ui.quality'))
this.setAttribute('ui-export_type_label', i18next.t('ui.export_type_label'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'dialog', 'common-ok', 'common-cancel', 'ui-quality', 'ui-export_type_label' ];
return ['dialog', 'common-ok', 'common-cancel', 'ui-quality', 'ui-export_type_label']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -50,86 +52,91 @@ export class SeExportDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let node;
let node
switch (name) {
case 'dialog':
if (newValue === 'open') {
this.$dialog.open();
} else {
this.$dialog.close();
}
break;
case 'common-ok':
this.$okBtn.textContent = newValue;
break;
case 'common-cancel':
this.$cancelBtn.textContent = newValue;
break;
case 'ui-quality':
node = this._shadowRoot.querySelector('#se-quality');
node.prepend(newValue);
break;
case 'ui-export_type_label':
node = this._shadowRoot.querySelector('#export_select');
node.textContent = newValue;
break;
default:
case 'dialog':
if (newValue === 'open') {
this.$dialog.open()
} else {
this.$dialog.close()
}
break
case 'common-ok':
this.$okBtn.textContent = newValue
break
case 'common-cancel':
this.$cancelBtn.textContent = newValue
break
case 'ui-quality':
node = this._shadowRoot.querySelector('#se-quality')
node.prepend(newValue)
break
case 'ui-export_type_label':
node = this._shadowRoot.querySelector('#export_select')
node.textContent = newValue
break
default:
// super.attributeChangedCallback(name, oldValue, newValue);
break;
break
}
}
/**
* @function get
* @returns {any}
*/
get dialog () {
return this.getAttribute('dialog');
return this.getAttribute('dialog')
}
/**
* @function set
* @returns {void}
*/
set dialog (value) {
this.setAttribute('dialog', value);
this.setAttribute('dialog', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
this.$input.addEventListener('change', (e) => {
e.preventDefault();
this.value = e.target.value;
});
e.preventDefault()
this.value = e.target.value
})
this.$input.addEventListener('click', (e) => {
e.preventDefault();
this.value = e.target.value;
});
e.preventDefault()
this.value = e.target.value
})
const onSubmitHandler = (e, action) => {
if (action === 'cancel') {
document.getElementById('se-export-dialog').setAttribute('dialog', 'close');
document.getElementById('se-export-dialog').setAttribute('dialog', 'close')
} else {
const triggerEvent = new CustomEvent('change', { detail: {
trigger: action,
imgType: this.$exportOption.value,
quality: this.value
} });
this.dispatchEvent(triggerEvent);
document.getElementById('se-export-dialog').setAttribute('dialog', 'close');
const triggerEvent = new CustomEvent('change', {
detail: {
trigger: action,
imgType: this.$exportOption.value,
quality: this.value
}
})
this.dispatchEvent(triggerEvent)
document.getElementById('se-export-dialog').setAttribute('dialog', 'close')
}
};
}
const onChangeHandler = (e) => {
if (e.target.value === 'PDF') {
this.$qualityCont.style.display = 'none';
this.$qualityCont.style.display = 'none'
} else {
this.$qualityCont.style.display = 'block';
this.$qualityCont.style.display = 'block'
}
};
this.$okBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'ok'));
this.$cancelBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'cancel'));
this.$exportOption.addEventListener('change', (evt) => onChangeHandler(evt));
}
this.$okBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'ok'))
this.$cancelBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'cancel'))
this.$exportOption.addEventListener('change', (evt) => onChangeHandler(evt))
}
}
// Register
customElements.define('se-export-dialog', SeExportDialog);
customElements.define('se-export-dialog', SeExportDialog)

View File

@@ -1,9 +1,8 @@
import { isValidUnit } from '../../common/units.js';
import imagePropertiesDialogHTML from './imagePropertiesDialog.html';
import { isValidUnit } from '../../common/units.js'
import imagePropertiesDialogHTML from './imagePropertiesDialog.html'
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = imagePropertiesDialogHTML;
const template = document.createElement('template')
template.innerHTML = imagePropertiesDialogHTML
/**
* @class SeImgPropDialog
*/
@@ -12,39 +11,40 @@ export class SeImgPropDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this.eventlisten = false;
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$saveBtn = this._shadowRoot.querySelector('#tool_docprops_save');
this.$cancelBtn = this._shadowRoot.querySelector('#tool_docprops_cancel');
this.$resolution = this._shadowRoot.querySelector('#resolution');
this.$canvasTitle = this._shadowRoot.querySelector('#canvas_title');
this.$canvasWidth = this._shadowRoot.querySelector('#canvas_width');
this.$canvasHeight = this._shadowRoot.querySelector('#canvas_height');
this.$imageOptEmbed = this._shadowRoot.querySelector('#image_embed');
this.$imageOptRef = this._shadowRoot.querySelector('#image_ref');
this.$dialog = this._shadowRoot.querySelector('#svg_docprops');
this.eventlisten = false
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$saveBtn = this._shadowRoot.querySelector('#tool_docprops_save')
this.$cancelBtn = this._shadowRoot.querySelector('#tool_docprops_cancel')
this.$resolution = this._shadowRoot.querySelector('#resolution')
this.$canvasTitle = this._shadowRoot.querySelector('#canvas_title')
this.$canvasWidth = this._shadowRoot.querySelector('#canvas_width')
this.$canvasHeight = this._shadowRoot.querySelector('#canvas_height')
this.$imageOptEmbed = this._shadowRoot.querySelector('#image_embed')
this.$imageOptRef = this._shadowRoot.querySelector('#image_ref')
this.$dialog = this._shadowRoot.querySelector('#svg_docprops')
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('common-ok', i18next.t('common.ok'));
this.setAttribute('common-cancel', i18next.t('common.cancel'));
this.setAttribute('config-image_props', i18next.t('config.image_props'));
this.setAttribute('config-doc_title', i18next.t('config.doc_title'));
this.setAttribute('config-doc_dims', i18next.t('config.doc_dims'));
this.setAttribute('common-width', i18next.t('common.width'));
this.setAttribute('common-height', i18next.t('common.height'));
this.setAttribute('config-select_predefined', i18next.t('config.select_predefined'));
this.setAttribute('tools-fit-to-content', i18next.t('tools.fitToContent'));
this.setAttribute('config-included_images', i18next.t('config.included_images'));
this.setAttribute('config-image_opt_embed', i18next.t('config.image_opt_embed'));
this.setAttribute('config-image_opt_ref', i18next.t('config.image_opt_ref'));
this.setAttribute('common-ok', i18next.t('common.ok'))
this.setAttribute('common-cancel', i18next.t('common.cancel'))
this.setAttribute('config-image_props', i18next.t('config.image_props'))
this.setAttribute('config-doc_title', i18next.t('config.doc_title'))
this.setAttribute('config-doc_dims', i18next.t('config.doc_dims'))
this.setAttribute('common-width', i18next.t('common.width'))
this.setAttribute('common-height', i18next.t('common.height'))
this.setAttribute('config-select_predefined', i18next.t('config.select_predefined'))
this.setAttribute('tools-fit-to-content', i18next.t('tools.fitToContent'))
this.setAttribute('config-included_images', i18next.t('config.included_images'))
this.setAttribute('config-image_opt_embed', i18next.t('config.image_opt_embed'))
this.setAttribute('config-image_opt_ref', i18next.t('config.image_opt_ref'))
}
/**
@@ -52,12 +52,13 @@ export class SeImgPropDialog extends HTMLElement {
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'width', 'height', 'save', 'dialog', 'embed', 'common-ok',
return ['title', 'width', 'height', 'save', 'dialog', 'embed', 'common-ok',
'common-cancel', 'config-image_props', 'config-doc_title', 'config-doc_dims',
'common-width', 'common-height', 'config-select_predefined',
'tools-fit-to-content', 'config-included_images', 'config-image_opt_embed',
'config-image_opt_ref' ];
'config-image_opt_ref']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -66,117 +67,118 @@ export class SeImgPropDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
let node ;
if (oldValue === newValue) return
let node
switch (name) {
case 'title':
this.$canvasTitle.value = newValue;
break;
case 'width':
if (newValue === 'fit') {
this.$canvasWidth.removeAttribute('disabled');
this.$canvasWidth.value = 100;
this.$canvasHeight.removeAttribute('disabled');
this.$canvasHeight.value = 100;
} else {
this.$canvasWidth.value = newValue;
}
break;
case 'height':
if (newValue === 'fit') {
this.$canvasWidth.removeAttribute('disabled');
this.$canvasWidth.value = 100;
this.$canvasHeight.removeAttribute('disabled');
this.$canvasHeight.value = 100;
} else {
this.$canvasHeight.value = newValue;
}
break;
case 'dialog':
if (this.eventlisten) {
if (newValue === 'open') {
this.$dialog.open();
case 'title':
this.$canvasTitle.value = newValue
break
case 'width':
if (newValue === 'fit') {
this.$canvasWidth.removeAttribute('disabled')
this.$canvasWidth.value = 100
this.$canvasHeight.removeAttribute('disabled')
this.$canvasHeight.value = 100
} else {
this.$dialog.close();
this.$canvasWidth.value = newValue
}
}
break;
case 'save':
if (newValue === 'ref') {
this.$imageOptEmbed.setAttribute('checked', false);
this.$imageOptRef.setAttribute('checked', true);
} else {
this.$imageOptEmbed.setAttribute('checked', true);
this.$imageOptRef.setAttribute('checked', false);
}
break;
case 'embed':
if (newValue.includes('one')) {
const data = newValue.split('|');
if (data.length > 1) {
this._shadowRoot.querySelector('#image_opt_embed').setAttribute('title', data[1]);
this._shadowRoot.querySelector('#image_opt_embed').setAttribute('disabled', 'disabled');
this._shadowRoot.querySelector('#image_opt_embed').style.color = '#666';
break
case 'height':
if (newValue === 'fit') {
this.$canvasWidth.removeAttribute('disabled')
this.$canvasWidth.value = 100
this.$canvasHeight.removeAttribute('disabled')
this.$canvasHeight.value = 100
} else {
this.$canvasHeight.value = newValue
}
}
break;
case 'common-ok':
this.$saveBtn.textContent = newValue;
break;
case 'common-cancel':
this.$cancelBtn.textContent = newValue;
break;
case 'config-image_props':
node = this._shadowRoot.querySelector('#svginfo_image_props');
node.textContent = newValue;
break;
case 'config-doc_title':
node = this._shadowRoot.querySelector('#svginfo_title');
node.textContent = newValue;
break;
case 'config-doc_dims':
node = this._shadowRoot.querySelector('#svginfo_dim');
node.textContent = newValue;
break;
case 'common-width':
node = this._shadowRoot.querySelector('#svginfo_width');
node.textContent = newValue;
break;
case 'common-height':
node = this._shadowRoot.querySelector('#svginfo_height');
node.textContent = newValue;
break;
case 'config-select_predefined':
node = this._shadowRoot.querySelector('#selectedPredefined');
node.textContent = newValue;
break;
case 'tools-fit-to-content':
node = this._shadowRoot.querySelector('#fitToContent');
node.textContent = newValue;
break;
case 'config-included_images':
node = this._shadowRoot.querySelector('#includedImages');
node.textContent = newValue;
break;
case 'config-image_opt_embed':
node = this._shadowRoot.querySelector('#image_opt_embed');
node.textContent = newValue;
break;
case 'config-image_opt_ref':
node = this._shadowRoot.querySelector('#image_opt_ref');
node.textContent = newValue;
break;
default:
super.attributeChangedCallback(name, oldValue, newValue);
break;
break
case 'dialog':
if (this.eventlisten) {
if (newValue === 'open') {
this.$dialog.open()
} else {
this.$dialog.close()
}
}
break
case 'save':
if (newValue === 'ref') {
this.$imageOptEmbed.setAttribute('checked', false)
this.$imageOptRef.setAttribute('checked', true)
} else {
this.$imageOptEmbed.setAttribute('checked', true)
this.$imageOptRef.setAttribute('checked', false)
}
break
case 'embed':
if (newValue.includes('one')) {
const data = newValue.split('|')
if (data.length > 1) {
this._shadowRoot.querySelector('#image_opt_embed').setAttribute('title', data[1])
this._shadowRoot.querySelector('#image_opt_embed').setAttribute('disabled', 'disabled')
this._shadowRoot.querySelector('#image_opt_embed').style.color = '#666'
}
}
break
case 'common-ok':
this.$saveBtn.textContent = newValue
break
case 'common-cancel':
this.$cancelBtn.textContent = newValue
break
case 'config-image_props':
node = this._shadowRoot.querySelector('#svginfo_image_props')
node.textContent = newValue
break
case 'config-doc_title':
node = this._shadowRoot.querySelector('#svginfo_title')
node.textContent = newValue
break
case 'config-doc_dims':
node = this._shadowRoot.querySelector('#svginfo_dim')
node.textContent = newValue
break
case 'common-width':
node = this._shadowRoot.querySelector('#svginfo_width')
node.textContent = newValue
break
case 'common-height':
node = this._shadowRoot.querySelector('#svginfo_height')
node.textContent = newValue
break
case 'config-select_predefined':
node = this._shadowRoot.querySelector('#selectedPredefined')
node.textContent = newValue
break
case 'tools-fit-to-content':
node = this._shadowRoot.querySelector('#fitToContent')
node.textContent = newValue
break
case 'config-included_images':
node = this._shadowRoot.querySelector('#includedImages')
node.textContent = newValue
break
case 'config-image_opt_embed':
node = this._shadowRoot.querySelector('#image_opt_embed')
node.textContent = newValue
break
case 'config-image_opt_ref':
node = this._shadowRoot.querySelector('#image_opt_ref')
node.textContent = newValue
break
default:
super.attributeChangedCallback(name, oldValue, newValue)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -184,78 +186,89 @@ export class SeImgPropDialog extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get width () {
return this.getAttribute('width');
return this.getAttribute('width')
}
/**
* @function set
* @returns {void}
*/
set width (value) {
this.setAttribute('width', value);
this.setAttribute('width', value)
}
/**
* @function get
* @returns {any}
*/
get height () {
return this.getAttribute('height');
return this.getAttribute('height')
}
/**
* @function set
* @returns {void}
*/
set height (value) {
this.setAttribute('height', value);
this.setAttribute('height', value)
}
/**
* @function get
* @returns {any}
*/
get save () {
return this.getAttribute('save');
return this.getAttribute('save')
}
/**
* @function set
* @returns {void}
*/
set save (value) {
this.setAttribute('save', value);
this.setAttribute('save', value)
}
/**
* @function get
* @returns {any}
*/
get dialog () {
return this.getAttribute('dialog');
return this.getAttribute('dialog')
}
/**
* @function set
* @returns {void}
*/
set dialog (value) {
this.setAttribute('dialog', value);
this.setAttribute('dialog', value)
}
/**
* @function get
* @returns {any}
*/
get embed () {
return this.getAttribute('embed');
return this.getAttribute('embed')
}
/**
* @function set
* @returns {void}
*/
set embed (value) {
this.setAttribute('embed', value);
this.setAttribute('embed', value)
}
/**
* @function connectedCallback
* @returns {void}
@@ -264,72 +277,76 @@ export class SeImgPropDialog extends HTMLElement {
const onChangeHandler = (ev) => {
if (!ev.target.selectedIndex) {
if (this.$canvasWidth.getAttribute('value') === 'fit') {
this.$canvasWidth.removeAttribute('disabled');
this.$canvasWidth.value = 100;
this.$canvasHeight.removeAttribute('disabled');
this.$canvasHeight.value = 100;
this.$canvasWidth.removeAttribute('disabled')
this.$canvasWidth.value = 100
this.$canvasHeight.removeAttribute('disabled')
this.$canvasHeight.value = 100
}
} else if (ev.target.value === 'content') {
this.$canvasWidth.setAttribute('disabled', 'disabled');
this.$canvasWidth.value = 'fit';
this.$canvasHeight.setAttribute('disabled', 'disabled');
this.$canvasHeight.value = 'fit';
this.$canvasWidth.setAttribute('disabled', 'disabled')
this.$canvasWidth.value = 'fit'
this.$canvasHeight.setAttribute('disabled', 'disabled')
this.$canvasHeight.value = 'fit'
} else {
const dims = ev.target.value.split('x');
this.$canvasWidth.value = dims[0];
this.$canvasWidth.removeAttribute('disabled');
this.$canvasHeight.value = dims[1];
this.$canvasHeight.removeAttribute('disabled');
const dims = ev.target.value.split('x')
this.$canvasWidth.value = dims[0]
this.$canvasWidth.removeAttribute('disabled')
this.$canvasHeight.value = dims[1]
this.$canvasHeight.removeAttribute('disabled')
}
};
}
const onSaveHandler = () => {
let saveOpt = '';
const w = this.$canvasWidth.value;
const h = this.$canvasHeight.value;
let saveOpt = ''
const w = this.$canvasWidth.value
const h = this.$canvasHeight.value
if (w !== 'fit' && !isValidUnit('width', w)) {
this.$canvasWidth.parentElement.classList.add('error');
this.$canvasWidth.parentElement.classList.add('error')
} else {
this.$canvasWidth.parentElement.classList.remove('error');
this.$canvasWidth.parentElement.classList.remove('error')
}
if (h !== 'fit' && !isValidUnit('height', w)) {
this.$canvasHeight.parentElement.classList.add('error');
this.$canvasHeight.parentElement.classList.add('error')
} else {
this.$canvasHeight.parentElement.classList.remove('error');
this.$canvasHeight.parentElement.classList.remove('error')
}
if (this.$imageOptEmbed.getAttribute('checked') === 'true') {
saveOpt = 'embed';
saveOpt = 'embed'
}
if (this.$imageOptRef.getAttribute('checked') === 'true') {
saveOpt = 'ref';
saveOpt = 'ref'
}
const closeEvent = new CustomEvent('change', { detail: {
title: this.$canvasTitle.value,
w: this.$canvasWidth.value,
h: this.$canvasHeight.value,
save: saveOpt,
dialog: 'close'
} });
this.$canvasWidth.removeAttribute('disabled');
this.$canvasHeight.removeAttribute('disabled');
this.$resolution.selectedIndex = 0;
this.dispatchEvent(closeEvent);
};
const closeEvent = new CustomEvent('change', {
detail: {
title: this.$canvasTitle.value,
w: this.$canvasWidth.value,
h: this.$canvasHeight.value,
save: saveOpt,
dialog: 'close'
}
})
this.$canvasWidth.removeAttribute('disabled')
this.$canvasHeight.removeAttribute('disabled')
this.$resolution.selectedIndex = 0
this.dispatchEvent(closeEvent)
}
const onCancelHandler = () => {
const closeEvent = new CustomEvent('change', { detail: {
dialog: 'closed'
} });
this.$canvasWidth.removeAttribute('disabled');
this.$canvasHeight.removeAttribute('disabled');
this.$resolution.selectedIndex = 0;
this.dispatchEvent(closeEvent);
};
this.$resolution.addEventListener('change', onChangeHandler);
this.$saveBtn.addEventListener('click', onSaveHandler);
this.$cancelBtn.addEventListener('click', onCancelHandler);
this.$dialog.addEventListener('close', onCancelHandler);
this.eventlisten = true;
const closeEvent = new CustomEvent('change', {
detail: {
dialog: 'closed'
}
})
this.$canvasWidth.removeAttribute('disabled')
this.$canvasHeight.removeAttribute('disabled')
this.$resolution.selectedIndex = 0
this.dispatchEvent(closeEvent)
}
this.$resolution.addEventListener('change', onChangeHandler)
this.$saveBtn.addEventListener('click', onSaveHandler)
this.$cancelBtn.addEventListener('click', onCancelHandler)
this.$dialog.addEventListener('close', onCancelHandler)
this.eventlisten = true
}
}
// Register
customElements.define('se-img-prop-dialog', SeImgPropDialog);
customElements.define('se-img-prop-dialog', SeImgPropDialog)

View File

@@ -1,11 +1,11 @@
import 'elix/define/Dialog.js';
import './imagePropertiesDialog.js';
import './editorPreferencesDialog.js';
import './svgSourceDialog.js';
import './cmenuDialog.js';
import './cmenuLayersDialog.js';
import './seSelectDialog.js';
import './seConfirmDialog.js';
import './sePromptDialog.js';
import './seAlertDialog.js';
import './exportDialog.js';
import 'elix/define/Dialog.js'
import './imagePropertiesDialog.js'
import './editorPreferencesDialog.js'
import './svgSourceDialog.js'
import './cmenuDialog.js'
import './cmenuLayersDialog.js'
import './seSelectDialog.js'
import './seConfirmDialog.js'
import './sePromptDialog.js'
import './seAlertDialog.js'
import './exportDialog.js'

View File

@@ -1,8 +1,7 @@
import PlainNumberSpinBox from '../src/plain/PlainNumberSpinBox.js';
import PlainNumberSpinBox from '../src/plain/PlainNumberSpinBox.js'
/**
* @class ElixNumberSpinBox
*/
export default class ElixNumberSpinBox extends PlainNumberSpinBox {}
customElements.define('elix-number-spin-box', ElixNumberSpinBox);
customElements.define('elix-number-spin-box', ElixNumberSpinBox)

View File

@@ -3,10 +3,10 @@ import {
setState,
state,
stateEffects
} from 'elix/src/base/internal.js';
} from 'elix/src/base/internal.js'
import {
SpinBox
} from 'elix/src/base/SpinBox.js';
} from 'elix/src/base/SpinBox.js'
/**
* @class NumberSpinBox
@@ -21,15 +21,16 @@ class NumberSpinBox extends SpinBox {
*/
attributeChangedCallback (name, oldValue, newValue) {
if (name === 'max') {
this.max = parseFloat(newValue);
this.max = parseFloat(newValue)
} else if (name === 'min') {
this.min = parseFloat(newValue);
this.min = parseFloat(newValue)
} else if (name === 'step') {
this.step = parseFloat(newValue);
this.step = parseFloat(newValue)
} else {
super.attributeChangedCallback(name, oldValue, newValue);
super.attributeChangedCallback(name, oldValue, newValue)
}
}
/**
* @function observedAttributes
* @returns {any} observed
@@ -39,7 +40,7 @@ class NumberSpinBox extends SpinBox {
max: null,
min: null,
step: 1
});
})
}
/**
@@ -54,7 +55,7 @@ class NumberSpinBox extends SpinBox {
* @returns {number}
*/
formatValue (value, precision) {
return Number(value).toFixed(precision);
return Number(value).toFixed(precision)
}
/**
@@ -64,8 +65,9 @@ class NumberSpinBox extends SpinBox {
* @default 1
*/
get max () {
return this[state].max;
return this[state].max
}
/**
* The maximum allowable value of the `value` property.
*
@@ -75,7 +77,7 @@ class NumberSpinBox extends SpinBox {
set max (max) {
this[setState]({
max
});
})
}
/**
@@ -85,8 +87,9 @@ class NumberSpinBox extends SpinBox {
* @default 1
*/
get min () {
return this[state].min;
return this[state].min
}
/**
* @function set
* @returns {void}
@@ -94,7 +97,7 @@ class NumberSpinBox extends SpinBox {
set min (min) {
this[setState]({
min
});
})
}
/**
@@ -104,9 +107,10 @@ class NumberSpinBox extends SpinBox {
* @returns {int}
*/
parseValue (value, precision) {
const parsed = precision === 0 ? parseInt(value) : parseFloat(value);
return isNaN(parsed) ? 0 : parsed;
const parsed = precision === 0 ? parseInt(value) : parseFloat(value)
return isNaN(parsed) ? 0 : parsed
}
/**
* @function stateEffects
* @param {any} state
@@ -114,19 +118,19 @@ class NumberSpinBox extends SpinBox {
* @returns {any}
*/
[stateEffects] (state, changed) {
const effects = super[stateEffects];
const effects = super[stateEffects]
// If step changed, calculate its precision (number of digits after
// the decimal).
if (changed.step) {
const {
step
} = state;
const decimalRegex = /\.(\d)+$/;
const match = decimalRegex.exec(String(step));
const precision = match && match[1] ? match[1].length : 0;
} = state
const decimalRegex = /\.(\d)+$/
const match = decimalRegex.exec(String(step))
const precision = match && match[1] ? match[1].length : 0
Object.assign(effects, {
precision
});
})
}
if (changed.max || changed.min || changed.value) {
@@ -140,41 +144,41 @@ class NumberSpinBox extends SpinBox {
min,
precision,
value
} = state;
const parsed = parseInt(value, precision);
} = state
const parsed = parseInt(value, precision)
if (value !== '' && isNaN(parsed)) {
Object.assign(effects, {
valid: false,
validationMessage: 'Value must be a number'
});
})
} else if (!(max === null || parsed <= max)) {
Object.assign(effects, {
valid: false,
validationMessage: `Value must be less than or equal to ${max}.`
});
})
} else if (!(min === null || parsed >= min)) {
Object.assign(effects, {
valid: false,
validationMessage: `Value must be greater than or equal to ${min}.`
});
})
} else {
Object.assign(effects, {
valid: true,
validationMessage: ''
});
})
}
// We can only go up if we're below max.
Object.assign(effects, {
canGoUp: isNaN(parsed) || state.max === null || parsed <= state.max
});
})
// We can only go down if we're above min.
Object.assign(effects, {
canGoDown: isNaN(parsed) || state.min === null || parsed >= state.min
});
})
}
return effects;
return effects
}
/**
@@ -182,8 +186,9 @@ class NumberSpinBox extends SpinBox {
* @returns {any}
*/
get step () {
return this[state].step;
return this[state].step
}
/**
* @function set
* @returns {void}
@@ -192,7 +197,7 @@ class NumberSpinBox extends SpinBox {
if (!isNaN(step)) {
this[setState]({
step
});
})
}
}
@@ -201,21 +206,21 @@ class NumberSpinBox extends SpinBox {
* @returns {void}
*/
stepDown () {
super.stepDown();
super.stepDown()
const {
max,
precision,
value
} = this[state];
let result = this.parseValue(value, precision) - this.step;
} = this[state]
let result = this.parseValue(value, precision) - this.step
if (max !== null) {
result = Math.min(result, max);
result = Math.min(result, max)
}
const {
min
} = this[state];
} = this[state]
if (min === null || result >= min) {
this.value = this.formatValue(result, precision);
this.value = this.formatValue(result, precision)
}
}
@@ -224,23 +229,23 @@ class NumberSpinBox extends SpinBox {
* @returns {void}
*/
stepUp () {
super.stepUp();
super.stepUp()
const {
min,
precision,
value
} = this[state];
let result = this.parseValue(value, precision) + this.step;
} = this[state]
let result = this.parseValue(value, precision) + this.step
if (min !== null) {
result = Math.max(result, min);
result = Math.max(result, min)
}
const {
max
} = this[state];
} = this[state]
if (max === null || result <= max) {
this.value = this.formatValue(result, precision);
this.value = this.formatValue(result, precision)
}
}
}
export default NumberSpinBox;
export default NumberSpinBox

View File

@@ -1,9 +1,9 @@
import PlainSpinBoxMixin from 'elix/src/plain/PlainSpinBoxMixin.js';
import NumberSpinBox from '../base/NumberSpinBox.js';
import PlainSpinBoxMixin from 'elix/src/plain/PlainSpinBoxMixin.js'
import NumberSpinBox from '../base/NumberSpinBox.js'
/**
* @class PlainNumberSpinBox
*/
class PlainNumberSpinBox extends PlainSpinBoxMixin(NumberSpinBox) {}
export default PlainNumberSpinBox;
export default PlainNumberSpinBox

View File

@@ -1,10 +1,10 @@
import SePlainAlertDialog from './SePlainAlertDialog.js';
import SePlainAlertDialog from './SePlainAlertDialog.js'
const seAlert = (text) => {
const dialog = new SePlainAlertDialog();
dialog.textContent = text;
dialog.choices = [ 'Ok' ];
dialog.open();
};
const dialog = new SePlainAlertDialog()
dialog.textContent = text
dialog.choices = ['Ok']
dialog.open()
}
window.seAlert = seAlert;
window.seAlert = seAlert

View File

@@ -1,12 +1,12 @@
import SePlainAlertDialog from './SePlainAlertDialog.js';
import SePlainAlertDialog from './SePlainAlertDialog.js'
const seConfirm = async (text, choices) => {
const dialog = new SePlainAlertDialog();
dialog.textContent = text;
dialog.choices = (choices === undefined) ? [ 'Ok', 'Cancel' ] : choices;
dialog.open();
const response = await dialog.whenClosed();
return response.choice;
};
const dialog = new SePlainAlertDialog()
dialog.textContent = text
dialog.choices = (choices === undefined) ? ['Ok', 'Cancel'] : choices
dialog.open()
const response = await dialog.whenClosed()
return response.choice
}
window.seConfirm = seConfirm;
window.seConfirm = seConfirm

View File

@@ -1,4 +1,4 @@
import SePlainAlertDialog from './SePlainAlertDialog.js';
import SePlainAlertDialog from './SePlainAlertDialog.js'
/**
* @class SePromptDialog
*/
@@ -7,18 +7,20 @@ export class SePromptDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this.dialog = new SePlainAlertDialog();
this._shadowRoot = this.attachShadow({ mode: 'open' })
this.dialog = new SePlainAlertDialog()
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'title', 'close' ];
return ['title', 'close']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -28,32 +30,33 @@ export class SePromptDialog extends HTMLElement {
*/
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();
} else {
this.dialog.open();
}
break;
default:
console.error('unknown attr for:', name, 'newValue =', newValue);
break;
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()
} else {
this.dialog.open()
}
break
default:
console.error('unknown attr for:', name, 'newValue =', newValue)
break
}
}
/**
* @function get
* @returns {any}
*/
get title () {
return this.getAttribute('title');
return this.getAttribute('title')
}
/**
@@ -61,14 +64,15 @@ export class SePromptDialog extends HTMLElement {
* @returns {void}
*/
set title (value) {
this.setAttribute('title', value);
this.setAttribute('title', value)
}
/**
* @function get
* @returns {any}
*/
get close () {
return this.getAttribute('close');
return this.getAttribute('close')
}
/**
@@ -78,12 +82,12 @@ export class SePromptDialog extends HTMLElement {
set close (value) {
// boolean value => existence = true
if (value) {
this.setAttribute('close', 'true');
this.setAttribute('close', 'true')
} else {
this.removeAttribute('close');
this.removeAttribute('close')
}
}
}
// Register
customElements.define('se-prompt-dialog', SePromptDialog);
customElements.define('se-prompt-dialog', SePromptDialog)

View File

@@ -1,12 +1,12 @@
import SePlainAlertDialog from './SePlainAlertDialog.js';
import SePlainAlertDialog from './SePlainAlertDialog.js'
const seSelect = async (text, choices) => {
const dialog = new SePlainAlertDialog();
dialog.textContent = text;
dialog.choices = choices;
dialog.open();
const response = await dialog.whenClosed();
return response.choice;
};
const dialog = new SePlainAlertDialog()
dialog.textContent = text
dialog.choices = choices
dialog.open()
const response = await dialog.whenClosed()
return response.choice
}
window.seSelect = seSelect;
window.seSelect = seSelect

View File

@@ -1,8 +1,7 @@
import svgSourceDialogHTML from './svgSourceDialog.html';
import svgSourceDialogHTML from './svgSourceDialog.html'
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = svgSourceDialogHTML;
const template = document.createElement('template')
template.innerHTML = svgSourceDialogHTML
/**
* @class SeSvgSourceEditorDialog
*/
@@ -11,36 +10,39 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(template.content.cloneNode(true));
this.$dialog = this._shadowRoot.querySelector('#svg_source_editor');
this.$copyBtn = this._shadowRoot.querySelector('#copy_save_done');
this.$saveBtn = this._shadowRoot.querySelector('#tool_source_save');
this.$cancelBtn = this._shadowRoot.querySelector('#tool_source_cancel');
this.$sourceTxt = this._shadowRoot.querySelector('#svg_source_textarea');
this.$copySec = this._shadowRoot.querySelector('#save_output_btns');
this.$applySec = this._shadowRoot.querySelector('#tool_source_back');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(template.content.cloneNode(true))
this.$dialog = this._shadowRoot.querySelector('#svg_source_editor')
this.$copyBtn = this._shadowRoot.querySelector('#copy_save_done')
this.$saveBtn = this._shadowRoot.querySelector('#tool_source_save')
this.$cancelBtn = this._shadowRoot.querySelector('#tool_source_cancel')
this.$sourceTxt = this._shadowRoot.querySelector('#svg_source_textarea')
this.$copySec = this._shadowRoot.querySelector('#save_output_btns')
this.$applySec = this._shadowRoot.querySelector('#tool_source_back')
}
/**
* @function init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('tools-source_save', i18next.t('tools.source_save'));
this.setAttribute('common-cancel', i18next.t('common.cancel'));
this.setAttribute('notification-source_dialog_note', i18next.t('notification.source_dialog_note'));
this.setAttribute('config-done', i18next.t('config.done'));
this.setAttribute('tools-source_save', i18next.t('tools.source_save'))
this.setAttribute('common-cancel', i18next.t('common.cancel'))
this.setAttribute('notification-source_dialog_note', i18next.t('notification.source_dialog_note'))
this.setAttribute('config-done', i18next.t('config.done'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'dialog', 'value', 'applysec', 'copysec', 'tools-source_save', 'common-cancel', 'notification-source_dialog_note', 'config-done' ];
return ['dialog', 'value', 'applysec', 'copysec', 'tools-source_save', 'common-cancel', 'notification-source_dialog_note', 'config-done']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -49,51 +51,51 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
let node;
if (oldValue === newValue) return
let node
switch (name) {
case 'dialog':
if (newValue === 'open') {
this.$sourceTxt.focus();
this.$dialog.open();
} else {
this.$dialog.close();
this.$sourceTxt.blur();
}
break;
case 'applysec':
if (newValue === 'false') {
this.$applySec.style.display = 'none';
} else {
this.$applySec.style.display = 'block';
}
break;
case 'copysec':
if (newValue === 'false') {
this.$copySec.style.display = 'none';
} else {
this.$copySec.style.display = 'block';
}
break;
case 'value':
this.$sourceTxt.value = newValue;
break;
case 'tools-source_save':
this.$saveBtn.textContent = newValue;
break;
case 'common-cancel':
this.$cancelBtn.textContent = newValue;
break;
case 'notification-source_dialog_note':
node = this._shadowRoot.querySelector('#copy_save_note');
node.textContent = newValue;
break;
case 'config-done':
this.$copyBtn.textContent = newValue;
break;
default:
super.attributeChangedCallback(name, oldValue, newValue);
break;
case 'dialog':
if (newValue === 'open') {
this.$sourceTxt.focus()
this.$dialog.open()
} else {
this.$dialog.close()
this.$sourceTxt.blur()
}
break
case 'applysec':
if (newValue === 'false') {
this.$applySec.style.display = 'none'
} else {
this.$applySec.style.display = 'block'
}
break
case 'copysec':
if (newValue === 'false') {
this.$copySec.style.display = 'none'
} else {
this.$copySec.style.display = 'block'
}
break
case 'value':
this.$sourceTxt.value = newValue
break
case 'tools-source_save':
this.$saveBtn.textContent = newValue
break
case 'common-cancel':
this.$cancelBtn.textContent = newValue
break
case 'notification-source_dialog_note':
node = this._shadowRoot.querySelector('#copy_save_note')
node.textContent = newValue
break
case 'config-done':
this.$copyBtn.textContent = newValue
break
default:
super.attributeChangedCallback(name, oldValue, newValue)
break
}
}
@@ -102,14 +104,15 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @returns {any}
*/
get dialog () {
return this.getAttribute('dialog');
return this.getAttribute('dialog')
}
/**
* @function set
* @returns {void}
*/
set dialog (value) {
this.setAttribute('dialog', value);
this.setAttribute('dialog', value)
}
/**
@@ -117,14 +120,15 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @returns {any}
*/
get value () {
return this.getAttribute('value');
return this.getAttribute('value')
}
/**
* @function set
* @returns {void}
*/
set value (value) {
this.setAttribute('value', value);
this.setAttribute('value', value)
}
/**
@@ -132,14 +136,15 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @returns {any}
*/
get applysec () {
return this.getAttribute('applysec');
return this.getAttribute('applysec')
}
/**
* @function set
* @returns {void}
*/
set applysec (value) {
this.setAttribute('applysec', value);
this.setAttribute('applysec', value)
}
/**
@@ -147,48 +152,54 @@ export class SeSvgSourceEditorDialog extends HTMLElement {
* @returns {any}
*/
get copysec () {
return this.getAttribute('copysec');
return this.getAttribute('copysec')
}
/**
* @function set
* @returns {void}
*/
set copysec (value) {
this.setAttribute('copysec', value);
this.setAttribute('copysec', value)
}
/**
* @function connectedCallback
* @returns {void}
*/
connectedCallback () {
const onCancelHandler = () => {
const closeEvent = new CustomEvent('change', { detail: {
dialog: 'closed'
} });
this.dispatchEvent(closeEvent);
};
const closeEvent = new CustomEvent('change', {
detail: {
dialog: 'closed'
}
})
this.dispatchEvent(closeEvent)
}
const onCopyHandler = () => {
const closeEvent = new CustomEvent('change', {
detail: {
copy: 'click',
value: this.$sourceTxt.value
}
});
this.dispatchEvent(closeEvent);
};
})
this.dispatchEvent(closeEvent)
}
const onSaveHandler = () => {
const closeEvent = new CustomEvent('change', { detail: {
value: this.$sourceTxt.value,
dialog: 'close'
} });
this.dispatchEvent(closeEvent);
};
this.$copyBtn.addEventListener('click', onCopyHandler);
this.$saveBtn.addEventListener('click', onSaveHandler);
this.$cancelBtn.addEventListener('click', onCancelHandler);
this.$dialog.addEventListener('close', onCancelHandler);
const closeEvent = new CustomEvent('change', {
detail: {
value: this.$sourceTxt.value,
dialog: 'close'
}
})
this.dispatchEvent(closeEvent)
}
this.$copyBtn.addEventListener('click', onCopyHandler)
this.$saveBtn.addEventListener('click', onSaveHandler)
this.$cancelBtn.addEventListener('click', onCancelHandler)
this.$dialog.addEventListener('close', onCancelHandler)
}
}
// Register
customElements.define('se-svg-source-editor-dialog', SeSvgSourceEditorDialog);
customElements.define('se-svg-source-editor-dialog', SeSvgSourceEditorDialog)

View File

@@ -8,39 +8,41 @@
*
*/
const name = "eyedropper";
const name = 'eyedropper'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init() {
const svgEditor = this;
const { svgCanvas } = svgEditor;
await loadExtensionTranslation(svgEditor);
const { ChangeElementCommand } = svgCanvas.history;
async init () {
const svgEditor = this
const { svgCanvas } = svgEditor
await loadExtensionTranslation(svgEditor)
const { ChangeElementCommand } = svgCanvas.history
// svgdoc = S.svgroot.parentNode.ownerDocument,
const addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); };
const addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd) }
const currentStyle = {
fillPaint: 'red', fillOpacity: 1.0,
strokePaint: 'black', strokeOpacity: 1.0,
strokeWidth: 5, strokeDashArray: null,
fillPaint: 'red',
fillOpacity: 1.0,
strokePaint: 'black',
strokeOpacity: 1.0,
strokeWidth: 5,
strokeDashArray: null,
opacity: 1.0,
strokeLinecap: 'butt',
strokeLinejoin: 'miter'
};
const { $id } = svgCanvas;
}
const { $id } = svgCanvas
/**
*
@@ -49,79 +51,79 @@ export default {
*/
const getStyle = (opts) => {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
const mode = svgCanvas.getMode();
if (mode === 'eyedropper') { return; }
const mode = svgCanvas.getMode()
if (mode === 'eyedropper') { return }
const tool = $id('tool_eyedropper');
const tool = $id('tool_eyedropper')
// enable-eye-dropper if one element is selected
let elem = null;
let elem = null
if (!opts.multiselected && opts.elems[0] &&
![ 'svg', 'g', 'use' ].includes(opts.elems[0].nodeName)
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
) {
elem = opts.elems[0];
tool.classList.remove('disabled');
elem = opts.elems[0]
tool.classList.remove('disabled')
// grab the current style
currentStyle.fillPaint = elem.getAttribute('fill') || 'black';
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0;
currentStyle.strokePaint = elem.getAttribute('stroke');
currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0;
currentStyle.strokeWidth = elem.getAttribute('stroke-width');
currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray');
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap');
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin');
currentStyle.opacity = elem.getAttribute('opacity') || 1.0;
currentStyle.fillPaint = elem.getAttribute('fill') || 'black'
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0
currentStyle.strokePaint = elem.getAttribute('stroke')
currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0
currentStyle.strokeWidth = elem.getAttribute('stroke-width')
currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray')
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap')
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin')
currentStyle.opacity = elem.getAttribute('opacity') || 1.0
// disable eye-dropper tool
} else {
tool.classList.add('disabled');
tool.classList.add('disabled')
}
};
}
return {
name: svgEditor.i18next.t(`${name}:name`),
callback() {
callback () {
// Add the button and its handler(s)
const title = `${name}:buttons.0.title`;
const key = `${name}:buttons.0.key`;
const title = `${name}:buttons.0.title`
const key = `${name}:buttons.0.key`
const buttonTemplate = `
<se-button id="tool_eyedropper" title="${title}" src="eye_dropper.svg" shortcut=${key}></se-button>
`;
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 12);
$id('tool_eyedropper').addEventListener("click", () => {
if (this.leftPanel.updateLeftPanel("tool_eyedropper")) {
svgCanvas.setMode('eyedropper');
`
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 12)
$id('tool_eyedropper').addEventListener('click', () => {
if (this.leftPanel.updateLeftPanel('tool_eyedropper')) {
svgCanvas.setMode('eyedropper')
}
});
})
},
// if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle,
elementChanged: getStyle,
mouseDown(opts) {
const mode = svgCanvas.getMode();
mouseDown (opts) {
const mode = svgCanvas.getMode()
if (mode === 'eyedropper') {
const e = opts.event;
const { target } = e;
if (![ 'svg', 'g', 'use' ].includes(target.nodeName)) {
const changes = {};
const e = opts.event
const { target } = e
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
const changes = {}
const change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue);
};
changes[attrname] = elem.getAttribute(attrname)
elem.setAttribute(attrname, newvalue)
}
if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); }
if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); }
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); }
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); }
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); }
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); }
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); }
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); }
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); }
if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint) }
if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity) }
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint) }
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity) }
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth) }
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray) }
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity) }
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap) }
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin) }
addToHistory(new ChangeElementCommand(target, changes));
addToHistory(new ChangeElementCommand(target, changes))
}
}
}
};
}
}
};
}

View File

@@ -6,4 +6,4 @@ export default {
key: 'I'
}
]
};
}

View File

@@ -6,4 +6,4 @@ export default {
key: 'I'
}
]
};
}

View File

@@ -6,4 +6,4 @@ export default {
key: 'I'
}
]
};
}

View File

@@ -7,40 +7,39 @@
*
*/
const name = "grid";
const name = 'grid'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init () {
const svgEditor = this;
await loadExtensionTranslation(svgEditor);
const { svgCanvas } = svgEditor;
const { $id, NS } = svgCanvas;
const svgdoc = $id('svgcanvas').ownerDocument;
const { assignAttributes } = svgCanvas;
const hcanvas = document.createElement('canvas');
const canvBG = $id('canvasBackground');
const units = svgCanvas.getTypeMap(); // Assumes prior `init()` call on `units.js` module
const intervals = [ 0.01, 0.1, 1, 10, 100, 1000 ];
let showGrid = svgEditor.configObj.curConfig.showGrid || false;
const svgEditor = this
await loadExtensionTranslation(svgEditor)
const { svgCanvas } = svgEditor
const { $id, NS } = svgCanvas
const svgdoc = $id('svgcanvas').ownerDocument
const { assignAttributes } = svgCanvas
const hcanvas = document.createElement('canvas')
const canvBG = $id('canvasBackground')
const units = svgCanvas.getTypeMap() // Assumes prior `init()` call on `units.js` module
const intervals = [0.01, 0.1, 1, 10, 100, 1000]
let showGrid = svgEditor.configObj.curConfig.showGrid || false
hcanvas.style.display = 'none';
svgEditor.$svgEditor.appendChild(hcanvas);
hcanvas.style.display = 'none'
svgEditor.$svgEditor.appendChild(hcanvas)
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg')
assignAttributes(canvasGrid, {
id: 'canvasGrid',
width: '100%',
@@ -49,11 +48,11 @@ export default {
y: 0,
overflow: 'visible',
display: 'none'
});
canvBG.appendChild(canvasGrid);
const gridDefs = svgdoc.createElementNS(NS.SVG, 'defs');
})
canvBG.appendChild(canvasGrid)
const gridDefs = svgdoc.createElementNS(NS.SVG, 'defs')
// grid-pattern
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern')
assignAttributes(gridPattern, {
id: 'gridpattern',
patternUnits: 'userSpaceOnUse',
@@ -61,21 +60,21 @@ export default {
y: 0, // -(value.strokeWidth / 2), // position for strokewidth
width: 100,
height: 100
});
})
const gridimg = svgdoc.createElementNS(NS.SVG, 'image');
const gridimg = svgdoc.createElementNS(NS.SVG, 'image')
assignAttributes(gridimg, {
x: 0,
y: 0,
width: 100,
height: 100
});
gridPattern.append(gridimg);
gridDefs.append(gridPattern);
$id('canvasGrid').appendChild(gridDefs);
})
gridPattern.append(gridimg)
gridDefs.append(gridPattern)
$id('canvasGrid').appendChild(gridDefs)
// grid-box
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect')
assignAttributes(gridBox, {
width: '100%',
height: '100%',
@@ -85,8 +84,8 @@ export default {
stroke: 'none',
fill: 'url(#gridpattern)',
style: 'pointer-events: none; display:visible;'
});
$id('canvasGrid').appendChild(gridBox);
})
$id('canvasGrid').appendChild(gridBox)
/**
*
@@ -95,52 +94,52 @@ export default {
*/
const updateGrid = (zoom) => {
// TODO: Try this with <line> elements, then compare performance difference
const unit = units[svgEditor.configObj.curConfig.baseUnit]; // 1 = 1px
const uMulti = unit * zoom;
const unit = units[svgEditor.configObj.curConfig.baseUnit] // 1 = 1px
const uMulti = unit * zoom
// Calculate the main number interval
const rawM = 100 / uMulti;
let multi = 1;
const rawM = 100 / uMulti
let multi = 1
intervals.some((num) => {
multi = num;
return rawM <= num;
});
const bigInt = multi * uMulti;
multi = num
return rawM <= num
})
const bigInt = multi * uMulti
// Set the canvas size to the width of the container
hcanvas.width = bigInt;
hcanvas.height = bigInt;
const ctx = hcanvas.getContext('2d');
const curD = 0.5;
const part = bigInt / 10;
hcanvas.width = bigInt
hcanvas.height = bigInt
const ctx = hcanvas.getContext('2d')
const curD = 0.5
const part = bigInt / 10
ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.configObj.curConfig.gridColor;
ctx.globalAlpha = 0.2
ctx.strokeStyle = svgEditor.configObj.curConfig.gridColor
for (let i = 1; i < 10; i++) {
const subD = Math.round(part * i) + 0.5;
const subD = Math.round(part * i) + 0.5
// const lineNum = (i % 2)?12:10;
const lineNum = 0;
ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD);
ctx.lineTo(lineNum, subD);
const lineNum = 0
ctx.moveTo(subD, bigInt)
ctx.lineTo(subD, lineNum)
ctx.moveTo(bigInt, subD)
ctx.lineTo(lineNum, subD)
}
ctx.stroke();
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.moveTo(curD, bigInt);
ctx.lineTo(curD, 0);
ctx.stroke()
ctx.beginPath()
ctx.globalAlpha = 0.5
ctx.moveTo(curD, bigInt)
ctx.lineTo(curD, 0)
ctx.moveTo(bigInt, curD);
ctx.lineTo(0, curD);
ctx.stroke();
ctx.moveTo(bigInt, curD)
ctx.lineTo(0, curD)
ctx.stroke()
const datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri);
};
const datauri = hcanvas.toDataURL('image/png')
gridimg.setAttribute('width', bigInt)
gridimg.setAttribute('height', bigInt)
gridimg.parentNode.setAttribute('width', bigInt)
gridimg.parentNode.setAttribute('height', bigInt)
svgCanvas.setHref(gridimg, datauri)
}
/**
*
@@ -148,34 +147,32 @@ export default {
*/
const gridUpdate = () => {
if (showGrid) {
updateGrid(svgCanvas.getZoom());
updateGrid(svgCanvas.getZoom())
}
$id('canvasGrid').style.display = (showGrid) ? 'block' : 'none';
$id('view_grid').pressed = showGrid;
};
$id('canvasGrid').style.display = (showGrid) ? 'block' : 'none'
$id('view_grid').pressed = showGrid
}
return {
name: svgEditor.i18next.t(`${name}:name`),
zoomChanged (zoom) {
if (showGrid) { updateGrid(zoom); }
if (showGrid) { updateGrid(zoom) }
},
callback () {
// Add the button and its handler(s)
const buttonTemplate = document.createElement("template");
const title = `${name}:buttons.0.title`;
// eslint-disable-next-line no-unsanitized/property
const buttonTemplate = document.createElement('template')
const title = `${name}:buttons.0.title`
buttonTemplate.innerHTML = `
<se-button id="view_grid" title="${title}" src="grid.svg"></se-button>
`;
$id('editor_panel').append(buttonTemplate.content.cloneNode(true));
$id('view_grid').addEventListener("click", () => {
svgEditor.configObj.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
});
`
$id('editor_panel').append(buttonTemplate.content.cloneNode(true))
$id('view_grid').addEventListener('click', () => {
svgEditor.configObj.curConfig.showGrid = showGrid = !showGrid
gridUpdate()
})
if (showGrid) {
gridUpdate();
gridUpdate()
}
}
};
}
}
};
}

View File

@@ -5,4 +5,4 @@ export default {
title: 'Show/Hide Grid'
}
]
};
}

View File

@@ -5,4 +5,4 @@ export default {
title: 'Afficher/Cacher Grille'
}
]
};
}

View File

@@ -5,4 +5,4 @@ export default {
title: '显示/隐藏网格'
}
]
};
}

View File

@@ -13,42 +13,40 @@
* will show the user the point on the canvas that was clicked on.
*/
const name = "helloworld";
const name = 'helloworld'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init ({ _importLocale }) {
const svgEditor = this;
await loadExtensionTranslation(svgEditor);
const { svgCanvas } = svgEditor;
const { $id } = svgCanvas;
const svgEditor = this
await loadExtensionTranslation(svgEditor)
const { svgCanvas } = svgEditor
const { $id } = svgCanvas
return {
name: svgEditor.i18next.t(`${name}:name`),
callback() {
callback () {
// Add the button and its handler(s)
const buttonTemplate = document.createElement("template");
const title = `${name}:buttons.0.title`;
// eslint-disable-next-line no-unsanitized/property
const buttonTemplate = document.createElement('template')
const title = `${name}:buttons.0.title`
buttonTemplate.innerHTML = `
<se-button id="hello_world" title="${title}" src="hello_world.svg"></se-button>
`;
$id('tools_left').append(buttonTemplate.content.cloneNode(true));
$id('hello_world').addEventListener("click", () => {
svgCanvas.setMode('hello_world');
});
`
$id('tools_left').append(buttonTemplate.content.cloneNode(true))
$id('hello_world').addEventListener('click', () => {
svgCanvas.setMode('hello_world')
})
},
// This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels)
@@ -57,9 +55,9 @@ export default {
if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with
// a value of true in order for mouseUp to be triggered
return { started: true };
return { started: true }
}
return undefined;
return undefined
},
// This is triggered from anywhere, but "started" must have been set
@@ -67,18 +65,18 @@ export default {
mouseUp (opts) {
// Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') {
const zoom = svgCanvas.getZoom();
const zoom = svgCanvas.getZoom()
// Get the actual coordinate by dividing by the zoom value
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const x = opts.mouse_x / zoom
const y = opts.mouse_y / zoom
// We do our own formatting
const text = svgEditor.i18next.t(`${name}:text`, { x, y });
const text = svgEditor.i18next.t(`${name}:text`, { x, y })
// Show the text using the custom alert function
alert(text);
alert(text)
}
}
};
}
}
};
}

View File

@@ -6,4 +6,4 @@ export default {
title: "Say 'Hello World'"
}
]
};
}

View File

@@ -6,4 +6,4 @@ export default {
title: "Dire 'Bonjour le Monde'"
}
]
};
}

View File

@@ -6,4 +6,4 @@ export default {
title: "输出 'Hello World'"
}
]
};
}

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-unsanitized/property */
/* globals seConfirm */
/**
* @file ext-imagelib.js
@@ -9,32 +8,31 @@
*
*/
const name = "imagelib";
const name = 'imagelib'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init({ decode64, dropXMLInternalSubset }) {
const svgEditor = this;
const { $id } = svgEditor.svgCanvas;
const { $svgEditor } = svgEditor;
const { imgPath } = svgEditor.configObj.curConfig;
async init ({ decode64, dropXMLInternalSubset }) {
const svgEditor = this
const { $id } = svgEditor.svgCanvas
const { $svgEditor } = svgEditor
const { imgPath } = svgEditor.configObj.curConfig
await loadExtensionTranslation(svgEditor);
await loadExtensionTranslation(svgEditor)
const { svgCanvas } = svgEditor;
const { svgCanvas } = svgEditor
const imgLibs = [
{
@@ -47,24 +45,24 @@ export default {
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php?svgedit=3',
description: svgEditor.i18next.t(`${name}:imgLibs_1_description`)
}
];
]
const allowedImageLibOrigins = imgLibs.map(({ url }) => {
try {
return new URL(url).origin;
return new URL(url).origin
} catch (err) {
return location.origin;
return location.origin
}
});
})
/**
*
* @returns {void}
*/
const closeBrowser = () => {
$id("imgbrowse_holder").style.display = 'none';
document.activeElement.blur(); // make sure focus is the body to correct issue #417
};
$id('imgbrowse_holder').style.display = 'none'
document.activeElement.blur() // make sure focus is the body to correct issue #417
}
/**
* @param {string} url
@@ -81,18 +79,18 @@ export default {
id: svgCanvas.getNextId(),
style: 'pointer-events:inherit'
}
});
svgCanvas.clearSelection();
svgCanvas.addToSelection([ newImage ]);
svgCanvas.setImageURL(url);
};
})
svgCanvas.clearSelection()
svgCanvas.addToSelection([newImage])
svgCanvas.setImageURL(url)
}
const pending = {};
const pending = {}
let mode = 's';
let multiArr = [];
let transferStopped = false;
let preview; let submit;
let mode = 's'
let multiArr = []
let transferStopped = false
let preview; let submit
/**
* Contains the SVG to insert.
@@ -130,403 +128,401 @@ export default {
* @param {ImageLibMetaMessage|ImageLibMessage|string} cfg.data String is deprecated when parsed to JSON `ImageLibMessage`
* @returns {void}
*/
async function onMessage({ origin, data }) {
let response = data;
if (!response || ![ 'string', 'object' ].includes(typeof response)) {
async function onMessage ({ origin, data }) {
let response = data
if (!response || !['string', 'object'].includes(typeof response)) {
// Do nothing
return;
return
}
let id;
let type;
let id
let type
try {
// Todo: This block can be removed (and the above check changed to
// insist on an object) if embedAPI moves away from a string to
// an object (if IE9 support not needed)
response = typeof response === 'object' ? response : JSON.parse(response);
response = typeof response === 'object' ? response : JSON.parse(response)
if (response.namespace !== 'imagelib') {
return;
return
}
if (!allowedImageLibOrigins.includes('*') && !allowedImageLibOrigins.includes(origin)) {
// Todo: Surface this error to user?
console.error(`Origin ${origin} not whitelisted for posting to ${window.origin}`);
return;
console.error(`Origin ${origin} not whitelisted for posting to ${window.origin}`)
return
}
const hasName = 'name' in response;
const hasHref = 'href' in response;
const hasName = 'name' in response
const hasHref = 'href' in response
if (!hasName && transferStopped) {
transferStopped = false;
return;
transferStopped = false
return
}
if (hasHref) {
id = response.href;
response = response.data;
id = response.href
response = response.data
}
// Hide possible transfer dialog box
if (document.querySelector('se-elix-alert-dialog')) {
document.querySelector('se-elix-alert-dialog').remove();
document.querySelector('se-elix-alert-dialog').remove()
}
type = hasName
? 'meta'
: response.charAt(0);
: response.charAt(0)
} catch (e) {
// This block is for backward compatibility (for IAN and Openclipart);
// should otherwise return
if (typeof response === 'string') {
const char1 = response.charAt(0);
const char1 = response.charAt(0)
if (char1 !== '{' && transferStopped) {
transferStopped = false;
return;
transferStopped = false
return
}
if (char1 === '|') {
const secondpos = response.indexOf('|', 1);
id = response.substr(1, secondpos - 1);
response = response.substr(secondpos + 1);
type = response.charAt(0);
const secondpos = response.indexOf('|', 1)
id = response.substr(1, secondpos - 1)
response = response.substr(secondpos + 1)
type = response.charAt(0)
}
}
}
let entry; let curMeta; let svgStr; let imgStr;
let entry; let curMeta; let svgStr; let imgStr
switch (type) {
case 'meta': {
case 'meta': {
// Metadata
transferStopped = false;
curMeta = response;
transferStopped = false
curMeta = response
// Should be safe to add dynamic property as passed metadata
pending[curMeta.id] = curMeta; // lgtm [js/remote-property-injection]
// Should be safe to add dynamic property as passed metadata
pending[curMeta.id] = curMeta // lgtm [js/remote-property-injection]
const name = (curMeta.name || 'file');
const name = (curMeta.name || 'file')
const message = svgEditor.i18next.t('notification.retrieving').replace('%s', name);
const message = svgEditor.i18next.t('notification.retrieving').replace('%s', name)
if (mode !== 'm') {
await seConfirm(message);
transferStopped = true;
} else {
entry = document.createElement('div');
entry.textContent = message;
entry.dataset.id = curMeta.id;
preview.appendChild(entry);
curMeta.entry = entry;
if (mode !== 'm') {
await seConfirm(message)
transferStopped = true
} else {
entry = document.createElement('div')
entry.textContent = message
entry.dataset.id = curMeta.id
preview.appendChild(entry)
curMeta.entry = entry
}
return
}
return;
}
case '<':
svgStr = true;
break;
case 'd': {
if (response.startsWith('data:image/svg+xml')) {
const pre = 'data:image/svg+xml;base64,';
const src = response.substring(pre.length);
response = decode64(src);
svgStr = true;
break;
} else if (response.startsWith('data:image/')) {
imgStr = true;
break;
case '<':
svgStr = true
break
case 'd': {
if (response.startsWith('data:image/svg+xml')) {
const pre = 'data:image/svg+xml;base64,'
const src = response.substring(pre.length)
response = decode64(src)
svgStr = true
break
} else if (response.startsWith('data:image/')) {
imgStr = true
break
}
}
}
// Else fall through
default:
// Else fall through
default:
// TODO: See if there's a way to base64 encode the binary data stream
// const str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data
// importImage(str);
// Assume it's raw image data
// importImage(str);
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser();
} else {
pending[id].entry.remove();
}
// await alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return;
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser()
} else {
pending[id].entry.remove()
}
// await alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return
}
switch (mode) {
case 's':
case 's':
// Import one
if (svgStr) {
svgEditor.svgCanvas.importSvgString(response);
} else if (imgStr) {
importImage(response);
}
closeBrowser();
break;
case 'm': {
if (svgStr) {
svgEditor.svgCanvas.importSvgString(response)
} else if (imgStr) {
importImage(response)
}
closeBrowser()
break
case 'm': {
// Import multiple
multiArr.push([ (svgStr ? 'svg' : 'img'), response ]);
curMeta = pending[id];
let title;
if (svgStr) {
if (curMeta && curMeta.name) {
title = curMeta.name;
} else {
multiArr.push([(svgStr ? 'svg' : 'img'), response])
curMeta = pending[id]
let title
if (svgStr) {
if (curMeta && curMeta.name) {
title = curMeta.name
} else {
// Try to find a title
// `dropXMLInternalSubset` is to help prevent the billion laughs attack
const xml = new DOMParser().parseFromString(dropXMLInternalSubset(response), 'text/xml').documentElement; // lgtm [js/xml-bomb]
title = xml.querySelector('title').textContent || '(SVG #' + response.length + ')';
}
if (curMeta) {
Array.from(preview.children).forEach(function (element) {
if (element.dataset.id === id) {
if (curMeta.preview_url) {
const img = document.createElement("img");
img.src = curMeta.preview_url;
const span = document.createElement("span");
span.appendChild(img);
element.append(span);
} else {
element.textContent = title;
const xml = new DOMParser().parseFromString(dropXMLInternalSubset(response), 'text/xml').documentElement // lgtm [js/xml-bomb]
title = xml.querySelector('title').textContent || '(SVG #' + response.length + ')'
}
if (curMeta) {
Array.from(preview.children).forEach(function (element) {
if (element.dataset.id === id) {
if (curMeta.preview_url) {
const img = document.createElement('img')
img.src = curMeta.preview_url
const span = document.createElement('span')
span.appendChild(img)
element.append(span)
} else {
element.textContent = title
}
submit.removeAttribute('disabled')
}
submit.removeAttribute('disabled');
}
});
})
} else {
const div = document.createElement('div')
div.textContent = title
preview.appendChild(div)
submit.removeAttribute('disabled')
}
} else {
const div = document.createElement("div");
div.textContent = title;
preview.appendChild(div);
submit.removeAttribute('disabled');
}
} else {
if (curMeta && curMeta.preview_url) {
title = curMeta.name || '';
entry = document.createElement('span');
const img = document.createElement("img");
img.src = curMeta.preview_url;
entry.appendChild(img);
entry.appendChild(document.createTextNode(title));
} else {
entry = document.createElement("img");
entry.src = response;
}
if (curMeta && curMeta.preview_url) {
title = curMeta.name || ''
entry = document.createElement('span')
const img = document.createElement('img')
img.src = curMeta.preview_url
entry.appendChild(img)
entry.appendChild(document.createTextNode(title))
} else {
entry = document.createElement('img')
entry.src = response
}
if (curMeta) {
Array.from(preview.children).forEach(function (element) {
if (element.dataset.id === id) {
element.appendChild(entry);
submit.removeAttribute('disabled');
}
});
} else {
const div = document.createElement("div");
div.appendChild(entry);
preview.appendChild(div);
submit.removeAttribute('disabled');
if (curMeta) {
Array.from(preview.children).forEach(function (element) {
if (element.dataset.id === id) {
element.appendChild(entry)
submit.removeAttribute('disabled')
}
})
} else {
const div = document.createElement('div')
div.appendChild(entry)
preview.appendChild(div)
submit.removeAttribute('disabled')
}
}
}
break;
} case 'o': {
break
} case 'o': {
// Open
if (!svgStr) { break; }
closeBrowser();
const ok = await svgEditor.openPrep();
if (!ok) { return; }
svgCanvas.clear();
svgCanvas.setSvgString(response);
// updateCanvas();
break;
}
if (!svgStr) { break }
closeBrowser()
const ok = await svgEditor.openPrep()
if (!ok) { return }
svgCanvas.clear()
svgCanvas.setSvgString(response)
// updateCanvas();
break
}
}
}
// Receive `postMessage` data
window.addEventListener('message', onMessage, true);
window.addEventListener('message', onMessage, true)
const insertAfter = (referenceNode, newNode) => {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
};
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)
}
const toggleMultiLoop = () => {
multiArr.forEach(function(item, i){
const type = item[0];
const data = item[1];
multiArr.forEach(function (item, i) {
const type = item[0]
const data = item[1]
if (type === 'svg') {
svgCanvas.importSvgString(data);
svgCanvas.importSvgString(data)
} else {
importImage(data);
importImage(data)
}
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
});
while (preview.firstChild)
preview.removeChild(preview.firstChild);
multiArr = [];
$id("imgbrowse_holder").style.display = 'none';
};
svgCanvas.moveSelectedElements(i * 20, i * 20, false)
})
while (preview.firstChild) { preview.removeChild(preview.firstChild) }
multiArr = []
$id('imgbrowse_holder').style.display = 'none'
}
/**
* @param {boolean} show
* @returns {void}
*/
const toggleMulti = (show) => {
$id('lib_framewrap').style.right = (show ? 200 : 10);
$id('imglib_opts').style.right = (show ? 200 : 10);
$id('lib_framewrap').style.right = (show ? 200 : 10)
$id('imglib_opts').style.right = (show ? 200 : 10)
if (!preview) {
preview = document.createElement('div');
preview.setAttribute('id', 'imglib_preview');
preview.setAttribute('style', `position: absolute;top: 45px;right: 10px;width: 180px;bottom: 45px;background: #fff;overflow: auto;`);
insertAfter($id('lib_framewrap'), preview);
preview = document.createElement('div')
preview.setAttribute('id', 'imglib_preview')
preview.setAttribute('style', 'position: absolute;top: 45px;right: 10px;width: 180px;bottom: 45px;background: #fff;overflow: auto;')
insertAfter($id('lib_framewrap'), preview)
submit = document.createElement('button');
submit.setAttribute('content', 'Import selected');
submit.setAttribute('disabled', true);
submit.textContent = 'Import selected';
submit.setAttribute('style', `position: absolute;bottom: 10px;right: -10px;`);
$id('imgbrowse').appendChild(submit);
submit.addEventListener('click', toggleMultiLoop);
submit.addEventListener('touchend', toggleMultiLoop);
submit = document.createElement('button')
submit.setAttribute('content', 'Import selected')
submit.setAttribute('disabled', true)
submit.textContent = 'Import selected'
submit.setAttribute('style', 'position: absolute;bottom: 10px;right: -10px;')
$id('imgbrowse').appendChild(submit)
submit.addEventListener('click', toggleMultiLoop)
submit.addEventListener('touchend', toggleMultiLoop)
}
submit.style.display = (show) ? 'block' : 'none';
preview.style.display = (show) ? 'block' : 'none';
};
submit.style.display = (show) ? 'block' : 'none'
preview.style.display = (show) ? 'block' : 'none'
}
/**
*
* @returns {void}
*/
const showBrowser = () => {
let browser = $id('imgbrowse');
let browser = $id('imgbrowse')
if (!browser) {
const div = document.createElement('div');
div.id = 'imgbrowse_holder';
div.innerHTML = '<div id=imgbrowse class=toolbar_button></div>';
insertAfter($svgEditor, div);
browser = $id('imgbrowse');
const div = document.createElement('div')
div.id = 'imgbrowse_holder'
div.innerHTML = '<div id=imgbrowse class=toolbar_button></div>'
insertAfter($svgEditor, div)
browser = $id('imgbrowse')
const allLibs = svgEditor.i18next.t(`${name}:select_lib`);
const allLibs = svgEditor.i18next.t(`${name}:select_lib`)
const divFrameWrap = document.createElement('div');
divFrameWrap.id = 'lib_framewrap';
const divFrameWrap = document.createElement('div')
divFrameWrap.id = 'lib_framewrap'
const libOpts = document.createElement('ul');
libOpts.id = 'imglib_opts';
browser.append(libOpts);
const frame = document.createElement('iframe');
frame.src = "javascript:0";
frame.style.display = 'none';
divFrameWrap.append(frame);
browser.prepend(divFrameWrap);
const libOpts = document.createElement('ul')
libOpts.id = 'imglib_opts'
browser.append(libOpts)
const frame = document.createElement('iframe')
frame.src = 'javascript:0'
frame.style.display = 'none'
divFrameWrap.append(frame)
browser.prepend(divFrameWrap)
const header = document.createElement('h1');
browser.prepend(header);
header.textContent = allLibs;
header.setAttribute('style', `position: absolute;top: 0px;left: 0px;width: 100%;`);
const header = document.createElement('h1')
browser.prepend(header)
header.textContent = allLibs
header.setAttribute('style', 'position: absolute;top: 0px;left: 0px;width: 100%;')
const button = document.createElement('button');
button.innerHTML = svgEditor.i18next.t('common.cancel');
browser.appendChild(button);
const button = document.createElement('button')
button.innerHTML = svgEditor.i18next.t('common.cancel')
browser.appendChild(button)
button.addEventListener('click', function () {
$id("imgbrowse_holder").style.display = 'none';
});
$id('imgbrowse_holder').style.display = 'none'
})
button.addEventListener('touchend', function () {
$id("imgbrowse_holder").style.display = 'none';
});
button.setAttribute('style', `position: absolute;top: 5px;right: 10px;`);
$id('imgbrowse_holder').style.display = 'none'
})
button.setAttribute('style', 'position: absolute;top: 5px;right: 10px;')
const leftBlock = document.createElement('span');
leftBlock.setAttribute('style', `position: absolute;top: 5px;left: 10px;display: inline-flex;`);
browser.appendChild(leftBlock);
const leftBlock = document.createElement('span')
leftBlock.setAttribute('style', 'position: absolute;top: 5px;left: 10px;display: inline-flex;')
browser.appendChild(leftBlock)
const back = document.createElement('button');
back.style.visibility = "hidden";
back.innerHTML = `<img class="svg_icon" src="${imgPath}/library.svg" alt="icon" width="16" height="16" />` + svgEditor.i18next.t(`${name}:show_list`);
leftBlock.appendChild(back);
const back = document.createElement('button')
back.style.visibility = 'hidden'
back.innerHTML = `<img class="svg_icon" src="${imgPath}/library.svg" alt="icon" width="16" height="16" />` + svgEditor.i18next.t(`${name}:show_list`)
leftBlock.appendChild(back)
back.addEventListener('click', function () {
frame.setAttribute('src', 'about:blank');
frame.style.display = 'none';
libOpts.style.display = 'block';
header.textContent = allLibs;
back.style.display = 'none';
});
frame.setAttribute('src', 'about:blank')
frame.style.display = 'none'
libOpts.style.display = 'block'
header.textContent = allLibs
back.style.display = 'none'
})
back.addEventListener('touchend', function () {
frame.setAttribute('src', 'about:blank');
frame.style.display = 'none';
libOpts.style.display = 'block';
header.textContent = allLibs;
back.style.display = 'none';
});
back.setAttribute('style', `margin-right: 5px;`);
back.style.display = 'none';
frame.setAttribute('src', 'about:blank')
frame.style.display = 'none'
libOpts.style.display = 'block'
header.textContent = allLibs
back.style.display = 'none'
})
back.setAttribute('style', 'margin-right: 5px;')
back.style.display = 'none'
const select = document.createElement('select');
const select = document.createElement('select')
select.innerHTML = '<select><option value=s>' +
svgEditor.i18next.t(`${name}:import_single`) + '</option><option value=m>' +
svgEditor.i18next.t(`${name}:import_multi`) + '</option><option value=o>' +
svgEditor.i18next.t(`${name}:open`) + '</option>';
leftBlock.appendChild(select);
svgEditor.i18next.t(`${name}:open`) + '</option>'
leftBlock.appendChild(select)
select.addEventListener('change', function () {
mode = this.value;
mode = this.value
switch (mode) {
case 's':
case 'o':
toggleMulti(false);
break;
case 's':
case 'o':
toggleMulti(false)
break
case 'm':
case 'm':
// Import multiple
toggleMulti(true);
break;
toggleMulti(true)
break
}
});
select.setAttribute('style', `margin-top: 10px;`);
})
select.setAttribute('style', 'margin-top: 10px;')
imgLibs.forEach(function ({ name, url, description }) {
const li = document.createElement('li');
libOpts.appendChild(li);
li.textContent = name;
const li = document.createElement('li')
libOpts.appendChild(li)
li.textContent = name
li.addEventListener('click', function () {
frame.setAttribute('src', url);
frame.style.display = 'block';
header.textContent = name;
libOpts.style.display = 'none';
back.style.display = 'block';
});
frame.setAttribute('src', url)
frame.style.display = 'block'
header.textContent = name
libOpts.style.display = 'none'
back.style.display = 'block'
})
li.addEventListener('touchend', function () {
frame.setAttribute('src', url);
frame.style.display = 'block';
header.textContent = name;
libOpts.style.display = 'none';
back.style.display = 'block';
});
const span = document.createElement("span");
span.textContent = description;
li.appendChild(span);
});
frame.setAttribute('src', url)
frame.style.display = 'block'
header.textContent = name
libOpts.style.display = 'none'
back.style.display = 'block'
})
const span = document.createElement('span')
span.textContent = description
li.appendChild(span)
})
} else {
$id("imgbrowse_holder").style.display = 'block';
$id('imgbrowse_holder').style.display = 'block'
}
};
}
return {
svgicons: 'ext-imagelib.xml',
callback() {
callback () {
// Add the button and its handler(s)
const buttonTemplate = document.createElement("template");
const key = name + `:buttons.0.title`;
const buttonTemplate = document.createElement('template')
const key = name + ':buttons.0.title'
buttonTemplate.innerHTML = `
<se-menu-item id="tool_imagelib" label="${key}" src="library.svg"></se-menu-item>
`;
insertAfter($id('tool_export'), buttonTemplate.content.cloneNode(true));
$id('tool_imagelib').addEventListener("click", () => {
showBrowser();
});
`
insertAfter($id('tool_export'), buttonTemplate.content.cloneNode(true))
$id('tool_imagelib').addEventListener('click', () => {
showBrowser()
})
const style = document.createElement('style');
const style = document.createElement('style')
style.textContent = '#imgbrowse_holder {' +
'position: absolute;' +
'top: 0;' +
@@ -599,9 +595,9 @@ export default {
'width: 100%;' +
'height: 100%;' +
'border: 0;' +
'}';
document.head.appendChild(style);
'}'
document.head.appendChild(style)
}
};
}
}
};
}

View File

@@ -1,54 +1,54 @@
const atags = document.querySelectorAll('a');
const atags = document.querySelectorAll('a')
Array.prototype.forEach.call(atags, function (aEle) {
aEle.addEventListener('click', function (event) {
event.preventDefault();
const { href } = event.currentTarget;
const target = window.parent;
event.preventDefault()
const { href } = event.currentTarget
const target = window.parent
const post = (message) => {
// Todo: Make origin customizable as set by opening window
// Todo: If dropping IE9, avoid stringifying
target.postMessage(JSON.stringify({
namespace: 'imagelib',
...message
}), '*');
};
}), '*')
}
// Convert Non-SVG images to data URL first
// (this could also have been done server-side by the library)
// Send metadata (also indicates file is about to be sent)
post({
name: event.currentTarget.textContent,
id: href
});
})
if (!href.includes('.svg')) {
const img = new Image();
const img = new Image()
img.addEventListener('load', function () {
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
const canvas = document.createElement('canvas')
canvas.width = this.width
canvas.height = this.height
// load the raster image into the canvas
canvas.getContext('2d').drawImage(this, 0, 0);
canvas.getContext('2d').drawImage(this, 0, 0)
// retrieve the data: URL
let data;
let data
try {
data = canvas.toDataURL();
data = canvas.toDataURL()
} catch (err) {
// This fails in Firefox with `file:///` URLs :(
// Todo: This could use a generic alert library instead
alert('Data URL conversion failed: ' + err);
data = '';
alert('Data URL conversion failed: ' + err)
data = ''
}
post({ href, data });
});
img.src = href;
post({ href, data })
})
img.src = href
} else {
fetch(href)
.then( (r) => r.text())
.then( (data) => {
post({ href, data });
return data;
.then((r) => r.text())
.then((data) => {
post({ href, data })
return data
})
.catch( (error) => console.error(error));
.catch((error) => console.error(error))
}
return false;
});
});
return false
})
})

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -13,4 +13,4 @@ export default {
imgLibs_0_description: 'Demonstration library for SVG-edit on this server',
imgLibs_1_name: 'IAN Symbol Libraries',
imgLibs_1_description: 'Free library of illustrations'
};
}

View File

@@ -1,13 +1,13 @@
/* eslint-disable node/no-unpublished-import */
import { jml, body, nbsp } from 'jamilih';
import $ from 'query-result';
import { manipulation } from 'qr-manipulation';
import { jml, body, nbsp } from 'jamilih'
import $ from 'query-result'
import { manipulation } from 'qr-manipulation'
manipulation($, jml);
manipulation($, jml)
const baseAPIURL = 'https://openclipart.org/search/json/';
const baseAPIURL = 'https://openclipart.org/search/json/'
const jsVoid = 'javascript: void(0);';
const jsVoid = 'javascript: void(0);'
/**
* Shows results after query submission.
@@ -20,31 +20,35 @@ async function processResults (url) {
* @returns {external:JamilihArray}
*/
function queryLink (query) {
return [ 'a', {
return ['a', {
href: jsVoid,
dataset: { value: query },
$on: { click (e) {
e.preventDefault();
const { value } = this.dataset;
$('#query')[0].$set(value);
$('#openclipart')[0].$submit();
} }
}, [ query ] ];
$on: {
click (e) {
e.preventDefault()
const { value } = this.dataset
$('#query')[0].$set(value)
$('#openclipart')[0].$submit()
}
}
}, [query]]
}
const r = await fetch(url);
const json = await r.json();
const r = await fetch(url)
const json = await r.json()
if (!json || json.msg !== 'success') {
// Todo: This could use a generic alert library instead
alert('There was a problem downloading the results');
return;
alert('There was a problem downloading the results')
return
}
const { payload, info: {
results: numResults,
pages,
current_page: currentPage
} } = json;
const {
payload, info: {
results: numResults,
pages,
current_page: currentPage
}
} = json
// $('#page')[0].value = currentPage;
// $('#page')[0].max = pages;
@@ -57,19 +61,19 @@ async function processResults (url) {
// }` object of relevance?
// - No need for `tags` with `tags_array`
// - `svg`'s: `png_thumb`, `png_full_lossy`, `png_2400px`
const semiColonSep = '; ' + nbsp;
const semiColonSep = '; ' + nbsp
$('#results').jml('div', [
[ 'span', [
['span', [
'Number of results: ',
numResults
] ],
]],
semiColonSep,
[ 'span', [
['span', [
'page ',
currentPage,
' out of ',
pages
] ],
]],
...payload.map(({
title, description, id,
uploader, created,
@@ -79,170 +83,174 @@ async function processResults (url) {
downloaded_by: downloadedBy,
total_favorites: totalFavorites
}) => {
const imgHW = '100px';
const colonSep = ': ' + nbsp;
return [ 'div', [
[ 'button', { style: 'margin-right: 8px; border: 2px solid black;', dataset: { id, value: svgURL }, $on: {
async click (e) {
e.preventDefault();
const { value: svgurl } = this.dataset;
const post = (message) => {
const imgHW = '100px'
const colonSep = ': ' + nbsp
return ['div', [
['button', {
style: 'margin-right: 8px; border: 2px solid black;',
dataset: { id, value: svgURL },
$on: {
async click (e) {
e.preventDefault()
const { value: svgurl } = this.dataset
const post = (message) => {
// Todo: Make origin customizable as set by opening window
// Todo: If dropping IE9, avoid stringifying
window.parent.postMessage(JSON.stringify({
namespace: 'imagelib',
...message
}), '*');
};
// Send metadata (also indicates file is about to be sent)
post({
name: title,
id: svgurl
});
const result = await fetch(svgurl);
const svg = await result.text();
post({
href: svgurl,
data: svg
});
window.parent.postMessage(JSON.stringify({
namespace: 'imagelib',
...message
}), '*')
}
// Send metadata (also indicates file is about to be sent)
post({
name: title,
id: svgurl
})
const result = await fetch(svgurl)
const svg = await result.text()
post({
href: svgurl,
data: svg
})
}
}
} }, [
}, [
// If we wanted interactive versions despite security risk:
// ['object', {data: svgURL, type: 'image/svg+xml'}]
[ 'img', { src: svgURL, style: `width: ${imgHW}; height: ${imgHW};` } ]
] ],
[ 'b', [ title ] ],
['img', { src: svgURL, style: `width: ${imgHW}; height: ${imgHW};` }]
]],
['b', [title]],
' ',
[ 'i', [ description ] ],
['i', [description]],
' ',
[ 'span', [
['span', [
'(ID: ',
[ 'a', {
['a', {
href: jsVoid,
dataset: { value: id },
$on: {
click (e) {
e.preventDefault();
const { value } = this.dataset;
$('#byids')[0].$set(value);
$('#openclipart')[0].$submit();
e.preventDefault()
const { value } = this.dataset
$('#byids')[0].$set(value)
$('#openclipart')[0].$submit()
}
}
}, [ id ] ],
}, [id]],
')'
] ],
]],
' ',
[ 'i', [
[ 'a', {
['i', [
['a', {
href: detailLink,
target: '_blank'
}, [ 'Details' ] ]
] ],
[ 'br' ],
[ 'span', [
[ 'u', [ 'Uploaded by' ] ], colonSep,
}, ['Details']]
]],
['br'],
['span', [
['u', ['Uploaded by']], colonSep,
queryLink(uploader),
semiColonSep
] ],
[ 'span', [
[ 'u', [ 'Download count' ] ], colonSep,
]],
['span', [
['u', ['Download count']], colonSep,
downloadedBy,
semiColonSep
] ],
[ 'span', [
[ 'u', [ 'Times used as favorite' ] ], colonSep,
]],
['span', [
['u', ['Times used as favorite']], colonSep,
totalFavorites,
semiColonSep
] ],
[ 'span', [
[ 'u', [ 'Created date' ] ], colonSep,
]],
['span', [
['u', ['Created date']], colonSep,
created
] ],
[ 'br' ],
[ 'u', [ 'Tags' ] ], colonSep,
]],
['br'],
['u', ['Tags']], colonSep,
...tagsArray.map((tag) => {
return [ 'span', [
return ['span', [
' ',
queryLink(tag)
] ];
]]
})
] ];
]]
}),
[ 'br' ], [ 'br' ],
['br'], ['br'],
(currentPage === 1 || pages <= 2
? ''
: [ 'span', [
[ 'a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault();
$('#page')[0].value = 1;
$('#openclipart')[0].$submit();
: ['span', [
['a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault()
$('#page')[0].value = 1
$('#openclipart')[0].$submit()
}
}
}
}, [ 'First' ] ],
' '
] ]
}, ['First']],
' '
]]
),
(currentPage === 1
? ''
: [ 'span', [
[ 'a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault();
$('#page')[0].value = currentPage - 1;
$('#openclipart')[0].$submit();
: ['span', [
['a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault()
$('#page')[0].value = currentPage - 1
$('#openclipart')[0].$submit()
}
}
}
}, [ 'Prev' ] ],
' '
] ]
}, ['Prev']],
' '
]]
),
(currentPage === pages
? ''
: [ 'span', [
[ 'a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault();
$('#page')[0].value = currentPage + 1;
$('#openclipart')[0].$submit();
: ['span', [
['a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault()
$('#page')[0].value = currentPage + 1
$('#openclipart')[0].$submit()
}
}
}
}, [ 'Next' ] ],
' '
] ]
}, ['Next']],
' '
]]
),
(currentPage === pages || pages <= 2
? ''
: [ 'span', [
[ 'a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault();
$('#page')[0].value = pages;
$('#openclipart')[0].$submit();
: ['span', [
['a', {
href: jsVoid,
$on: {
click (e) {
e.preventDefault()
$('#page')[0].value = pages
$('#openclipart')[0].$submit()
}
}
}
}, [ 'Last' ] ],
' '
] ]
}, ['Last']],
' '
]]
)
]);
])
}
jml('div', [
[ 'style', [
['style', [
`.control {
padding-top: 10px;
}`
] ],
[ 'form', {
]],
['form', {
id: 'openclipart',
$custom: {
async $submit () {
@@ -250,95 +258,120 @@ jml('div', [
[
'query', 'sort', 'amount', 'page', 'byids'
].forEach((prop) => {
const { value } = $('#' + prop)[0];
const { value } = $('#' + prop)[0]
if (value) {
url.searchParams.set(prop, value);
url.searchParams.set(prop, value)
}
});
await processResults(url);
})
await processResults(url)
}
},
$on: {
submit (e) {
e.preventDefault();
this.$submit();
e.preventDefault()
this.$submit()
}
}
}, [
// Todo: i18nize
[ 'fieldset', [
[ 'legend', [ 'Search terms' ] ],
[ 'div', { class: 'control' }, [
[ 'label', [
['fieldset', [
['legend', ['Search terms']],
['div', { class: 'control' }, [
['label', [
'Query (Title, description, uploader, or tag): ',
[ 'input', { id: 'query', name: 'query', placeholder: 'cat', $custom: {
$set (value) {
$('#byids')[0].value = '';
this.value = value;
['input', {
id: 'query',
name: 'query',
placeholder: 'cat',
$custom: {
$set (value) {
$('#byids')[0].value = ''
this.value = value
}
},
$on: {
change () {
$('#byids')[0].value = ''
}
}
}, $on: {
change () {
$('#byids')[0].value = '';
}
} } ]
] ]
] ],
[ 'br' ],
}]
]]
]],
['br'],
' OR ',
[ 'br' ],
[ 'div', { class: 'control' }, [
[ 'label', [
['br'],
['div', { class: 'control' }, [
['label', [
'IDs (single or comma-separated): ',
[ 'input', { id: 'byids', name: 'ids', placeholder: '271380, 265741', $custom: {
$set (value) {
$('#query')[0].value = '';
this.value = value;
['input', {
id: 'byids',
name: 'ids',
placeholder: '271380, 265741',
$custom: {
$set (value) {
$('#query')[0].value = ''
this.value = value
}
},
$on: {
change () {
$('#query')[0].value = ''
}
}
}, $on: {
change () {
$('#query')[0].value = '';
}
} } ]
] ]
] ]
] ],
[ 'fieldset', [
[ 'legend', [ 'Configuring results' ] ],
[ 'div', { class: 'control' }, [
[ 'label', [
}]
]]
]]
]],
['fieldset', [
['legend', ['Configuring results']],
['div', { class: 'control' }, [
['label', [
'Sort by: ',
[ 'select', { id: 'sort' }, [
['select', { id: 'sort' }, [
// Todo: i18nize first values
[ 'Date', 'date' ],
[ 'Downloads', 'downloads' ],
[ 'Favorited', 'favorites' ]
].map(([ text, value = text ]) => {
return [ 'option', { value }, [ text ] ];
}) ]
] ]
] ],
[ 'div', { class: 'control' }, [
[ 'label', [
['Date', 'date'],
['Downloads', 'downloads'],
['Favorited', 'favorites']
].map(([text, value = text]) => {
return ['option', { value }, [text]]
})]
]]
]],
['div', { class: 'control' }, [
['label', [
'Results per page: ',
[ 'input', {
id: 'amount', name: 'amount', value: 10,
type: 'number', min: 1, max: 200, step: 1, pattern: '\\d+' } ]
] ]
] ],
[ 'div', { class: 'control' }, [
[ 'label', [
['input', {
id: 'amount',
name: 'amount',
value: 10,
type: 'number',
min: 1,
max: 200,
step: 1,
pattern: '\\d+'
}]
]]
]],
['div', { class: 'control' }, [
['label', [
'Page number: ',
[ 'input', {
['input', {
// max: 1, // We'll change this based on available results
id: 'page', name: 'page', value: 1, style: 'width: 40px;',
type: 'number', min: 1, step: 1, pattern: '\\d+'
} ]
] ]
] ]
] ],
[ 'div', { class: 'control' }, [
[ 'input', { type: 'submit' } ]
] ]
] ],
[ 'div', { id: 'results' } ]
], body);
id: 'page',
name: 'page',
value: 1,
style: 'width: 40px;',
type: 'number',
min: 1,
step: 1,
pattern: '\\d+'
}]
]]
]]
]],
['div', { class: 'control' }, [
['input', { type: 'submit' }]
]]
]],
['div', { id: 'results' }]
], body)

View File

@@ -30,12 +30,12 @@
export default {
name: 'markers',
async init () {
const svgEditor = this;
const { svgCanvas } = svgEditor;
const { BatchCommand, RemoveElementCommand, InsertElementCommand } = svgCanvas.history;
const { $id, addSVGElemensFromJson: addElem } = svgCanvas;
const mtypes = [ 'start', 'mid', 'end' ];
const markerElems = [ 'line', 'path', 'polyline', 'polygon' ];
const svgEditor = this
const { svgCanvas } = svgEditor
const { BatchCommand, RemoveElementCommand, InsertElementCommand } = svgCanvas.history
const { $id, addSVGElemensFromJson: addElem } = svgCanvas
const mtypes = ['start', 'mid', 'end']
const markerElems = ['line', 'path', 'polyline', 'polygon']
// note - to add additional marker types add them below with a unique id
// and add the associated icon(s) to marker-icons.svg
@@ -55,25 +55,25 @@ export default {
};
// duplicate shapes to support unfilled (open) marker types with an _o suffix
[ 'leftarrow', 'rightarrow', 'box', 'mcircle' ].forEach((v) => {
markerTypes[v + '_o'] = markerTypes[v];
});
['leftarrow', 'rightarrow', 'box', 'mcircle'].forEach((v) => {
markerTypes[v + '_o'] = markerTypes[v]
})
/**
* @param {Element} elem - A graphic element will have an attribute like marker-start
* @param {"marker-start"|"marker-mid"|"marker-end"} attr
* @returns {Element} The marker element that is linked to the graphic element
*/
const getLinked = (elem, attr) => {
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
const getLinked = (elem, attr) => {
const str = elem.getAttribute(attr)
if (!str) { return null }
const m = str.match(/\(#(.*)\)/)
// "url(#mkr_end_svg_1)" would give m[1] = "mkr_end_svg_1"
if (!m || m.length !== 2) {
return null;
return null
}
return svgCanvas.getElem(m[1]);
};
return svgCanvas.getElem(m[1])
}
/**
* Toggles context tool panel off/on.
@@ -81,18 +81,18 @@ export default {
* @returns {void}
*/
const showPanel = (on, elem) => {
$id('marker_panel').style.display = (on) ? 'block' : 'none';
$id('marker_panel').style.display = (on) ? 'block' : 'none'
if (on && elem) {
mtypes.forEach((pos) => {
const marker = getLinked(elem, 'marker-' + pos);
const marker = getLinked(elem, 'marker-' + pos)
if (marker?.attributes?.se_type) {
$id(`${pos}_marker_list_opts`).setAttribute('value', marker.attributes.se_type.value);
$id(`${pos}_marker_list_opts`).setAttribute('value', marker.attributes.se_type.value)
} else {
$id(`${pos}_marker_list_opts`).setAttribute('value', 'nomarker');
$id(`${pos}_marker_list_opts`).setAttribute('value', 'nomarker')
}
});
})
}
};
}
/**
* @param {string} id
@@ -100,22 +100,22 @@ export default {
* @returns {SVGMarkerElement}
*/
const addMarker = (id, seType) => {
const selElems = svgCanvas.getSelectedElements();
let marker = svgCanvas.getElem(id);
if (marker) { return undefined; }
if (seType === '' || seType === 'nomarker') { return undefined; }
const el = selElems[0];
const color = el.getAttribute('stroke');
const strokeWidth = 10;
const refX = 50;
const refY = 50;
const viewBox = '0 0 100 100';
const markerWidth = 5;
const markerHeight = 5;
const selElems = svgCanvas.getSelectedElements()
let marker = svgCanvas.getElem(id)
if (marker) { return undefined }
if (seType === '' || seType === 'nomarker') { return undefined }
const el = selElems[0]
const color = el.getAttribute('stroke')
const strokeWidth = 10
const refX = 50
const refY = 50
const viewBox = '0 0 100 100'
const markerWidth = 5
const markerHeight = 5
if (!markerTypes[seType]) {
console.error(`unknown marker type: ${seType}`);
return undefined;
console.error(`unknown marker type: ${seType}`)
return undefined
}
// create a generic marker
@@ -128,27 +128,27 @@ export default {
style: 'pointer-events:none',
se_type: seType
}
});
})
const mel = addElem(markerTypes[seType]);
const mel = addElem(markerTypes[seType])
const fillcolor = (seType.substr(-2) === '_o')
? 'none'
: color;
: color
mel.setAttribute('fill', fillcolor);
mel.setAttribute('stroke', color);
mel.setAttribute('stroke-width', strokeWidth);
marker.append(mel);
mel.setAttribute('fill', fillcolor)
mel.setAttribute('stroke', color)
mel.setAttribute('stroke-width', strokeWidth)
marker.append(mel)
marker.setAttribute('viewBox', viewBox);
marker.setAttribute('markerWidth', markerWidth);
marker.setAttribute('markerHeight', markerHeight);
marker.setAttribute('refX', refX);
marker.setAttribute('refY', refY);
svgCanvas.findDefs().append(marker);
marker.setAttribute('viewBox', viewBox)
marker.setAttribute('markerWidth', markerWidth)
marker.setAttribute('markerHeight', markerHeight)
marker.setAttribute('refX', refX)
marker.setAttribute('refY', refY)
svgCanvas.findDefs().append(marker)
return marker;
};
return marker
}
/**
* @param {Element} elem
@@ -157,16 +157,16 @@ export default {
const convertline = (elem) => {
// this routine came from the connectors extension
// it is needed because midpoint markers don't work with line elements
if (elem.tagName !== 'line') { return elem; }
if (elem.tagName !== 'line') { return elem }
// Convert to polyline to accept mid-arrow
const x1 = Number(elem.getAttribute('x1'));
const x2 = Number(elem.getAttribute('x2'));
const y1 = Number(elem.getAttribute('y1'));
const y2 = Number(elem.getAttribute('y2'));
const { id } = elem;
const x1 = Number(elem.getAttribute('x1'))
const x2 = Number(elem.getAttribute('x2'))
const y1 = Number(elem.getAttribute('y1'))
const y2 = Number(elem.getAttribute('y2'))
const { id } = elem
const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ')
const pline = addElem({
element: 'polyline',
attr: {
@@ -176,53 +176,53 @@ export default {
fill: 'none',
opacity: elem.getAttribute('opacity') || 1
}
});
})
mtypes.forEach((pos) => { // get any existing marker definitions
const nam = 'marker-' + pos;
const m = elem.getAttribute(nam);
if (m) { pline.setAttribute(nam, elem.getAttribute(nam)); }
});
const nam = 'marker-' + pos
const m = elem.getAttribute(nam)
if (m) { pline.setAttribute(nam, elem.getAttribute(nam)) }
})
const batchCmd = new BatchCommand();
batchCmd.addSubCommand(new RemoveElementCommand(elem, elem.parentNode));
batchCmd.addSubCommand(new InsertElementCommand(pline));
const batchCmd = new BatchCommand()
batchCmd.addSubCommand(new RemoveElementCommand(elem, elem.parentNode))
batchCmd.addSubCommand(new InsertElementCommand(pline))
elem.insertAdjacentElement('afterend', pline);
elem.remove();
svgCanvas.clearSelection();
pline.id = id;
svgCanvas.addToSelection([ pline ]);
svgCanvas.addCommandToHistory(batchCmd);
return pline;
};
elem.insertAdjacentElement('afterend', pline)
elem.remove()
svgCanvas.clearSelection()
pline.id = id
svgCanvas.addToSelection([pline])
svgCanvas.addCommandToHistory(batchCmd)
return pline
}
/**
*
* @returns {void}
*/
const setMarker = (pos, markerType) => {
const selElems = svgCanvas.getSelectedElements();
if (selElems.length === 0) return;
const markerName = 'marker-' + pos;
const el = selElems[0];
const marker = getLinked(el, markerName);
if (marker) { marker.remove(); }
el.removeAttribute(markerName);
let val = markerType;
if (val === '') { val = 'nomarker'; }
const selElems = svgCanvas.getSelectedElements()
if (selElems.length === 0) return
const markerName = 'marker-' + pos
const el = selElems[0]
const marker = getLinked(el, markerName)
if (marker) { marker.remove() }
el.removeAttribute(markerName)
let val = markerType
if (val === '') { val = 'nomarker' }
if (val === 'nomarker') {
svgCanvas.call('changed', selElems);
return;
svgCanvas.call('changed', selElems)
return
}
// Set marker on element
const id = 'mkr_' + pos + '_' + el.id;
addMarker(id, val);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
const id = 'mkr_' + pos + '_' + el.id
addMarker(id, val)
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')')
if (el.tagName === 'line' && pos === 'mid') {
convertline(el);
convertline(el)
}
svgCanvas.call('changed', selElems);
};
svgCanvas.call('changed', selElems)
}
/**
* Called when the main system modifies an object. This routine changes
@@ -231,20 +231,20 @@ export default {
* @returns {void}
*/
const colorChanged = (elem) => {
const color = elem.getAttribute('stroke');
const color = elem.getAttribute('stroke')
mtypes.forEach((pos) => {
const marker = getLinked(elem, 'marker-' + pos);
if (!marker) { return; }
if (!marker.attributes.se_type) { return; } // not created by this extension
const ch = marker.lastElementChild;
if (!ch) { return; }
const curfill = ch.getAttribute('fill');
const curstroke = ch.getAttribute('stroke');
if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); }
if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); }
});
};
const marker = getLinked(elem, 'marker-' + pos)
if (!marker) { return }
if (!marker.attributes.se_type) { return } // not created by this extension
const ch = marker.lastElementChild
if (!ch) { return }
const curfill = ch.getAttribute('fill')
const curstroke = ch.getAttribute('stroke')
if (curfill && curfill !== 'none') { ch.setAttribute('fill', color) }
if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color) }
})
}
/**
* Called when the main system creates or modifies an object.
@@ -253,78 +253,77 @@ export default {
* @returns {void}
*/
const updateReferences = (el) => {
const selElems = svgCanvas.getSelectedElements();
const selElems = svgCanvas.getSelectedElements()
mtypes.forEach((pos) => {
const markerName = 'marker-' + pos;
const marker = getLinked(el, markerName);
if (!marker || !marker.attributes.se_type) { return; } // not created by this extension
const url = el.getAttribute(markerName);
const markerName = 'marker-' + pos
const marker = getLinked(el, markerName)
if (!marker || !marker.attributes.se_type) { return } // not created by this extension
const url = el.getAttribute(markerName)
if (url) {
const len = el.id.length;
const linkid = url.substr(-len - 1, len);
const len = el.id.length
const linkid = url.substr(-len - 1, len)
if (el.id !== linkid) {
const newMarkerId = 'mkr_' + pos + '_' + el.id;
addMarker(newMarkerId, marker.attributes.se_type.value);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + newMarkerId + ')');
svgCanvas.call('changed', selElems);
const newMarkerId = 'mkr_' + pos + '_' + el.id
addMarker(newMarkerId, marker.attributes.se_type.value)
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + newMarkerId + ')')
svgCanvas.call('changed', selElems)
}
}
});
};
})
}
return {
name: svgEditor.i18next.t(`${name}:name`),
// The callback should be used to load the DOM with the appropriate UI items
callback() {
callback () {
// Add the context panel and its handler(s)
const panelTemplate = document.createElement("template");
const panelTemplate = document.createElement('template')
// create the marker panel
let innerHTML = '<div id="marker_panel">';
let innerHTML = '<div id="marker_panel">'
mtypes.forEach((pos) => {
innerHTML += `<se-list id="${pos}_marker_list_opts" title="tools.${pos}_marker_list_opts" label="" width="22px" height="22px">`;
Object.entries(markerTypes).forEach(([ marker, _mkr ]) => {
innerHTML += `<se-list-item id="mkr_${pos}_${marker}" value="${marker}" title="tools.mkr_${marker}" src="${marker}.svg" img-height="22px"></se-list-item>`;
});
innerHTML += '</se-list>';
});
innerHTML += '</div>';
// eslint-disable-next-line no-unsanitized/property
panelTemplate.innerHTML = innerHTML;
$id("tools_top").appendChild(panelTemplate.content.cloneNode(true));
innerHTML += `<se-list id="${pos}_marker_list_opts" title="tools.${pos}_marker_list_opts" label="" width="22px" height="22px">`
Object.entries(markerTypes).forEach(([marker, _mkr]) => {
innerHTML += `<se-list-item id="mkr_${pos}_${marker}" value="${marker}" title="tools.mkr_${marker}" src="${marker}.svg" img-height="22px"></se-list-item>`
})
innerHTML += '</se-list>'
})
innerHTML += '</div>'
panelTemplate.innerHTML = innerHTML
$id('tools_top').appendChild(panelTemplate.content.cloneNode(true))
// don't display the panels on start
showPanel(false);
showPanel(false)
mtypes.forEach((pos) => {
$id(`${pos}_marker_list_opts`).addEventListener('change', (evt) => {
setMarker(pos, evt.detail.value);
});
});
setMarker(pos, evt.detail.value)
})
})
},
selectedChanged (opts) {
// Use this to update the current selected elements
if (opts.elems.length === 0) showPanel(false);
opts.elems.forEach( (elem) => {
if (opts.elems.length === 0) showPanel(false)
opts.elems.forEach((elem) => {
if (elem && markerElems.includes(elem.tagName)) {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true, elem);
showPanel(true, elem)
} else {
showPanel(false);
showPanel(false)
}
} else {
showPanel(false);
showPanel(false)
}
});
})
},
elementChanged (opts) {
const elem = opts.elems[0];
const elem = opts.elems[0]
if (elem && (
elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end')
)) {
colorChanged(elem);
updateReferences(elem);
colorChanged(elem)
updateReferences(elem)
}
}
};
}
}
};
}

View File

@@ -43,4 +43,4 @@ export default {
title: 'Select end marker type'
}
]
};
}

View File

@@ -43,4 +43,4 @@ export default {
title: '选择末端标记类型'
}
]
};
}

View File

@@ -15,66 +15,65 @@
* @listens module:svgcanvas.SvgCanvas#event:saved
* @returns {void}
*/
import { fileOpen, fileSave } from 'browser-fs-access';
import { fileOpen, fileSave } from 'browser-fs-access'
const name = "opensave";
let handle = null;
const name = 'opensave'
let handle = null
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, 'translation', translationModule.default, true, true);
};
svgEditor.i18next.addResourceBundle(lang, 'translation', translationModule.default, true, true)
}
export default {
name,
async init(_S) {
const svgEditor = this;
const { svgCanvas } = svgEditor;
const { $id } = svgCanvas;
await loadExtensionTranslation(svgEditor);
async init (_S) {
const svgEditor = this
const { svgCanvas } = svgEditor
const { $id } = svgCanvas
await loadExtensionTranslation(svgEditor)
/**
* @param {Event} e
* @returns {void}
*/
const importImage = (e) => {
$id('se-prompt-dialog').title = this.i18next.t('notification.loadingImage');
$id('se-prompt-dialog').setAttribute('close', false);
e.stopPropagation();
e.preventDefault();
const file = (e.type === 'drop') ? e.dataTransfer.files[0] : e.currentTarget.files[0];
$id('se-prompt-dialog').title = this.i18next.t('notification.loadingImage')
$id('se-prompt-dialog').setAttribute('close', false)
e.stopPropagation()
e.preventDefault()
const file = (e.type === 'drop') ? e.dataTransfer.files[0] : e.currentTarget.files[0]
if (!file) {
$id('se-prompt-dialog').setAttribute('close', true);
return;
$id('se-prompt-dialog').setAttribute('close', true)
return
}
if (!file.type.includes('image')) {
return;
return
}
// Detected an image
// svg handling
let reader;
let reader
if (file.type.includes('svg')) {
reader = new FileReader();
reader.onloadend = (ev) => {
const newElement = this.svgCanvas.importSvgString(ev.target.result, true);
this.svgCanvas.alignSelectedElements('m', 'page');
this.svgCanvas.alignSelectedElements('c', 'page');
reader = new FileReader()
reader.onloadend = (ev) => {
const newElement = this.svgCanvas.importSvgString(ev.target.result, true)
this.svgCanvas.alignSelectedElements('m', 'page')
this.svgCanvas.alignSelectedElements('c', 'page')
// highlight imported element, otherwise we get strange empty selectbox
this.svgCanvas.selectOnly([ newElement ]);
$id('se-prompt-dialog').setAttribute('close', true);
};
reader.readAsText(file);
this.svgCanvas.selectOnly([newElement])
$id('se-prompt-dialog').setAttribute('close', true)
}
reader.readAsText(file)
} else {
// bitmap handling
reader = new FileReader();
reader = new FileReader()
reader.onloadend = function ({ target: { result } }) {
/**
* Insert the new image until we know its dimensions.
@@ -93,54 +92,54 @@ export default {
id: this.svgCanvas.getNextId(),
style: 'pointer-events:inherit'
}
});
this.svgCanvas.setHref(newImage, result);
this.svgCanvas.selectOnly([ newImage ]);
this.svgCanvas.alignSelectedElements('m', 'page');
this.svgCanvas.alignSelectedElements('c', 'page');
this.topPanel.updateContextPanel();
$id('se-prompt-dialog').setAttribute('close', true);
};
})
this.svgCanvas.setHref(newImage, result)
this.svgCanvas.selectOnly([newImage])
this.svgCanvas.alignSelectedElements('m', 'page')
this.svgCanvas.alignSelectedElements('c', 'page')
this.topPanel.updateContextPanel()
$id('se-prompt-dialog').setAttribute('close', true)
}
// create dummy img so we know the default dimensions
let imgWidth = 100;
let imgHeight = 100;
const img = new Image();
img.style.opacity = 0;
let imgWidth = 100
let imgHeight = 100
const img = new Image()
img.style.opacity = 0
img.addEventListener('load', () => {
imgWidth = img.offsetWidth || img.naturalWidth || img.width;
imgHeight = img.offsetHeight || img.naturalHeight || img.height;
insertNewImage(imgWidth, imgHeight);
});
img.src = result;
};
reader.readAsDataURL(file);
imgWidth = img.offsetWidth || img.naturalWidth || img.width
imgHeight = img.offsetHeight || img.naturalHeight || img.height
insertNewImage(imgWidth, imgHeight)
})
img.src = result
}
reader.readAsDataURL(file)
}
};
}
// create an input with type file to open the filesystem dialog
const imgImport = document.createElement('input');
imgImport.type="file";
imgImport.addEventListener('change', importImage);
const imgImport = document.createElement('input')
imgImport.type = 'file'
imgImport.addEventListener('change', importImage)
// dropping a svg file will import it in the svg as well
this.workarea.addEventListener('drop', importImage);
this.workarea.addEventListener('drop', importImage)
/**
* @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument
* @returns {void}
*/
const clickClear = async function () {
const [ x, y ] = svgEditor.configObj.curConfig.dimensions;
const ok = await seConfirm(svgEditor.i18next.t('notification.QwantToClear'));
if (ok === "Cancel") {
return;
const [x, y] = svgEditor.configObj.curConfig.dimensions
const ok = await seConfirm(svgEditor.i18next.t('notification.QwantToClear'))
if (ok === 'Cancel') {
return
}
svgEditor.leftPanel.clickSelect();
svgEditor.svgCanvas.clear();
svgEditor.svgCanvas.setResolution(x, y);
svgEditor.updateCanvas(true);
svgEditor.zoomImage();
svgEditor.layersPanel.populateLayers();
svgEditor.topPanel.updateContextPanel();
svgEditor.svgCanvas.runExtensions("onNewDocument");
};
svgEditor.leftPanel.clickSelect()
svgEditor.svgCanvas.clear()
svgEditor.svgCanvas.setResolution(x, y)
svgEditor.updateCanvas(true)
svgEditor.zoomImage()
svgEditor.layersPanel.populateLayers()
svgEditor.topPanel.updateContextPanel()
svgEditor.svgCanvas.runExtensions('onNewDocument')
}
/**
* By default, this.editor.svgCanvas.open() is a no-op. It is up to an extension
@@ -150,113 +149,113 @@ export default {
*/
const clickOpen = async function () {
// ask user before clearing an unsaved SVG
const response = await svgEditor.openPrep();
if (response === 'Cancel') { return; }
svgCanvas.clear();
const response = await svgEditor.openPrep()
if (response === 'Cancel') { return }
svgCanvas.clear()
try {
const blob = await fileOpen({
mimeTypes: [ 'image/*' ]
});
const svgContent = await blob.text();
await svgEditor.loadSvgString(svgContent);
svgEditor.updateCanvas();
mimeTypes: ['image/*']
})
const svgContent = await blob.text()
await svgEditor.loadSvgString(svgContent)
svgEditor.updateCanvas()
} catch (err) {
if (err.name !== 'AbortError') {
return console.error(err);
return console.error(err)
}
}
};
}
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
const byteCharacters = atob(b64Data)
const byteArrays = []
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
const slice = byteCharacters.slice(offset, offset + sliceSize)
const byteNumbers = new Array(slice.length)
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
byteNumbers[i] = slice.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}
const blob = new Blob(byteArrays, { type: contentType });
return blob;
};
const blob = new Blob(byteArrays, { type: contentType })
return blob
}
/**
*
* @returns {void}
*/
const clickSave = async function (type, _) {
const $editorDialog = $id("se-svg-editor-dialog");
const editingsource = $editorDialog.getAttribute("dialog") === "open";
const $editorDialog = $id('se-svg-editor-dialog')
const editingsource = $editorDialog.getAttribute('dialog') === 'open'
if (editingsource) {
svgEditor.saveSourceEditor();
svgEditor.saveSourceEditor()
} else {
// In the future, more options can be provided here
const saveOpts = {
images: svgEditor.configObj.pref("img_save"),
images: svgEditor.configObj.pref('img_save'),
round_digits: 6
};
}
// remove the selected outline before serializing
svgCanvas.clearSelection();
svgCanvas.clearSelection()
// Update save options if provided
if (saveOpts) {
const saveOptions = svgCanvas.mergeDeep(svgCanvas.getSvgOption(), saveOpts);
for (const [ key, value ] of Object.entries(saveOptions)) {
svgCanvas.setSvgOption(key, value);
const saveOptions = svgCanvas.mergeDeep(svgCanvas.getSvgOption(), saveOpts)
for (const [key, value] of Object.entries(saveOptions)) {
svgCanvas.setSvgOption(key, value)
}
}
svgCanvas.setSvgOption('apply', true);
svgCanvas.setSvgOption('apply', true)
// no need for doctype, see https://jwatt.org/svg/authoring/#doctype-declaration
const svg = '<?xml version="1.0"?>\n' + svgCanvas.svgCanvasToString();
const b64Data = svgCanvas.encode64(svg);
const blob = b64toBlob(b64Data, 'image/svg+xml');
const svg = '<?xml version="1.0"?>\n' + svgCanvas.svgCanvasToString()
const b64Data = svgCanvas.encode64(svg)
const blob = b64toBlob(b64Data, 'image/svg+xml')
try {
if(type === "save" && handle !== null) {
const throwIfExistingHandleNotGood = false;
if (type === 'save' && handle !== null) {
const throwIfExistingHandleNotGood = false
handle = await fileSave(blob, {
fileName: 'icon.svg',
extensions: [ '.svg' ]
}, handle, throwIfExistingHandleNotGood);
extensions: ['.svg']
}, handle, throwIfExistingHandleNotGood)
} else {
handle = await fileSave(blob, {
fileName: 'icon.svg',
extensions: [ '.svg' ]
});
extensions: ['.svg']
})
}
} catch (err) {
if (err.name !== 'AbortError') {
return console.error(err);
return console.error(err)
}
}
}
};
}
return {
name: svgEditor.i18next.t(`${name}:name`),
// The callback should be used to load the DOM with the appropriate UI items
callback() {
callback () {
const buttonTemplate = `
<se-menu-item id="tool_clear" label="opensave.new_doc" shortcut="N" src="new.svg"></se-menu-item>`;
svgCanvas.insertChildAtIndex($id('main_button'), buttonTemplate, 0);
const openButtonTemplate = `<se-menu-item id="tool_open" label="opensave.open_image_doc" src="open.svg"></se-menu-item>`;
svgCanvas.insertChildAtIndex($id('main_button'), openButtonTemplate, 1);
const saveButtonTemplate = `<se-menu-item id="tool_save" label="opensave.save_doc" shortcut="S" src="saveImg.svg"></se-menu-item>`;
svgCanvas.insertChildAtIndex($id('main_button'), saveButtonTemplate, 2);
const saveAsButtonTemplate = `<se-menu-item id="tool_save_as" label="opensave.save_as_doc" src="saveImg.svg"></se-menu-item>`;
svgCanvas.insertChildAtIndex($id('main_button'), saveAsButtonTemplate, 3);
const importButtonTemplate = `<se-menu-item id="tool_import" label="tools.import_doc" src="importImg.svg"></se-menu-item>`;
svgCanvas.insertChildAtIndex($id('main_button'), importButtonTemplate, 4);
<se-menu-item id="tool_clear" label="opensave.new_doc" shortcut="N" src="new.svg"></se-menu-item>`
svgCanvas.insertChildAtIndex($id('main_button'), buttonTemplate, 0)
const openButtonTemplate = '<se-menu-item id="tool_open" label="opensave.open_image_doc" src="open.svg"></se-menu-item>'
svgCanvas.insertChildAtIndex($id('main_button'), openButtonTemplate, 1)
const saveButtonTemplate = '<se-menu-item id="tool_save" label="opensave.save_doc" shortcut="S" src="saveImg.svg"></se-menu-item>'
svgCanvas.insertChildAtIndex($id('main_button'), saveButtonTemplate, 2)
const saveAsButtonTemplate = '<se-menu-item id="tool_save_as" label="opensave.save_as_doc" src="saveImg.svg"></se-menu-item>'
svgCanvas.insertChildAtIndex($id('main_button'), saveAsButtonTemplate, 3)
const importButtonTemplate = '<se-menu-item id="tool_import" label="tools.import_doc" src="importImg.svg"></se-menu-item>'
svgCanvas.insertChildAtIndex($id('main_button'), importButtonTemplate, 4)
// handler
$id("tool_clear").addEventListener("click", clickClear.bind(this));
$id("tool_open").addEventListener("click", clickOpen.bind(this));
$id("tool_save").addEventListener("click", clickSave.bind(this, "save"));
$id("tool_save_as").addEventListener("click", clickSave.bind(this, "saveas"));
$id("tool_import").addEventListener("click", () => imgImport.click());
$id('tool_clear').addEventListener('click', clickClear.bind(this))
$id('tool_open').addEventListener('click', clickOpen.bind(this))
$id('tool_save').addEventListener('click', clickSave.bind(this, 'save'))
$id('tool_save_as').addEventListener('click', clickSave.bind(this, 'saveas'))
$id('tool_import').addEventListener('click', () => imgImport.click())
}
};
}
}
};
}

View File

@@ -5,4 +5,4 @@ export default {
save_doc: 'Save SVG',
save_as_doc: 'Save as SVG'
}
};
}

View File

@@ -5,4 +5,4 @@ export default {
save_doc: 'Enregistrer l\'image',
save_as_doc: 'Enregistrer en tant qu\'image'
}
};
}

View File

@@ -5,4 +5,4 @@ export default {
save_doc: '保存图像',
save_as_doc: '另存为图像'
}
};
}

View File

@@ -3,95 +3,95 @@
// MIT License.
// can't use npm version as the dragmove is different.
let _loaded = false;
const _callbacks = [];
const _isTouch = window.ontouchstart !== undefined;
let _loaded = false
const _callbacks = []
const _isTouch = window.ontouchstart !== undefined
export const dragmove = function(target, handler, parent, onStart, onEnd, onDrag) {
export const dragmove = function (target, handler, parent, onStart, onEnd, onDrag) {
// Register a global event to capture mouse moves (once).
if (!_loaded) {
document.addEventListener(_isTouch ? "touchmove" : "mousemove", function(e) {
let c = e;
document.addEventListener(_isTouch ? 'touchmove' : 'mousemove', function (e) {
let c = e
if (e.touches) {
c = e.touches[0];
c = e.touches[0]
}
// On mouse move, dispatch the coords to all registered callbacks.
for (let i = 0; i < _callbacks.length; i++) {
_callbacks[i](c.clientX, c.clientY);
_callbacks[i](c.clientX, c.clientY)
}
});
})
}
_loaded = true;
let isMoving = false; let hasStarted = false;
let startX = 0; let startY = 0; let lastX = 0; let lastY = 0;
_loaded = true
let isMoving = false; let hasStarted = false
let startX = 0; let startY = 0; let lastX = 0; let lastY = 0
// On the first click and hold, record the offset of the pointer in relation
// to the point of click inside the element.
handler.addEventListener(_isTouch ? "touchstart" : "mousedown", function(e) {
e.stopPropagation();
e.preventDefault();
if (target.dataset.dragEnabled === "false") {
return;
handler.addEventListener(_isTouch ? 'touchstart' : 'mousedown', function (e) {
e.stopPropagation()
e.preventDefault()
if (target.dataset.dragEnabled === 'false') {
return
}
let c = e;
let c = e
if (e.touches) {
c = e.touches[0];
c = e.touches[0]
}
isMoving = true;
startX = target.offsetLeft - c.clientX;
startY = target.offsetTop - c.clientY;
});
isMoving = true
startX = target.offsetLeft - c.clientX
startY = target.offsetTop - c.clientY
})
// On leaving click, stop moving.
document.addEventListener(_isTouch ? "touchend" : "mouseup", function() {
document.addEventListener(_isTouch ? 'touchend' : 'mouseup', function () {
if (onEnd && hasStarted) {
onEnd(target, parent, parseInt(target.style.left), parseInt(target.style.top));
onEnd(target, parent, parseInt(target.style.left), parseInt(target.style.top))
}
isMoving = false;
hasStarted = false;
});
isMoving = false
hasStarted = false
})
// On leaving click, stop moving.
document.addEventListener(_isTouch ? "touchmove" : "mousemove", function() {
document.addEventListener(_isTouch ? 'touchmove' : 'mousemove', function () {
if (onDrag && hasStarted) {
onDrag(target, parseInt(target.style.left), parseInt(target.style.top));
onDrag(target, parseInt(target.style.left), parseInt(target.style.top))
}
});
})
// Register mouse-move callback to move the element.
_callbacks.push(function move(x, y) {
_callbacks.push(function move (x, y) {
if (!isMoving) {
return;
return
}
if (!hasStarted) {
hasStarted = true;
hasStarted = true
if (onStart) {
onStart(target, lastX, lastY);
onStart(target, lastX, lastY)
}
}
lastX = x + startX;
lastY = y + startY;
lastX = x + startX
lastY = y + startY
// If boundary checking is on, don't let the element cross the viewport.
if (target.dataset.dragBoundary === "true") {
if (target.dataset.dragBoundary === 'true') {
if (lastX < 1 || lastX >= window.innerWidth - target.offsetWidth) {
return;
return
}
if (lastY < 1 || lastY >= window.innerHeight - target.offsetHeight) {
return;
return
}
}
target.style.left = lastX + "px";
target.style.top = lastY + "px";
});
};
target.style.left = lastX + 'px'
target.style.top = lastY + 'px'
})
}
export { dragmove as default };
export { dragmove as default }

View File

@@ -6,14 +6,14 @@
* @copyright 2013 James Sacksteder
*
*/
import { dragmove } from './dragmove/dragmove.js';
import { dragmove } from './dragmove/dragmove.js'
export default {
name: 'overview_window',
init ({ _$ }) {
const svgEditor = this;
const { $id } = svgEditor.svgCanvas;
const overviewWindowGlobals = {};
const svgEditor = this
const { $id } = svgEditor.svgCanvas
const overviewWindowGlobals = {}
// Define and insert the base html element.
const propsWindowHtml =
@@ -29,129 +29,128 @@ export default {
'</div>' +
'</div>' +
'</div>' +
'</div>';
$id("sidepanel_content").insertAdjacentHTML( 'beforeend', propsWindowHtml );
'</div>'
$id('sidepanel_content').insertAdjacentHTML('beforeend', propsWindowHtml)
// Define dynamic animation of the view box.
const updateViewBox = () => {
const { workarea } = svgEditor;
const portHeight = parseFloat(getComputedStyle(workarea, null).height.replace("px", ""));
const portWidth = parseFloat(getComputedStyle(workarea, null).width.replace("px", ""));
const portX = workarea.scrollLeft;
const portY = workarea.scrollTop;
const windowWidth = parseFloat(getComputedStyle($id("svgcanvas"), null).width.replace("px", ""));
const windowHeight = parseFloat(getComputedStyle($id("svgcanvas"), null).height.replace("px", ""));
const overviewWidth = parseFloat(getComputedStyle($id("overviewMiniView"), null).width.replace("px", ""));
const overviewHeight = parseFloat(getComputedStyle($id("overviewMiniView"), null).height.replace("px", ""));
const { workarea } = svgEditor
const portHeight = parseFloat(getComputedStyle(workarea, null).height.replace('px', ''))
const portWidth = parseFloat(getComputedStyle(workarea, null).width.replace('px', ''))
const portX = workarea.scrollLeft
const portY = workarea.scrollTop
const windowWidth = parseFloat(getComputedStyle($id('svgcanvas'), null).width.replace('px', ''))
const windowHeight = parseFloat(getComputedStyle($id('svgcanvas'), null).height.replace('px', ''))
const overviewWidth = parseFloat(getComputedStyle($id('overviewMiniView'), null).width.replace('px', ''))
const overviewHeight = parseFloat(getComputedStyle($id('overviewMiniView'), null).height.replace('px', ''))
const viewBoxX = portX / windowWidth * overviewWidth;
const viewBoxY = portY / windowHeight * overviewHeight;
const viewBoxWidth = portWidth / windowWidth * overviewWidth;
const viewBoxHeight = portHeight / windowHeight * overviewHeight;
const viewBoxX = portX / windowWidth * overviewWidth
const viewBoxY = portY / windowHeight * overviewHeight
const viewBoxWidth = portWidth / windowWidth * overviewWidth
const viewBoxHeight = portHeight / windowHeight * overviewHeight
$id("overview_window_view_box").style.minWidth = viewBoxWidth + 'px';
$id("overview_window_view_box").style.minHeight = viewBoxHeight + 'px';
$id("overview_window_view_box").style.top = viewBoxY + 'px';
$id("overview_window_view_box").style.left = viewBoxX + 'px';
};
$id('overview_window_view_box').style.minWidth = viewBoxWidth + 'px'
$id('overview_window_view_box').style.minHeight = viewBoxHeight + 'px'
$id('overview_window_view_box').style.top = viewBoxY + 'px'
$id('overview_window_view_box').style.left = viewBoxX + 'px'
}
$id('workarea').addEventListener('scroll', () => {
if (!(overviewWindowGlobals.viewBoxDragging)) {
updateViewBox();
updateViewBox()
}
});
$id('workarea').addEventListener('resize', updateViewBox);
updateViewBox();
})
$id('workarea').addEventListener('resize', updateViewBox)
updateViewBox()
// Compensate for changes in zoom and canvas size.
const updateViewDimensions = function () {
const viewWidth = parseFloat(getComputedStyle($id("svgroot"), null).width.replace("px", ""));
const viewHeight = parseFloat(getComputedStyle($id("svgroot"), null).height.replace("px", ""));
const viewWidth = parseFloat(getComputedStyle($id('svgroot'), null).width.replace('px', ''))
const viewHeight = parseFloat(getComputedStyle($id('svgroot'), null).height.replace('px', ''))
const viewX = 640;
const viewY = 480;
const viewX = 640
const viewY = 480
const svgWidthOld = parseFloat(getComputedStyle($id("overviewMiniView"), null).width.replace("px", ""));
const svgHeightNew = viewHeight / viewWidth * svgWidthOld;
$id('overviewMiniView').setAttribute('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
$id('overviewMiniView').setAttribute('height', svgHeightNew);
updateViewBox();
};
updateViewDimensions();
const svgWidthOld = parseFloat(getComputedStyle($id('overviewMiniView'), null).width.replace('px', ''))
const svgHeightNew = viewHeight / viewWidth * svgWidthOld
$id('overviewMiniView').setAttribute('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight)
$id('overviewMiniView').setAttribute('height', svgHeightNew)
updateViewBox()
}
updateViewDimensions()
// Set up the overview window as a controller for the view port.
overviewWindowGlobals.viewBoxDragging = false;
overviewWindowGlobals.viewBoxDragging = false
const updateViewPortFromViewBox = function () {
const windowWidth = parseFloat(getComputedStyle($id("svgcanvas"), null).width.replace("px", ""));
const windowHeight = parseFloat(getComputedStyle($id("svgcanvas"), null).height.replace("px", ""));
const overviewWidth = parseFloat(getComputedStyle($id("overviewMiniView"), null).width.replace("px", ""));
const overviewHeight = parseFloat(getComputedStyle($id("overviewMiniView"), null).height.replace("px", ""));
const viewBoxX = parseFloat(getComputedStyle($id("overview_window_view_box"), null).getPropertyValue('left').replace("px", ""));
const viewBoxY = parseFloat(getComputedStyle($id("overview_window_view_box"), null).getPropertyValue('top').replace("px", ""));
const windowWidth = parseFloat(getComputedStyle($id('svgcanvas'), null).width.replace('px', ''))
const windowHeight = parseFloat(getComputedStyle($id('svgcanvas'), null).height.replace('px', ''))
const overviewWidth = parseFloat(getComputedStyle($id('overviewMiniView'), null).width.replace('px', ''))
const overviewHeight = parseFloat(getComputedStyle($id('overviewMiniView'), null).height.replace('px', ''))
const viewBoxX = parseFloat(getComputedStyle($id('overview_window_view_box'), null).getPropertyValue('left').replace('px', ''))
const viewBoxY = parseFloat(getComputedStyle($id('overview_window_view_box'), null).getPropertyValue('top').replace('px', ''))
const portX = viewBoxX / overviewWidth * windowWidth;
const portY = viewBoxY / overviewHeight * windowHeight;
$id('workarea').scrollLeft = portX;
$id('workarea').scrollTop = portY;
};
const portX = viewBoxX / overviewWidth * windowWidth
const portY = viewBoxY / overviewHeight * windowHeight
$id('workarea').scrollLeft = portX
$id('workarea').scrollTop = portY
}
const onStart = () => {
overviewWindowGlobals.viewBoxDragging = true;
updateViewPortFromViewBox();
};
overviewWindowGlobals.viewBoxDragging = true
updateViewPortFromViewBox()
}
const onEnd = (el, parent, _x, _y) => {
if((el.offsetLeft + el.offsetWidth) > parseFloat(getComputedStyle(parent, null).width.replace("px", ""))){
el.style.left = (parseFloat(getComputedStyle(parent, null).width.replace("px", "")) - el.offsetWidth) + 'px';
} else if(el.offsetLeft < 0){
el.style.left = "0px";
if ((el.offsetLeft + el.offsetWidth) > parseFloat(getComputedStyle(parent, null).width.replace('px', ''))) {
el.style.left = (parseFloat(getComputedStyle(parent, null).width.replace('px', '')) - el.offsetWidth) + 'px'
} else if (el.offsetLeft < 0) {
el.style.left = '0px'
}
if((el.offsetTop + el.offsetHeight) > parseFloat(getComputedStyle(parent, null).height.replace("px", ""))){
el.style.top = (parseFloat(getComputedStyle(parent, null).height.replace("px", "")) - el.offsetHeight) + 'px';
} else if(el.offsetTop < 0){
el.style.top = "0px";
if ((el.offsetTop + el.offsetHeight) > parseFloat(getComputedStyle(parent, null).height.replace('px', ''))) {
el.style.top = (parseFloat(getComputedStyle(parent, null).height.replace('px', '')) - el.offsetHeight) + 'px'
} else if (el.offsetTop < 0) {
el.style.top = '0px'
}
overviewWindowGlobals.viewBoxDragging = false;
updateViewPortFromViewBox();
};
overviewWindowGlobals.viewBoxDragging = false
updateViewPortFromViewBox()
}
const onDrag = function () {
updateViewPortFromViewBox();
};
const dragElem = document.querySelector("#overview_window_view_box");
const parentElem = document.querySelector("#overviewMiniView");
dragmove(dragElem, dragElem, parentElem, onStart, onEnd, onDrag);
updateViewPortFromViewBox()
}
const dragElem = document.querySelector('#overview_window_view_box')
const parentElem = document.querySelector('#overviewMiniView')
dragmove(dragElem, dragElem, parentElem, onStart, onEnd, onDrag)
$id("overviewMiniView").addEventListener("click", (evt) => {
$id('overviewMiniView').addEventListener('click', (evt) => {
// Firefox doesn't support evt.offsetX and evt.offsetY.
const mouseX = (evt.offsetX || evt.originalEvent.layerX);
const mouseY = (evt.offsetY || evt.originalEvent.layerY);
const overviewWidth = parseFloat(getComputedStyle($id("overviewMiniView"), null).width.replace("px", ""));
const overviewHeight = parseFloat(getComputedStyle($id("overviewMiniView"), null).height.replace("px", ""));
const viewBoxWidth = parseFloat(getComputedStyle($id("overview_window_view_box"), null).getPropertyValue('min-width').replace("px", ""));
const viewBoxHeight = parseFloat(getComputedStyle($id("overview_window_view_box"), null).getPropertyValue('min-height').replace("px", ""));
const mouseX = (evt.offsetX || evt.originalEvent.layerX)
const mouseY = (evt.offsetY || evt.originalEvent.layerY)
const overviewWidth = parseFloat(getComputedStyle($id('overviewMiniView'), null).width.replace('px', ''))
const overviewHeight = parseFloat(getComputedStyle($id('overviewMiniView'), null).height.replace('px', ''))
const viewBoxWidth = parseFloat(getComputedStyle($id('overview_window_view_box'), null).getPropertyValue('min-width').replace('px', ''))
const viewBoxHeight = parseFloat(getComputedStyle($id('overview_window_view_box'), null).getPropertyValue('min-height').replace('px', ''))
let viewBoxX = mouseX - 0.5 * viewBoxWidth;
let viewBoxY = mouseY - 0.5 * viewBoxHeight;
let viewBoxX = mouseX - 0.5 * viewBoxWidth
let viewBoxY = mouseY - 0.5 * viewBoxHeight
// deal with constraints
if (viewBoxX < 0) {
viewBoxX = 0;
viewBoxX = 0
}
if (viewBoxY < 0) {
viewBoxY = 0;
viewBoxY = 0
}
if (viewBoxX + viewBoxWidth > overviewWidth) {
viewBoxX = overviewWidth - viewBoxWidth;
viewBoxX = overviewWidth - viewBoxWidth
}
if (viewBoxY + viewBoxHeight > overviewHeight) {
viewBoxY = overviewHeight - viewBoxHeight;
viewBoxY = overviewHeight - viewBoxHeight
}
$id("overview_window_view_box").style.top = viewBoxY + 'px';
$id("overview_window_view_box").style.left = viewBoxX + 'px';
updateViewPortFromViewBox();
});
$id('overview_window_view_box').style.top = viewBoxY + 'px'
$id('overview_window_view_box').style.left = viewBoxX + 'px'
updateViewPortFromViewBox()
})
return {
name: 'overview window',
canvasUpdated: updateViewDimensions,
workareaResized: updateViewBox
};
}
}
};
}

View File

@@ -10,71 +10,69 @@
This is a very basic SVG-Edit extension to let tablet/mobile devices pan without problem
*/
const name = "panning";
const name = 'panning'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init() {
const svgEditor = this;
await loadExtensionTranslation(svgEditor);
async init () {
const svgEditor = this
await loadExtensionTranslation(svgEditor)
const {
svgCanvas
} = svgEditor;
} = svgEditor
const {
$id
} = svgCanvas;
} = svgCanvas
const insertAfter = (referenceNode, newNode) => {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
};
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)
}
return {
name: svgEditor.i18next.t(`${name}:name`),
callback() {
const btitle = `${name}:buttons.0.title`;
callback () {
const btitle = `${name}:buttons.0.title`
// Add the button and its handler(s)
const buttonTemplate = document.createElement("template");
// eslint-disable-next-line no-unsanitized/property
const buttonTemplate = document.createElement('template')
buttonTemplate.innerHTML = `
<se-button id="ext-panning" title="${btitle}" src="panning.svg"></se-button>
`;
insertAfter($id('tool_zoom'), buttonTemplate.content.cloneNode(true));
$id('ext-panning').addEventListener("click", () => {
if (this.leftPanel.updateLeftPanel("ext-panning")) {
svgCanvas.setMode('ext-panning');
`
insertAfter($id('tool_zoom'), buttonTemplate.content.cloneNode(true))
$id('ext-panning').addEventListener('click', () => {
if (this.leftPanel.updateLeftPanel('ext-panning')) {
svgCanvas.setMode('ext-panning')
}
});
})
},
mouseDown() {
mouseDown () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true);
svgEditor.setPanning(true)
return {
started: true
};
}
}
return undefined;
return undefined
},
mouseUp() {
mouseUp () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false);
svgEditor.setPanning(false)
return {
keep: false,
element: null
};
}
}
return undefined;
return undefined
}
};
}
}
};
}

View File

@@ -5,4 +5,4 @@ export default {
title: 'Panning'
}
]
};
}

View File

@@ -5,4 +5,4 @@ export default {
title: '移动'
}
]
};
}

View File

@@ -8,33 +8,32 @@
*
*/
const name = "polystar";
const name = 'polystar'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init() {
const svgEditor = this;
const { svgCanvas } = svgEditor;
const { ChangeElementCommand } = svgCanvas.history;
const addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); };
const { $id } = svgCanvas;
let selElems;
let started;
let newFO;
await loadExtensionTranslation(svgEditor);
async init () {
const svgEditor = this
const { svgCanvas } = svgEditor
const { ChangeElementCommand } = svgCanvas.history
const addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd) }
const { $id } = svgCanvas
let selElems
let started
let newFO
await loadExtensionTranslation(svgEditor)
/**
* @param {boolean} on true=display
@@ -43,11 +42,11 @@ export default {
*/
const showPanel = (on, tool) => {
if (on) {
$id(`${tool}_panel`).style.removeProperty('display');
$id(`${tool}_panel`).style.removeProperty('display')
} else {
$id(`${tool}_panel`).style.display = 'none';
$id(`${tool}_panel`).style.display = 'none'
}
};
}
/**
*
@@ -56,66 +55,65 @@ export default {
* @returns {void}
*/
const setAttr = (attr, val) => {
svgCanvas.changeSelectedAttribute(attr, val);
svgCanvas.call("changed", selElems);
};
svgCanvas.changeSelectedAttribute(attr, val)
svgCanvas.call('changed', selElems)
}
/**
* @param {Float} n angle
* @return {Float} cotangeante
*/
const cot = (n) => 1 / Math.tan(n);
const cot = (n) => 1 / Math.tan(n)
/**
* @param {Float} n angle
* @returns {Float} sec
*/
const sec = (n) => 1 / Math.cos(n);
const sec = (n) => 1 / Math.cos(n)
return {
name: svgEditor.i18next.t(`${name}:name`),
// The callback should be used to load the DOM with the appropriate UI items
callback() {
callback () {
// Add the button and its handler(s)
// Note: the star extension needs to be loaded before the polygon extension
const fbtitle = `${name}:title`;
const title_star = `${name}:buttons.0.title`;
const title_polygon = `${name}:buttons.1.title`;
const fbtitle = `${name}:title`
const titleStar = `${name}:buttons.0.title`
const titlePolygon = `${name}:buttons.1.title`
const buttonTemplate = `
<se-flyingbutton id="tools_polygon" title="${fbtitle}">
<se-button id="tool_star" title="${title_star}" src="star.svg">
<se-button id="tool_star" title="${titleStar}" src="star.svg">
</se-button>
<se-button id="tool_polygon" title="${title_polygon}" src="polygon.svg">
<se-button id="tool_polygon" title="${titlePolygon}" src="polygon.svg">
</se-button>
</se-flyingbutton>
`;
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 10);
`
svgCanvas.insertChildAtIndex($id('tools_left'), buttonTemplate, 10)
// handler
$id("tool_star").addEventListener("click", () => {
if (this.leftPanel.updateLeftPanel("tool_star")) {
svgCanvas.setMode("star");
showPanel(true, "star");
showPanel(false, "polygon");
$id('tool_star').addEventListener('click', () => {
if (this.leftPanel.updateLeftPanel('tool_star')) {
svgCanvas.setMode('star')
showPanel(true, 'star')
showPanel(false, 'polygon')
}
});
$id("tool_polygon").addEventListener("click", () => {
if (this.leftPanel.updateLeftPanel("tool_polygon")) {
svgCanvas.setMode("polygon");
showPanel(true, "polygon");
showPanel(false, "star");
})
$id('tool_polygon').addEventListener('click', () => {
if (this.leftPanel.updateLeftPanel('tool_polygon')) {
svgCanvas.setMode('polygon')
showPanel(true, 'polygon')
showPanel(false, 'star')
}
});
const label0 = `${name}:contextTools.0.label`;
const title0 = `${name}:contextTools.0.title`;
const label1 = `${name}:contextTools.1.label`;
const title1 = `${name}:contextTools.1.title`;
const label2 = `${name}:contextTools.2.label`;
const title2 = `${name}:contextTools.2.title`;
const label3 = `${name}:contextTools.3.label`;
const title3 = `${name}:contextTools.3.title`;
})
const label0 = `${name}:contextTools.0.label`
const title0 = `${name}:contextTools.0.title`
const label1 = `${name}:contextTools.1.label`
const title1 = `${name}:contextTools.1.title`
const label2 = `${name}:contextTools.2.label`
const title2 = `${name}:contextTools.2.title`
const label3 = `${name}:contextTools.3.label`
const title3 = `${name}:contextTools.3.title`
// Add the context panel and its handler(s)
const panelTemplate = document.createElement("template");
// eslint-disable-next-line no-unsanitized/property
const panelTemplate = document.createElement('template')
panelTemplate.innerHTML = `
<div id="star_panel">
<se-spin-input id="starNumPoints" label="${label0}" min=1 step=1 value=5 title="${title0}">
@@ -129,324 +127,324 @@ export default {
<se-spin-input size="3" id="polySides" min=1 step=1 value=5 label="${label3}" title="${title3}">
</se-spin-input>
</div>
`;
//add handlers for the panel
$id("tools_top").appendChild(panelTemplate.content.cloneNode(true));
`
// add handlers for the panel
$id('tools_top').appendChild(panelTemplate.content.cloneNode(true))
// don't display the panels on start
showPanel(false, "star");
showPanel(false, "polygon");
$id("starNumPoints").addEventListener("change", (event) => {
setAttr("point", event.target.value);
const orient = 'point';
const point = event.target.value;
let i = selElems.length;
showPanel(false, 'star')
showPanel(false, 'polygon')
$id('starNumPoints').addEventListener('change', (event) => {
setAttr('point', event.target.value)
const orient = 'point'
const point = event.target.value
let i = selElems.length
while (i--) {
const elem = selElems[i];
const elem = selElems[i]
if (elem.hasAttribute('r')) {
const oldPoint = elem.getAttribute('point');
const oldPoints = elem.getAttribute('points');
const radialshift = elem.getAttribute('radialshift');
let xpos = 0;
let ypos = 0;
const oldPoint = elem.getAttribute('point')
const oldPoints = elem.getAttribute('points')
const radialshift = elem.getAttribute('radialshift')
let xpos = 0
let ypos = 0
if (elem.points) {
const list = elem.points;
const len = list.numberOfItems;
const list = elem.points
const len = list.numberOfItems
for (let i = 0; i < len; ++i) {
const pt = list.getItem(i);
xpos += parseFloat(pt.x);
ypos += parseFloat(pt.y);
const pt = list.getItem(i)
xpos += parseFloat(pt.x)
ypos += parseFloat(pt.y)
}
const cx = xpos / len;
const cy = ypos / len;
const circumradius = Number(elem.getAttribute('r'));
const inradius = circumradius / elem.getAttribute('starRadiusMultiplier');
const cx = xpos / len
const cy = ypos / len
const circumradius = Number(elem.getAttribute('r'))
const inradius = circumradius / elem.getAttribute('starRadiusMultiplier')
let polyPoints = "";
let polyPoints = ''
for (let s = 0; point >= s; s++) {
let angle = 2.0 * Math.PI * (s / point);
if (orient === "point") {
angle -= Math.PI / 2;
} else if (orient === "edge") {
angle = angle + Math.PI / point - Math.PI / 2;
let angle = 2.0 * Math.PI * (s / point)
if (orient === 'point') {
angle -= Math.PI / 2
} else if (orient === 'edge') {
angle = angle + Math.PI / point - Math.PI / 2
}
let x = circumradius * Math.cos(angle) + cx;
let y = circumradius * Math.sin(angle) + cy;
let x = circumradius * Math.cos(angle) + cx
let y = circumradius * Math.sin(angle) + cy
polyPoints += x + "," + y + " ";
polyPoints += x + ',' + y + ' '
if (!isNaN(inradius)) {
angle = 2.0 * Math.PI * (s / point) + Math.PI / point;
if (orient === "point") {
angle -= Math.PI / 2;
} else if (orient === "edge") {
angle = angle + Math.PI / point - Math.PI / 2;
angle = 2.0 * Math.PI * (s / point) + Math.PI / point
if (orient === 'point') {
angle -= Math.PI / 2
} else if (orient === 'edge') {
angle = angle + Math.PI / point - Math.PI / 2
}
angle += radialshift;
angle += radialshift
x = inradius * Math.cos(angle) + cx;
y = inradius * Math.sin(angle) + cy;
x = inradius * Math.cos(angle) + cx
y = inradius * Math.sin(angle) + cy
polyPoints += x + "," + y + " ";
polyPoints += x + ',' + y + ' '
}
}
elem.setAttribute("points", polyPoints);
addToHistory(new ChangeElementCommand(elem, { 'point': oldPoint, 'points': oldPoints }));
elem.setAttribute('points', polyPoints)
addToHistory(new ChangeElementCommand(elem, { point: oldPoint, points: oldPoints }))
}
}
}
});
$id("RadiusMultiplier").addEventListener("change", (event) => {
setAttr("starRadiusMultiplier", event.target.value);
});
$id("radialShift").addEventListener("change", (event) => {
setAttr("radialshift", event.target.value);
});
$id("polySides").addEventListener("change", (event) => {
setAttr("sides", event.target.value);
const sides = event.target.value;
let i = selElems.length;
})
$id('RadiusMultiplier').addEventListener('change', (event) => {
setAttr('starRadiusMultiplier', event.target.value)
})
$id('radialShift').addEventListener('change', (event) => {
setAttr('radialshift', event.target.value)
})
$id('polySides').addEventListener('change', (event) => {
setAttr('sides', event.target.value)
const sides = event.target.value
let i = selElems.length
while (i--) {
const elem = selElems[i];
const elem = selElems[i]
if (elem.hasAttribute('edge')) {
const oldSides = elem.getAttribute('sides');
const oldPoints = elem.getAttribute('points');
let xpos = 0;
let ypos = 0;
const oldSides = elem.getAttribute('sides')
const oldPoints = elem.getAttribute('points')
let xpos = 0
let ypos = 0
if (elem.points) {
const list = elem.points;
const len = list.numberOfItems;
const list = elem.points
const len = list.numberOfItems
for (let i = 0; i < len; ++i) {
const pt = list.getItem(i);
xpos += parseFloat(pt.x);
ypos += parseFloat(pt.y);
const pt = list.getItem(i)
xpos += parseFloat(pt.x)
ypos += parseFloat(pt.y)
}
const cx = xpos / len;
const cy = ypos / len;
const edg = elem.getAttribute('edge');
const inradius = (edg / 2) * cot(Math.PI / sides);
const circumradius = inradius * sec(Math.PI / sides);
let points = "";
const cx = xpos / len
const cy = ypos / len
const edg = elem.getAttribute('edge')
const inradius = (edg / 2) * cot(Math.PI / sides)
const circumradius = inradius * sec(Math.PI / sides)
let points = ''
for (let s = 0; sides >= s; s++) {
const angle = (2.0 * Math.PI * s) / sides;
const x = circumradius * Math.cos(angle) + cx;
const y = circumradius * Math.sin(angle) + cy;
points += x + "," + y + " ";
const angle = (2.0 * Math.PI * s) / sides
const x = circumradius * Math.cos(angle) + cx
const y = circumradius * Math.sin(angle) + cy
points += x + ',' + y + ' '
}
elem.setAttribute("points", points);
addToHistory(new ChangeElementCommand(elem, { 'sides': oldSides, 'points': oldPoints }));
elem.setAttribute('points', points)
addToHistory(new ChangeElementCommand(elem, { sides: oldSides, points: oldPoints }))
}
}
}
});
})
},
mouseDown(opts) {
if (svgCanvas.getMode() === "star") {
const rgb = svgCanvas.getColor("fill");
const sRgb = svgCanvas.getColor("stroke");
const sWidth = svgCanvas.getStrokeWidth();
started = true;
mouseDown (opts) {
if (svgCanvas.getMode() === 'star') {
const rgb = svgCanvas.getColor('fill')
const sRgb = svgCanvas.getColor('stroke')
const sWidth = svgCanvas.getStrokeWidth()
started = true
newFO = svgCanvas.addSVGElemensFromJson({
element: "polygon",
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: svgCanvas.getNextId(),
shape: "star",
point: $id("starNumPoints").value,
shape: 'star',
point: $id('starNumPoints').value,
r: 0,
radialshift: $id("radialShift").value,
radialshift: $id('radialShift').value,
r2: 0,
orient: "point",
orient: 'point',
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
}
});
})
return {
started: true
};
}
}
if (svgCanvas.getMode() === "polygon") {
if (svgCanvas.getMode() === 'polygon') {
// const e = opts.event;
const rgb = svgCanvas.getColor("fill");
const rgb = svgCanvas.getColor('fill')
// const ccRgbEl = rgb.substring(1, rgb.length);
const sRgb = svgCanvas.getColor("stroke");
const sRgb = svgCanvas.getColor('stroke')
// ccSRgbEl = sRgb.substring(1, rgb.length);
const sWidth = svgCanvas.getStrokeWidth();
started = true;
const sWidth = svgCanvas.getStrokeWidth()
started = true
newFO = svgCanvas.addSVGElemensFromJson({
element: "polygon",
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: svgCanvas.getNextId(),
shape: "regularPoly",
sides: $id("polySides").value,
orient: "x",
shape: 'regularPoly',
sides: $id('polySides').value,
orient: 'x',
edge: 0,
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
}
});
})
return {
started: true
};
}
}
return undefined;
return undefined
},
mouseMove(opts) {
mouseMove (opts) {
if (!started) {
return undefined;
return undefined
}
if (svgCanvas.getMode() === "star") {
const cx = Number(newFO.getAttribute("cx"));
const cy = Number(newFO.getAttribute("cy"));
const point = Number(newFO.getAttribute("point"));
const orient = newFO.getAttribute("orient");
const fill = newFO.getAttribute("fill");
const strokecolor = newFO.getAttribute("strokecolor");
const strokeWidth = Number(newFO.getAttribute("strokeWidth"));
const radialshift = Number(newFO.getAttribute("radialshift"));
if (svgCanvas.getMode() === 'star') {
const cx = Number(newFO.getAttribute('cx'))
const cy = Number(newFO.getAttribute('cy'))
const point = Number(newFO.getAttribute('point'))
const orient = newFO.getAttribute('orient')
const fill = newFO.getAttribute('fill')
const strokecolor = newFO.getAttribute('strokecolor')
const strokeWidth = Number(newFO.getAttribute('strokeWidth'))
const radialshift = Number(newFO.getAttribute('radialshift'))
let x = opts.mouse_x;
let y = opts.mouse_y;
let x = opts.mouse_x
let y = opts.mouse_y
const circumradius =
Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) / 1.5;
const RadiusMultiplier = document.getElementById("RadiusMultiplier").value;
Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) / 1.5
const RadiusMultiplier = document.getElementById('RadiusMultiplier').value
const inradius =
circumradius / RadiusMultiplier;
newFO.setAttribute("r", circumradius);
newFO.setAttribute("r2", inradius);
newFO.setAttribute('starRadiusMultiplier', RadiusMultiplier);
circumradius / RadiusMultiplier
newFO.setAttribute('r', circumradius)
newFO.setAttribute('r2', inradius)
newFO.setAttribute('starRadiusMultiplier', RadiusMultiplier)
let polyPoints = "";
let polyPoints = ''
for (let s = 0; point >= s; s++) {
let angle = 2.0 * Math.PI * (s / point);
if (orient === "point") {
angle -= Math.PI / 2;
} else if (orient === "edge") {
angle = angle + Math.PI / point - Math.PI / 2;
let angle = 2.0 * Math.PI * (s / point)
if (orient === 'point') {
angle -= Math.PI / 2
} else if (orient === 'edge') {
angle = angle + Math.PI / point - Math.PI / 2
}
x = circumradius * Math.cos(angle) + cx;
y = circumradius * Math.sin(angle) + cy;
x = circumradius * Math.cos(angle) + cx
y = circumradius * Math.sin(angle) + cy
polyPoints += x + "," + y + " ";
polyPoints += x + ',' + y + ' '
if (!isNaN(inradius)) {
angle = 2.0 * Math.PI * (s / point) + Math.PI / point;
if (orient === "point") {
angle -= Math.PI / 2;
} else if (orient === "edge") {
angle = angle + Math.PI / point - Math.PI / 2;
angle = 2.0 * Math.PI * (s / point) + Math.PI / point
if (orient === 'point') {
angle -= Math.PI / 2
} else if (orient === 'edge') {
angle = angle + Math.PI / point - Math.PI / 2
}
angle += radialshift;
angle += radialshift
x = inradius * Math.cos(angle) + cx;
y = inradius * Math.sin(angle) + cy;
x = inradius * Math.cos(angle) + cx
y = inradius * Math.sin(angle) + cy
polyPoints += x + "," + y + " ";
polyPoints += x + ',' + y + ' '
}
}
newFO.setAttribute("points", polyPoints);
newFO.setAttribute("fill", fill);
newFO.setAttribute("stroke", strokecolor);
newFO.setAttribute("stroke-width", strokeWidth);
/* const shape = */ newFO.getAttribute("shape");
newFO.setAttribute('points', polyPoints)
newFO.setAttribute('fill', fill)
newFO.setAttribute('stroke', strokecolor)
newFO.setAttribute('stroke-width', strokeWidth)
/* const shape = */ newFO.getAttribute('shape')
return {
started: true
};
}
}
if (svgCanvas.getMode() === "polygon") {
const cx = Number(newFO.getAttribute("cx"));
const cy = Number(newFO.getAttribute("cy"));
const sides = Number(newFO.getAttribute("sides"));
if (svgCanvas.getMode() === 'polygon') {
const cx = Number(newFO.getAttribute('cx'))
const cy = Number(newFO.getAttribute('cy'))
const sides = Number(newFO.getAttribute('sides'))
// const orient = newFO.getAttribute('orient');
const fill = newFO.getAttribute("fill");
const strokecolor = newFO.getAttribute("strokecolor");
const strokeWidth = Number(newFO.getAttribute("strokeWidth"));
const fill = newFO.getAttribute('fill')
const strokecolor = newFO.getAttribute('strokecolor')
const strokeWidth = Number(newFO.getAttribute('strokeWidth'))
let x = opts.mouse_x;
let y = opts.mouse_y;
let x = opts.mouse_x
let y = opts.mouse_y
const edg =
Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) / 1.5;
newFO.setAttribute("edge", edg);
Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) / 1.5
newFO.setAttribute('edge', edg)
const inradius = (edg / 2) * cot(Math.PI / sides);
const circumradius = inradius * sec(Math.PI / sides);
let points = "";
const inradius = (edg / 2) * cot(Math.PI / sides)
const circumradius = inradius * sec(Math.PI / sides)
let points = ''
for (let s = 0; sides >= s; s++) {
const angle = (2.0 * Math.PI * s) / sides;
x = circumradius * Math.cos(angle) + cx;
y = circumradius * Math.sin(angle) + cy;
const angle = (2.0 * Math.PI * s) / sides
x = circumradius * Math.cos(angle) + cx
y = circumradius * Math.sin(angle) + cy
points += x + "," + y + " ";
points += x + ',' + y + ' '
}
// const poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttribute("points", points);
newFO.setAttribute("fill", fill);
newFO.setAttribute("stroke", strokecolor);
newFO.setAttribute("stroke-width", strokeWidth);
newFO.setAttribute('points', points)
newFO.setAttribute('fill', fill)
newFO.setAttribute('stroke', strokecolor)
newFO.setAttribute('stroke-width', strokeWidth)
return {
started: true
};
}
}
return undefined;
return undefined
},
mouseUp() {
if (svgCanvas.getMode() === "star") {
const r = newFO.getAttribute("r");
mouseUp () {
if (svgCanvas.getMode() === 'star') {
const r = newFO.getAttribute('r')
return {
keep: r !== "0",
keep: r !== '0',
element: newFO
};
}
}
if (svgCanvas.getMode() === "polygon") {
const edge = newFO.getAttribute("edge");
const keep = edge !== "0";
if (svgCanvas.getMode() === 'polygon') {
const edge = newFO.getAttribute('edge')
const keep = edge !== '0'
// svgCanvas.addToSelection([newFO], true);
return {
keep,
element: newFO
};
}
}
return undefined;
return undefined
},
selectedChanged(opts) {
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
selElems = opts.elems
let i = selElems.length;
let i = selElems.length
while (i--) {
const elem = selElems[i];
if (elem && elem.getAttribute("shape") === "star") {
const elem = selElems[i]
if (elem && elem.getAttribute('shape') === 'star') {
if (opts.selectedElement && !opts.multiselected) {
$id("starNumPoints").value = elem.getAttribute("point");
$id("radialShift").value = elem.getAttribute("radialshift");
showPanel(true, "star");
$id('starNumPoints').value = elem.getAttribute('point')
$id('radialShift').value = elem.getAttribute('radialshift')
showPanel(true, 'star')
} else {
showPanel(false, "star");
showPanel(false, 'star')
}
} else if (elem && elem.getAttribute("shape") === "regularPoly") {
} else if (elem && elem.getAttribute('shape') === 'regularPoly') {
if (opts.selectedElement && !opts.multiselected) {
$id("polySides").value = elem.getAttribute("sides");
showPanel(true, "polygon");
$id('polySides').value = elem.getAttribute('sides')
showPanel(true, 'polygon')
} else {
showPanel(false, "polygon");
showPanel(false, 'polygon')
}
} else {
showPanel(false, "star");
showPanel(false, "polygon");
showPanel(false, 'star')
showPanel(false, 'polygon')
}
}
}
};
}
}
};
}

View File

@@ -27,4 +27,4 @@ export default {
label: 'sides'
}
]
};
}

View File

@@ -27,4 +27,4 @@ export default {
label: 'côtés'
}
]
};
}

View File

@@ -27,4 +27,4 @@ export default {
label: '边数'
}
]
};
}

View File

@@ -6,37 +6,36 @@
* @copyright 2010 Christian Tzurcanu, 2010 Alexis Deveria
*
*/
const name = "shapes";
const name = 'shapes'
const loadExtensionTranslation = async function (svgEditor) {
let translationModule;
const lang = svgEditor.configObj.pref('lang');
let translationModule
const lang = svgEditor.configObj.pref('lang')
try {
// eslint-disable-next-line no-unsanitized/method
translationModule = await import(`./locale/${lang}.js`);
translationModule = await import(`./locale/${lang}.js`)
} catch (_error) {
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`);
translationModule = await import(`./locale/en.js`);
console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
translationModule = await import('./locale/en.js')
}
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default);
};
svgEditor.i18next.addResourceBundle(lang, name, translationModule.default)
}
export default {
name,
async init () {
const svgEditor = this;
const canv = svgEditor.svgCanvas;
const { $id } = canv;
const svgroot = canv.getSvgRoot();
let lastBBox = {};
await loadExtensionTranslation(svgEditor);
const svgEditor = this
const canv = svgEditor.svgCanvas
const { $id } = canv
const svgroot = canv.getSvgRoot()
let lastBBox = {}
await loadExtensionTranslation(svgEditor)
const modeId = 'shapelib';
const startClientPos = {};
const modeId = 'shapelib'
const startClientPos = {}
let curShape;
let startX;
let startY;
let curShape
let startX
let startY
return {
callback () {
@@ -44,28 +43,28 @@ export default {
const buttonTemplate = `
<se-explorerbutton id="tool_shapelib" title="${svgEditor.i18next.t(`${name}:buttons.0.title`)}" lib="./extensions/ext-shapes/shapelib/"
src="shapelib.svg"></se-explorerbutton>
`;
canv.insertChildAtIndex($id('tools_left'), buttonTemplate, 9);
$id('tool_shapelib').addEventListener("click", () => {
if (this.leftPanel.updateLeftPanel("tool_shapelib")) {
canv.setMode(modeId);
`
canv.insertChildAtIndex($id('tools_left'), buttonTemplate, 9)
$id('tool_shapelib').addEventListener('click', () => {
if (this.leftPanel.updateLeftPanel('tool_shapelib')) {
canv.setMode(modeId)
}
});
})
}
},
mouseDown (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return undefined; }
const mode = canv.getMode()
if (mode !== modeId) { return undefined }
const currentD = document.getElementById('tool_shapelib').dataset.draw;
startX = opts.start_x;
const x = startX;
startY = opts.start_y;
const y = startY;
const curStyle = canv.getStyle();
const currentD = document.getElementById('tool_shapelib').dataset.draw
startX = opts.start_x
const x = startX
startY = opts.start_y
const y = startY
const curStyle = canv.getStyle()
startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY;
startClientPos.x = opts.event.clientX
startClientPos.y = opts.event.clientY
curShape = canv.addSVGElemensFromJson({
element: 'path',
@@ -76,87 +75,87 @@ export default {
opacity: curStyle.opacity / 2,
style: 'pointer-events:none'
}
});
})
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')')
canv.recalculateDimensions(curShape);
canv.recalculateDimensions(curShape)
lastBBox = curShape.getBBox();
lastBBox = curShape.getBBox()
return {
started: true
};
}
},
mouseMove (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
const mode = canv.getMode()
if (mode !== modeId) { return }
const zoom = canv.getZoom();
const evt = opts.event;
const zoom = canv.getZoom()
const evt = opts.event
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const x = opts.mouse_x / zoom
const y = opts.mouse_y / zoom
const tlist = curShape.transform.baseVal;
const box = curShape.getBBox();
const left = box.x; const top = box.y;
const tlist = curShape.transform.baseVal
const box = curShape.getBBox()
const left = box.x; const top = box.y
const newbox = {
x: Math.min(startX, x),
y: Math.min(startY, y),
width: Math.abs(x - startX),
height: Math.abs(y - startY)
};
}
let sx = (newbox.width / lastBBox.width) || 1;
let sy = (newbox.height / lastBBox.height) || 1;
let sx = (newbox.width / lastBBox.width) || 1
let sy = (newbox.height / lastBBox.height) || 1
// Not perfect, but mostly works...
let tx = 0;
let tx = 0
if (x < startX) {
tx = lastBBox.width;
tx = lastBBox.width
}
let ty = 0;
let ty = 0
if (y < startY) {
ty = lastBBox.height;
ty = lastBBox.height
}
// update the transform list with translate,scale,translate
const translateOrigin = svgroot.createSVGTransform();
const scale = svgroot.createSVGTransform();
const translateBack = svgroot.createSVGTransform();
const translateOrigin = svgroot.createSVGTransform()
const scale = svgroot.createSVGTransform()
const translateBack = svgroot.createSVGTransform()
translateOrigin.setTranslate(-(left + tx), -(top + ty));
translateOrigin.setTranslate(-(left + tx), -(top + ty))
if (!evt.shiftKey) {
const max = Math.min(Math.abs(sx), Math.abs(sy));
const max = Math.min(Math.abs(sx), Math.abs(sy))
sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1);
sx = max * (sx < 0 ? -1 : 1)
sy = max * (sy < 0 ? -1 : 1)
}
scale.setScale(sx, sy);
scale.setScale(sx, sy)
translateBack.setTranslate(left + tx, top + ty);
tlist.appendItem(translateBack);
tlist.appendItem(scale);
tlist.appendItem(translateOrigin);
translateBack.setTranslate(left + tx, top + ty)
tlist.appendItem(translateBack)
tlist.appendItem(scale)
tlist.appendItem(translateOrigin)
canv.recalculateDimensions(curShape);
canv.recalculateDimensions(curShape)
lastBBox = curShape.getBBox();
lastBBox = curShape.getBBox()
},
mouseUp (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return undefined; }
const mode = canv.getMode()
if (mode !== modeId) { return undefined }
const keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
const keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y)
return {
keep: keepObject,
element: curShape,
started: false
};
}
}
};
}
}
};
}

View File

@@ -21,4 +21,4 @@ export default {
title: 'Shape library'
}
]
};
}

View File

@@ -21,4 +21,4 @@ export default {
title: "Bibliothèque d'images"
}
]
};
}

View File

@@ -21,4 +21,4 @@ export default {
title: '图元库'
}
]
};
}

View File

@@ -18,23 +18,23 @@
* @todo We might provide control of storage settings through the UI besides the
* initial (or URL-forced) dialog. *
*/
import './storageDialog.js';
import './storageDialog.js'
/**
* Expire the storage cookie.
* @returns {void}
*/
const removeStoragePrefCookie = () => {
expireCookie('svgeditstore');
};
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';
};
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'
}
/**
* Replace `storagePrompt` parameter within URL.
@@ -43,22 +43,22 @@ const expireCookie = (cookie) => {
* @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
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 || ''));
});
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''))
})
} else {
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
loc.href += (loc.href.includes('?') ? '&' : '?') + val
}
};
}
export default {
name: 'storage',
init () {
const svgEditor = this;
const { svgCanvas, storage } = svgEditor;
const svgEditor = this
const { svgCanvas, storage } = 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
@@ -77,50 +77,50 @@ export default {
// the "noStorageOnLoad" config setting to true in svgedit-config-*.js.
noStorageOnLoad,
forceStorage
} = svgEditor.configObj.curConfig;
} = svgEditor.configObj.curConfig
// storageDialog added to DOM
const storageBox = document.createElement('se-storage-dialog');
storageBox.setAttribute('id', 'se-storage-dialog');
svgEditor.$container.append(storageBox);
storageBox.init(svgEditor.i18next);
const storageBox = document.createElement('se-storage-dialog')
storageBox.setAttribute('id', 'se-storage-dialog')
svgEditor.$container.append(storageBox)
storageBox.init(svgEditor.i18next)
// manage the change in the storageDialog
storageBox.addEventListener('change', (e) => {
storageBox.setAttribute('dialog', 'close');
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';
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;
replaceStoragePrompt()
return
}
} else {
removeStoragePrefCookie();
removeStoragePrefCookie()
if (svgEditor.configObj.curConfig.emptyStorageOnDecline && e?.detail?.checkbox) {
this.setSvgContentStorage('');
this.setSvgContentStorage('')
Object.keys(svgEditor.curPrefs).forEach((name) => {
name = 'svg-edit-' + name;
name = 'svg-edit-' + name
if (svgEditor.storage) {
svgEditor.storage.removeItem(name);
svgEditor.storage.removeItem(name)
}
expireCookie(name);
});
expireCookie(name)
})
}
if (e?.detail?.select && e?.detail?.checkbox) {
replaceStoragePrompt('false');
return;
replaceStoragePrompt('false')
return
}
}
} else if (e?.detail?.trigger === 'cancel') {
removeStoragePrefCookie();
removeStoragePrefCookie()
}
setupBeforeUnloadListener();
svgEditor.storagePromptState = 'closed';
svgEditor.updateCanvas(true);
});
setupBeforeUnloadListener()
svgEditor.storagePromptState = 'closed'
svgEditor.updateCanvas(true)
})
/**
* Sets SVG content as a string with "svgedit-" and the current
@@ -130,11 +130,11 @@ export default {
*/
function setSvgContentStorage (val) {
if (storage) {
const name = 'svgedit-' + svgEditor.configObj.curConfig.canvasName;
const name = 'svgedit-' + svgEditor.configObj.curConfig.canvasName
if (!val) {
storage.removeItem(name);
storage.removeItem(name)
} else {
storage.setItem(name, val);
storage.setItem(name, val)
}
}
}
@@ -152,46 +152,46 @@ export default {
window.addEventListener('beforeunload', function () {
// Don't save anything unless the user opted in to storage
if (!(/(?:^|;\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/).test(document.cookie)) {
return;
return
}
if ((/(?:^|;\s*)svgeditstore=prefsAndContent/).test(document.cookie)) {
setSvgContentStorage(svgCanvas.getSvgString());
setSvgContentStorage(svgCanvas.getSvgString())
}
svgEditor.setConfig({ no_save_warning: true }); // No need for explicit saving at all once storage is on
svgEditor.setConfig({ no_save_warning: true }) // No need for explicit saving at all once storage is on
// svgEditor.showSaveWarning = false;
const { curPrefs } = svgEditor.configObj;
const { curPrefs } = svgEditor.configObj
Object.entries(curPrefs).forEach(([ key, val ]) => {
const store = (val !== undefined);
key = 'svg-edit-' + key;
Object.entries(curPrefs).forEach(([key, val]) => {
const store = (val !== undefined)
key = 'svg-edit-' + key
if (!store) {
return;
return
}
if (storage) {
storage.setItem(key, val);
storage.setItem(key, val)
} else if (window.widget) {
window.widget.setPreferenceForKey(val, key);
window.widget.setPreferenceForKey(val, key)
} else {
val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
val = encodeURIComponent(val)
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
}
});
});
})
})
}
let loaded = false;
let loaded = false
return {
name: 'storage',
callback () {
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt')
// No need to run this one-time dialog again just because the user
// changes the language
if (loaded) {
return;
return
}
loaded = true;
loaded = true
// Note that the following can load even if "noStorageOnLoad" is
// set to false; to avoid any chance of storage, avoid this
@@ -213,17 +213,17 @@ export default {
)
// ...then show the storage prompt.
)) {
const options = Boolean(storage);
const options = Boolean(storage)
// Open select-with-checkbox dialog
// From svg-editor.js
svgEditor.storagePromptState = 'waiting';
const $storageDialog = document.getElementById('se-storage-dialog');
$storageDialog.setAttribute('dialog', 'open');
$storageDialog.setAttribute('storage', options);
svgEditor.storagePromptState = 'waiting'
const $storageDialog = document.getElementById('se-storage-dialog')
$storageDialog.setAttribute('dialog', 'open')
$storageDialog.setAttribute('storage', options)
} else if (!noStorageOnLoad || forceStorage) {
setupBeforeUnloadListener();
setupBeforeUnloadListener()
}
}
};
}
}
};
}

View File

@@ -11,4 +11,4 @@ export default {
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
};
}

View File

@@ -11,4 +11,4 @@ export default {
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
};
}

View File

@@ -11,4 +11,4 @@ export default {
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: "Si vous choisissez de désactiver le stockage en mémorisant le choix, l'URL va changer afin que la question ne vous soit plus reposée."
};
}

View File

@@ -8,4 +8,4 @@ export default {
storageNoPrefs: '本地不保存配置参数',
rememberLabel: '记住选择?',
rememberTooltip: '如果您勾选记住选择,将不再弹出本窗口.'
};
}

View File

@@ -1,8 +1,7 @@
import storageDialogHTML from './storageDialog.html';
import storageDialogHTML from './storageDialog.html'
const template = document.createElement('template');
// eslint-disable-next-line no-unsanitized/property
template.innerHTML = storageDialogHTML;
const template = document.createElement('template')
template.innerHTML = storageDialogHTML
/**
* @class SeStorageDialog
*/
@@ -11,39 +10,42 @@ export class SeStorageDialog extends HTMLElement {
* @function constructor
*/
constructor () {
super();
super()
// create the shadowDom and insert the template
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._shadowRoot.append(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');
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._shadowRoot.append(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 init
* @param {any} name
* @returns {void}
*/
init (i18next) {
this.setAttribute('common-ok', i18next.t('common.ok'));
this.setAttribute('common-cancel', i18next.t('common.cancel'));
this.setAttribute('notify-editor_pref_msg', i18next.t('notification.editorPreferencesMsg'));
this.setAttribute('properties-prefs_and_content', i18next.t('properties.prefs_and_content'));
this.setAttribute('properties-prefs_only', i18next.t('properties.prefs_only'));
this.setAttribute('properties-no_prefs_or_content', i18next.t('properties.no_prefs_or_content'));
this.setAttribute('tools-remember_this_choice', i18next.t('tools.remember_this_choice'));
this.setAttribute('tools-remember_this_choice_title', i18next.t('tools.remember_this_choice_title'));
this.setAttribute('common-ok', i18next.t('common.ok'))
this.setAttribute('common-cancel', i18next.t('common.cancel'))
this.setAttribute('notify-editor_pref_msg', i18next.t('notification.editorPreferencesMsg'))
this.setAttribute('properties-prefs_and_content', i18next.t('properties.prefs_and_content'))
this.setAttribute('properties-prefs_only', i18next.t('properties.prefs_only'))
this.setAttribute('properties-no_prefs_or_content', i18next.t('properties.no_prefs_or_content'))
this.setAttribute('tools-remember_this_choice', i18next.t('tools.remember_this_choice'))
this.setAttribute('tools-remember_this_choice_title', i18next.t('tools.remember_this_choice_title'))
}
/**
* @function observedAttributes
* @returns {any} observed
*/
static get observedAttributes () {
return [ 'dialog', 'storage', 'common-ok', 'common-cancel', 'notify-editor_pref_msg', 'properties-prefs_and_content', 'tools-remember_this_choice', 'tools-remember_this_choice_title', 'properties-prefs_only', 'properties-no_prefs_or_content' ];
return ['dialog', 'storage', 'common-ok', 'common-cancel', 'notify-editor_pref_msg', 'properties-prefs_and_content', 'tools-remember_this_choice', 'tools-remember_this_choice_title', 'properties-prefs_only', 'properties-no_prefs_or_content']
}
/**
* @function attributeChangedCallback
* @param {string} name
@@ -52,87 +54,93 @@ export class SeStorageDialog extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
let node;
let node
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;
case 'common-ok':
this.$okBtn.textContent = newValue;
break;
case 'common-cancel':
this.$cancelBtn.textContent = newValue;
break;
case 'notify-editor_pref_msg':
node = this._shadowRoot.querySelector('#notificationNote');
node.textContent = newValue;
break;
case 'properties-prefs_and_content':
node = this._shadowRoot.querySelector('#prefsAndContent');
node.textContent = newValue;
break;
case 'properties-prefs_only':
node = this._shadowRoot.querySelector('#prefsOnly');
node.textContent = newValue;
break;
case 'properties-no_prefs_or_content':
node = this._shadowRoot.querySelector('#noPrefsOrContent');
node.textContent = newValue;
break;
case 'tools-remember_this_choice':
node = this._shadowRoot.querySelector('#se-remember-title');
node.prepend(newValue);
break;
case 'tools-remember_this_choice_title':
node = this._shadowRoot.querySelector('#se-remember-title');
node.setAttribute('title', newValue);
break;
default:
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
case 'common-ok':
this.$okBtn.textContent = newValue
break
case 'common-cancel':
this.$cancelBtn.textContent = newValue
break
case 'notify-editor_pref_msg':
node = this._shadowRoot.querySelector('#notificationNote')
node.textContent = newValue
break
case 'properties-prefs_and_content':
node = this._shadowRoot.querySelector('#prefsAndContent')
node.textContent = newValue
break
case 'properties-prefs_only':
node = this._shadowRoot.querySelector('#prefsOnly')
node.textContent = newValue
break
case 'properties-no_prefs_or_content':
node = this._shadowRoot.querySelector('#noPrefsOrContent')
node.textContent = newValue
break
case 'tools-remember_this_choice':
node = this._shadowRoot.querySelector('#se-remember-title')
node.prepend(newValue)
break
case 'tools-remember_this_choice_title':
node = this._shadowRoot.querySelector('#se-remember-title')
node.setAttribute('title', newValue)
break
default:
// super.attributeChangedCallback(name, oldValue, newValue);
break;
break
}
}
/**
* @function get
* @returns {any}
*/
get dialog () {
return this.getAttribute('dialog');
return this.getAttribute('dialog')
}
/**
* @function set
* @returns {void}
*/
set dialog (value) {
this.setAttribute('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'));
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.
@@ -141,15 +149,15 @@ export class SeStorageDialog extends HTMLElement {
*/
setSvgContentStorage (val) {
if (this.storage) {
const name = 'svgedit-' + this.configObj.curConfig.canvasName;
const name = 'svgedit-' + this.configObj.curConfig.canvasName
if (!val) {
this.storage.removeItem(name);
this.storage.removeItem(name)
} else {
this.storage.setItem(name, val);
this.storage.setItem(name, val)
}
}
}
}
// Register
customElements.define('se-storage-dialog', SeStorageDialog);
customElements.define('se-storage-dialog', SeStorageDialog)

View File

@@ -30,26 +30,26 @@
<!-- If you do not wish to add extensions by URL, you can add calls
within the following file to svgEditor.setConfig -->
<script type="module">
import Editor from './Editor.js';
/* for available options see the file `docs/tutorials/ConfigOptions.md */
const svgEditor = new Editor(document.getElementById('container'));
svgEditor.init();
svgEditor.setConfig({
import Editor from './Editor.js'
/* for available options see the file `docs/tutorials/ConfigOptions.md */
const svgEditor = new Editor(document.getElementById('container'))
svgEditor.init()
svgEditor.setConfig({
allowInitialUserOverride: true,
extensions: [],
noDefaultExtensions: false,
userExtensions: [/* '../ext-helloworld/ext-helloworld.js' */]
});
// Variable XDOMAIN below is created by Rollup for the Xdomain build (see rollup.config.js)
/* globals XDOMAIN */
try { // try clause to avoid js to complain if XDOMAIN undefined
})
// Variable XDOMAIN below is created by Rollup for the Xdomain build (see rollup.config.js)
/* globals XDOMAIN */
try { // try clause to avoid js to complain if XDOMAIN undefined
if (XDOMAIN) {
svgEditor.setConfig({
canvasName: 'xdomain', // Namespace this
allowedOrigins: [ '*' ]
});
console.info('xdomain config activated');
}
} catch (error) {/* empty fn */ }
})
console.info('xdomain config activated')
}
} catch (error) { /* empty fn */ }
</script>
</html>

Some files were not shown because too many files have changed in this diff Show More