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

@@ -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)