add MainMenu class

master
JFH 2021-03-14 21:44:15 +01:00
parent 57e7fe316b
commit c19c53565d
5 changed files with 326 additions and 366 deletions

View File

@ -34,6 +34,7 @@ import LeftPanel from './panels/LeftPanel.js';
import TopPanel from './panels/TopPanel.js';
import BottomPanel from './panels/BottomPanel.js';
import LayersPanel from './panels/LayersPanel.js';
import MainMenu from './MainMenu.js';
const {$id, $qa, isNullish, encode64, decode64, blankPageObjectURL} = SvgCanvas;
@ -139,6 +140,7 @@ class Editor extends EditorStartup {
this.bottomPanel = new BottomPanel(this);
this.topPanel = new TopPanel(this);
this.layersPanel = new LayersPanel(this);
this.mainMenu = new MainMenu(this);
}
/**
*
@ -988,170 +990,6 @@ class Editor extends EditorStartup {
this.topPanel.updateContextPanel();
}
/**
* @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument
* @returns {void}
*/
async clickClear () {
const [x, y] = this.configObj.curConfig.dimensions;
const ok = await seConfirm(this.uiStrings.notification.QwantToClear);
if (ok === 'Cancel') {
return;
}
this.leftPanel.clickSelect();
this.svgCanvas.clear();
this.svgCanvas.setResolution(x, y);
this.updateCanvas(true);
this.zoomImage();
this.layersPanel.populateLayers();
this.topPanel.updateContextPanel();
this.svgCanvas.runExtensions('onNewDocument');
}
/**
*
* @returns {void}
*/
clickSave () {
// In the future, more options can be provided here
const saveOpts = {
images: this.configObj.pref('img_save'),
round_digits: 6
};
this.svgCanvas.save(saveOpts);
}
/**
*
* @param e
* @returns {Promise<void>} Resolves to `undefined`
*/
async clickExport (e) {
if (e?.detail?.trigger !== 'ok' || e?.detail?.imgType === undefined) {
return;
}
const imgType = e?.detail?.imgType;
const quality = (e?.detail?.quality) ? (e?.detail?.quality / 100) : 1;
// Open placeholder window (prevents popup)
let exportWindowName;
/**
*
* @returns {void}
*/
const openExportWindow = () => {
const {loadingImage} = this.uiStrings.notification;
if (this.configObj.curConfig.exportWindowType === 'new') {
this.exportWindowCt++;
}
this.exportWindowName = this.configObj.curConfig.canvasName + this.exportWindowCt;
let popHTML, popURL;
if (this.loadingURL) {
popURL = this.loadingURL;
} else {
popHTML = `<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<title>${loadingImage}</title>
</head>
<body><h1>${loadingImage}</h1></body>
<html>`;
if (typeof URL !== 'undefined' && URL.createObjectURL) {
const blob = new Blob([popHTML], {type: 'text/html'});
popURL = URL.createObjectURL(blob);
} else {
popURL = 'data:text/html;base64;charset=utf-8,' + encode64(popHTML);
}
this.loadingURL = popURL;
}
this.exportWindow = window.open(popURL, this.exportWindowName);
};
const chrome = isChrome();
if (imgType === 'PDF') {
if (!this.customExportPDF && !chrome) {
openExportWindow();
}
this.svgCanvas.exportPDF(exportWindowName);
} else {
if (!this.customExportImage) {
openExportWindow();
}
/* const results = */ await this.svgCanvas.rasterExport(imgType, quality, this.exportWindowName);
}
}
/**
* By default, this.svgCanvas.open() is a no-op. It is up to an extension
* mechanism (opera widget, etc.) to call `setCustomHandlers()` which
* will make it do something.
* @returns {void}
*/
clickOpen () {
this.svgCanvas.open();
}
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
clickImport () {
/* empty fn */
}
/**
*
* @returns {void}
*/
showDocProperties () {
if (this.docprops) { return; }
this.docprops = true;
const $imgDialog = document.getElementById('se-img-prop');
// update resolution option with actual resolution
const resolution = this.svgCanvas.getResolution();
if (this.configObj.curConfig.baseUnit !== 'px') {
resolution.w = convertUnit(resolution.w) + this.configObj.curConfig.baseUnit;
resolution.h = convertUnit(resolution.h) + this.configObj.curConfig.baseUnit;
}
$imgDialog.setAttribute('save', this.configObj.pref('img_save'));
$imgDialog.setAttribute('width', resolution.w);
$imgDialog.setAttribute('height', resolution.h);
$imgDialog.setAttribute('title', this.svgCanvas.getDocumentTitle());
$imgDialog.setAttribute('dialog', 'open');
}
/**
*
* @returns {void}
*/
showPreferences () {
if (this.configObj.preferences) { return; }
this.configObj.preferences = true;
const $editDialog = document.getElementById('se-edit-prefs');
// $('#main_menu').hide();
// Update background color with current one
const canvasBg = this.configObj.curPrefs.bkgd_color;
const url = this.configObj.pref('bkgd_url');
if (url) {
$editDialog.setAttribute('bgurl', url);
}
$editDialog.setAttribute('gridsnappingon', this.configObj.curConfig.gridSnapping);
$editDialog.setAttribute('gridsnappingstep', this.configObj.curConfig.snappingStep);
$editDialog.setAttribute('gridcolor', this.configObj.curConfig.gridColor);
$editDialog.setAttribute('canvasbg', canvasBg);
$editDialog.setAttribute('dialog', 'open');
}
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
openHomePage () {
window.open(homePage, '_blank');
}
/**
*
* @returns {void}
@ -1239,37 +1077,6 @@ class Editor extends EditorStartup {
return true;
}
/**
* Save user preferences based on current values in the UI.
* @param {Event} e
* @function module:SVGthis.savePreferences
* @returns {Promise<void>}
*/
async savePreferences (e) {
const {lang, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail;
// Set background
this.setBackground(bgcolor, bgurl);
// set language
if (lang && lang !== this.configObj.pref('lang')) {
const {langParam, langData} = await this.putLocale(lang, this.goodLangs);
await this.setLang(langParam, langData);
}
// set grid setting
this.configObj.curConfig.gridSnapping = gridsnappingon;
this.configObj.curConfig.snappingStep = gridsnappingstep;
this.configObj.curConfig.gridColor = gridcolor;
this.configObj.curConfig.showRulers = showrulers;
$('#rulers').toggle(this.configObj.curConfig.showRulers);
if (this.configObj.curConfig.showRulers) { this.rulers.updateRulers(); }
this.configObj.curConfig.baseUnit = baseunit;
this.svgCanvas.setConfig(this.configObj.curConfig);
this.updateCanvas();
this.hidePreferences();
}
/**
* @param {Event} e
* @returns {void} Resolves to `undefined`

View File

@ -110,6 +110,7 @@ class EditorStartup {
this.bottomPanel.init();
this.topPanel.init();
this.layersPanel.init();
this.mainMenu.init();
const {undoMgr} = this.svgCanvas;
this.workarea = document.getElementById('workarea');
@ -317,79 +318,6 @@ class EditorStartup {
this.setPanning = (active) => {
this.svgCanvas.spaceKey = keypan = active;
};
// TODO: main menu move to webcomponent. so no need now
/*
const button = $('#main_icon');
const overlay = $('#main_icon span');
const list = $('#main_menu');
let onButton = false;
let height = 0;
let jsHover = true;
let setClick = false;
$(window).mouseup(function (evt) {
if (!onButton) {
button.removeClass('buttondown');
// do not hide if it was the file input as that input needs to be visible
// for its change event to fire
if (evt.target.tagName !== 'INPUT') {
list.fadeOut(200);
} else if (!setClick) {
setClick = true;
$(evt.target).click(() => {
list.css('margin-left', '-9999px').show();
});
}
}
onButton = false;
}).mousedown(function (evt) {
// $('.contextMenu').hide();
const islib = $(evt.target).closest('.contextMenu').length;
if (!islib) {
$('.contextMenu').fadeOut(250);
}
});
overlay.bind('mousedown', () => {
if (!button.hasClass('buttondown')) {
// Margin must be reset in case it was changed before;
list.css('margin-left', 0).show();
if (!height) {
height = list.height();
}
// Using custom animation as slideDown has annoying 'bounce effect'
list.css('height', 0).animate({
height
}, 200);
onButton = true;
} else {
list.fadeOut(200);
}
button.toggleClass('buttondown buttonup');
}).hover(() => {
onButton = true;
}).mouseout(() => {
onButton = false;
});
const listItems = $('#main_menu li');
// Check if JS method of hovering needs to be used (Webkit bug)
listItems.mouseover(function () {
jsHover = ($(this).css('background-color') === 'rgba(0, 0, 0, 0)');
listItems.unbind('mouseover');
if (jsHover) {
listItems.mouseover(() => {
this.style.backgroundColor = '#FFC';
}).mouseout((evt) => {
evt.currentTarget.style.backgroundColor = 'transparent';
return true;
});
}
}); */
// Unfocus text input when this.workarea is mousedowned.
let inp;
/**
*
@ -455,51 +383,6 @@ class EditorStartup {
// Prevent browser from erroneously repopulating fields
$('input,select').attr('autocomplete', 'off');
/**
* Associate all button actions as well as non-button keyboard shortcuts.
*/
$id('tool_clear').addEventListener('click', this.clickClear.bind(this));
$id('tool_open').addEventListener('click', (e) => {
e.preventDefault();
this.clickOpen();
window.dispatchEvent(new CustomEvent('openImage'));
});
$id('tool_import').addEventListener('click', (e) => {
this.clickImport();
window.dispatchEvent(new CustomEvent('importImages'));
});
$id('tool_save').addEventListener('click', function (e) {
const $editorDialog = document.getElementById('se-svg-editor-dialog');
const editingsource = $editorDialog.getAttribute('dialog') === 'open';
if (editingsource) {
this.saveSourceEditor();
} else {
this.clickSave();
}
}.bind(this));
// this.clickExport.bind(this)
$id('tool_export').addEventListener('click', function (e) {
document.getElementById('se-export-dialog').setAttribute('dialog', 'open');
});
$id('se-export-dialog').addEventListener('change', this.clickExport.bind(this));
$id('tool_docprops').addEventListener('click', this.showDocProperties.bind(this));
$id('tool_editor_prefs').addEventListener('click', this.showPreferences.bind(this));
$id('tool_editor_homepage').addEventListener('click', this.openHomePage.bind(this));
$id('se-img-prop').addEventListener('change', function (e) {
if (e.detail.dialog === 'closed') {
this.hideDocProperties();
} else {
this.saveDocProperties(e);
}
}.bind(this));
$id('se-edit-prefs').addEventListener('change', function (e) {
if (e.detail.dialog === 'closed') {
this.hidePreferences();
} else {
this.savePreferences(e);
}
}.bind(this));
$id('se-svg-editor-dialog').addEventListener('change', function (e) {
if (e?.detail?.copy === 'click') {
this.cancelOverlays(e);

323
src/editor/MainMenu.js Normal file
View File

@ -0,0 +1,323 @@
/* globals $ */
import SvgCanvas from "../svgcanvas/svgcanvas.js";
const { $id } = SvgCanvas;
/**
*
*/
class MainMenu {
/**
* @param {PlainObject} editor svgedit handler
*/
constructor(editor) {
this.editor = editor;
}
/**
* @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument
* @returns {void}
*/
async clickClear() {
const [x, y] = this.editor.configObj.curConfig.dimensions;
const ok = await seConfirm(this.editor.uiStrings.notification.QwantToClear);
if (ok === "Cancel") {
return;
}
this.editor.leftPanel.clickSelect();
this.editor.svgCanvas.clear();
this.editor.svgCanvas.setResolution(x, y);
this.editor.updateCanvas(true);
this.editor.zoomImage();
this.editor.layersPanel.populateLayers();
this.editor.topPanel.updateContextPanel();
this.editor.svgCanvas.runExtensions("onNewDocument");
}
/**
* Save user preferences based on current values in the UI.
* @param {Event} e
* @function module:SVGthis.savePreferences
* @returns {Promise<void>}
*/
async savePreferences (e) {
const {lang, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail;
// Set background
this.editor.setBackground(bgcolor, bgurl);
// set language
if (lang && lang !== this.configObj.pref('lang')) {
const {langParam, langData} = await this.editor.putLocale(lang, this.goodLangs);
await this.editor.svgCanvassetLang(langParam, langData);
}
// set grid setting
this.editor.configObj.curConfig.gridSnapping = gridsnappingon;
this.editor.configObj.curConfig.snappingStep = gridsnappingstep;
this.editor.configObj.curConfig.gridColor = gridcolor;
this.editor.configObj.curConfig.showRulers = showrulers;
$('#rulers').toggle(this.editor.configObj.curConfig.showRulers);
if (this.editor.configObj.curConfig.showRulers) { this.editor.rulers.updateRulers(); }
this.editor.configObj.curConfig.baseUnit = baseunit;
this.editor.svgCanvas.setConfig(this.configObj.curConfig);
this.editor.updateCanvas();
this.editor.hidePreferences();
}
/**
*
* @returns {void}
*/
clickSave() {
// In the future, more options can be provided here
const saveOpts = {
images: this.editor.configObj.pref("img_save"),
round_digits: 6
};
this.editor.svgCanvas.save(saveOpts);
}
/**
*
* @param e
* @returns {Promise<void>} Resolves to `undefined`
*/
async clickExport(e) {
if (e?.detail?.trigger !== "ok" || e?.detail?.imgType === undefined) {
return;
}
const imgType = e?.detail?.imgType;
const quality = e?.detail?.quality ? e?.detail?.quality / 100 : 1;
// Open placeholder window (prevents popup)
let exportWindowName;
/**
*
* @returns {void}
*/
const openExportWindow = () => {
const { loadingImage } = this.editor.uiStrings.notification;
if (this.editor.configObj.curConfig.exportWindowType === "new") {
this.editor.exportWindowCt++;
}
this.editor.exportWindowName =
this.editor.configObj.curConfig.canvasName + this.editor.exportWindowCt;
let popHTML, popURL;
if (this.editor.loadingURL) {
popURL = this.editor.loadingURL;
} else {
popHTML = `<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<title>${loadingImage}</title>
</head>
<body><h1>${loadingImage}</h1></body>
<html>`;
if (typeof URL !== "undefined" && URL.createObjectURL) {
const blob = new Blob([popHTML], { type: "text/html" });
popURL = URL.createObjectURL(blob);
} else {
popURL = "data:text/html;base64;charset=utf-8," + encode64(popHTML);
}
this.editor.loadingURL = popURL;
}
this.editor.exportWindow = window.open(popURL, this.editor.exportWindowName);
};
const chrome = isChrome();
if (imgType === "PDF") {
if (!this.editor.customExportPDF && !chrome) {
openExportWindow();
}
this.editor.svgCanvas.exportPDF(exportWindowName);
} else {
if (!this.editor.customExportImage) {
openExportWindow();
}
/* const results = */ await this.editor.svgCanvas.rasterExport(
imgType,
quality,
this.editor.exportWindowName
);
}
}
/**
* By default, this.editor.svgCanvas.open() is a no-op. It is up to an extension
* mechanism (opera widget, etc.) to call `setCustomHandlers()` which
* will make it do something.
* @returns {void}
*/
clickOpen() {
this.editor.svgCanvas.open();
}
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
clickImport() {
/* empty fn */
}
/**
*
* @returns {void}
*/
showDocProperties() {
if (this.editor.docprops) {
return;
}
this.editor.docprops = true;
const $imgDialog = document.getElementById("se-img-prop");
// update resolution option with actual resolution
const resolution = this.editor.svgCanvas.getResolution();
if (this.editor.configObj.curConfig.baseUnit !== "px") {
resolution.w =
convertUnit(resolution.w) + this.editor.configObj.curConfig.baseUnit;
resolution.h =
convertUnit(resolution.h) + this.editor.configObj.curConfig.baseUnit;
}
$imgDialog.setAttribute("save", this.editor.configObj.pref("img_save"));
$imgDialog.setAttribute("width", resolution.w);
$imgDialog.setAttribute("height", resolution.h);
$imgDialog.setAttribute("title", this.editor.svgCanvas.getDocumentTitle());
$imgDialog.setAttribute("dialog", "open");
}
/**
*
* @returns {void}
*/
showPreferences() {
if (this.editor.configObj.preferences) {
return;
}
this.editor.configObj.preferences = true;
const $editDialog = document.getElementById("se-edit-prefs");
// $('#main_menu').hide();
// Update background color with current one
const canvasBg = this.editor.configObj.curPrefs.bkgd_color;
const url = this.editor.configObj.pref("bkgd_url");
if (url) {
$editDialog.setAttribute("bgurl", url);
}
$editDialog.setAttribute(
"gridsnappingon",
this.editor.configObj.curConfig.gridSnapping
);
$editDialog.setAttribute(
"gridsnappingstep",
this.editor.configObj.curConfig.snappingStep
);
$editDialog.setAttribute("gridcolor", this.editor.configObj.curConfig.gridColor);
$editDialog.setAttribute("canvasbg", canvasBg);
$editDialog.setAttribute("dialog", "open");
}
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
openHomePage() {
window.open(homePage, "_blank");
}
/**
* @type {module}
*/
init() {
// add Top panel
const template = document.createElement("template");
template.innerHTML = `
<se-menu id="main_button" label="SVG-Edit" src="./images/logo.svg" alt="logo">
<!-- File-like buttons: New, Save, Source -->
<se-menu-item id="tool_clear" label="New Image" shortcut="N" src="./images/new.svg"></se-menu-item>
<se-menu-item id="tool_open" label="Open SVG" src="./images/open.svg"></se-menu-item>
<se-menu-item id="tool_save" label="Save Image" shortcut="S" src="./images/saveImg.svg"></se-menu-item>
<se-menu-item id="tool_import" label="Import Image" src="./images/importImg.svg"></se-menu-item>
<se-menu-item id="tool_export" label="Export" src="./images/export.svg"></se-menu-item>
<se-menu-item id="tool_imagelib" label="Image library" src="./images/library.svg"></se-menu-item>
<se-menu-item id="tool_docprops" label="Document Properties" shortcut="D" src="./images/docprop.svg">
</se-menu-item>
<se-menu-item id="tool_editor_prefs" label="Editor Preferences" src="./images/editPref.svg"></se-menu-item>
<se-menu-item id="tool_editor_homepage" label="SVG-Edit Home Page" src="./images/logo.svg">
</se-menu-item>
</se-menu>
`;
this.editor.$svgEditor.append(template.content.cloneNode(true));
// register action to main menu entries
/**
* Associate all button actions as well as non-button keyboard shortcuts.
*/
$id("tool_clear").addEventListener("click", this.clickClear.bind(this));
$id("tool_open").addEventListener("click", e => {
e.preventDefault();
this.clickOpen();
window.dispatchEvent(new CustomEvent("openImage"));
});
$id("tool_import").addEventListener("click", e => {
this.clickImport();
window.dispatchEvent(new CustomEvent("importImages"));
});
$id("tool_save").addEventListener(
"click",
function(e) {
const $editorDialog = document.getElementById("se-svg-editor-dialog");
const editingsource = $editorDialog.getAttribute("dialog") === "open";
if (editingsource) {
this.saveSourceEditor();
} else {
this.clickSave();
}
}.bind(this)
);
// this.clickExport.bind(this)
$id("tool_export").addEventListener("click", function(e) {
document
.getElementById("se-export-dialog")
.setAttribute("dialog", "open");
});
$id("se-export-dialog").addEventListener(
"change",
this.clickExport.bind(this)
);
$id("tool_docprops").addEventListener(
"click",
this.showDocProperties.bind(this)
);
$id("tool_editor_prefs").addEventListener(
"click",
this.showPreferences.bind(this)
);
$id("tool_editor_homepage").addEventListener(
"click",
this.openHomePage.bind(this)
);
$id("se-img-prop").addEventListener(
"change",
function(e) {
if (e.detail.dialog === "closed") {
this.hideDocProperties();
} else {
this.saveDocProperties(e);
}
}.bind(this)
);
$id("se-edit-prefs").addEventListener(
"change",
function(e) {
if (e.detail.dialog === "closed") {
this.hidePreferences();
} else {
this.savePreferences(e);
}
}.bind(this)
);
}
}
export default MainMenu;

View File

@ -29,21 +29,6 @@
<body>
<div id="svg_editor" role="main">
<se-menu id="main_button" label="SVG-Edit" src="./images/logo.svg" alt="logo">
<!-- File-like buttons: New, Save, Source -->
<se-menu-item id="tool_clear" label="New Image" shortcut="N" src="./images/new.svg"></se-menu-item>
<se-menu-item id="tool_open" label="Open SVG" src="./images/open.svg"></se-menu-item>
<se-menu-item id="tool_save" label="Save Image" shortcut="S" src="./images/saveImg.svg"></se-menu-item>
<se-menu-item id="tool_import" label="Import Image" src="./images/importImg.svg"></se-menu-item>
<se-menu-item id="tool_export" label="Export" src="./images/export.svg"></se-menu-item>
<se-menu-item id="tool_imagelib" label="Image library" src="./images/library.svg"></se-menu-item>
<se-menu-item id="tool_docprops" label="Document Properties" shortcut="D" src="./images/docprop.svg">
</se-menu-item>
<se-menu-item id="tool_editor_prefs" label="Editor Preferences" src="./images/editPref.svg"></se-menu-item>
<se-menu-item id="tool_editor_homepage" label="SVG-Edit Home Page" src="./images/logo.svg">
</se-menu-item>
</se-menu>
<div id="option_lists" class="dropdown"></div>
</div>
</body>

View File

@ -616,48 +616,10 @@ input[type=text] {
overflow: visible;
}
/**/
#option_lists ul {
display: none;
position: absolute;
height: auto;
z-index: 3;
margin: -10px;
list-style: none;
padding-left: 0;
}
#option_lists .optcols2 {
width: 70px;
margin-left: -15px;
}
#option_lists .optcols3 {
width: 90px;
margin-left: -31px;
}
#option_lists .optcols4 {
width: 130px;
margin-left: -44px;
}
#option_lists ul[class^=optcols] li {
float: left;
}
ul li.current {
background-color: #F4E284;
}
#option_lists ul li {
margin: 0;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
}
#copyright {
text-align: right;
padding-right: .3em;