diff --git a/src/editor/dialogs/imagePropertiesDialog.js b/src/editor/dialogs/imagePropertiesDialog.js new file mode 100644 index 00000000..4b5c0cd9 --- /dev/null +++ b/src/editor/dialogs/imagePropertiesDialog.js @@ -0,0 +1,377 @@ +/* eslint-disable node/no-unpublished-import */ +import 'elix/define/Dialog.js'; +import {isValidUnit} from '../../common/units.js'; + +const template = document.createElement('template'); +template.innerHTML = ` + + +
+
+ + +
+
+ Image Properties + +
+ Canvas Dimensions + + + +
+
+ Included Images + + +
+
+
+
+ +`; +/** + * @class SeImgPropDialog + */ +export class SeImgPropDialog extends HTMLElement { + /** + * @function constructor + */ + constructor () { + super(); + // create the shadowDom and insert the template + this.eventlisten = false; + this._shadowRoot = this.attachShadow({mode: 'open'}); + this._shadowRoot.appendChild(template.content.cloneNode(true)); + this.$saveBtn = this._shadowRoot.querySelector('#tool_docprops_save'); + this.$cancelBtn = this._shadowRoot.querySelector('#tool_docprops_cancel'); + this.$resolution = this._shadowRoot.querySelector('#resolution'); + this.$canvasTitle = this._shadowRoot.querySelector('#canvas_title'); + this.$canvasWidth = this._shadowRoot.querySelector('#canvas_width'); + this.$canvasHeight = this._shadowRoot.querySelector('#canvas_height'); + this.$imageOptEmbed = this._shadowRoot.querySelector('#image_embed'); + this.$imageOptRef = this._shadowRoot.querySelector('#image_ref'); + this.$dialog = this._shadowRoot.querySelector('#svg_docprops'); + } + /** + * @function observedAttributes + * @returns {any} observed + */ + static get observedAttributes () { + return ['title', 'width', 'height', 'save', 'dialog', 'embed']; + } + /** + * @function attributeChangedCallback + * @param {string} name + * @param {string} oldValue + * @param {string} newValue + * @returns {void} + */ + attributeChangedCallback (name, oldValue, newValue) { + if (oldValue === newValue) return; + switch (name) { + case 'title': + this.$canvasTitle.value = newValue; + break; + case 'width': + if (newValue === 'fit') { + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasWidth.value = 100; + this.$canvasHeight.removeAttribute('disabled'); + this.$canvasHeight.value = 100; + } else { + this.$canvasWidth.value = newValue; + } + break; + case 'height': + if (newValue === 'fit') { + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasWidth.value = 100; + this.$canvasHeight.removeAttribute('disabled'); + this.$canvasHeight.value = 100; + } else { + this.$canvasHeight.value = newValue; + } + break; + case 'dialog': + if (this.eventlisten) { + if (newValue === 'open') { + this.$dialog.open(); + } else { + this.$dialog.close(); + } + } + break; + case 'save': + if (newValue === 'ref') { + this.$imageOptEmbed.setAttribute('checked', false); + this.$imageOptRef.setAttribute('checked', true); + } else { + this.$imageOptEmbed.setAttribute('checked', true); + this.$imageOptRef.setAttribute('checked', false); + } + break; + case 'embed': + if (newValue.includes('one')) { + const data = newValue.split('|'); + if (data.length > 1) { + this._shadowRoot.querySelector('#image_opt_embed').setAttribute('title', data[1]); + this._shadowRoot.querySelector('#image_opt_embed').setAttribute('disabled', 'disabled'); + this._shadowRoot.querySelector('#image_opt_embed').style.color = '#666'; + } + } + break; + default: + super.attributeChangedCallback(name, oldValue, newValue); + break; + } + } + /** + * @function get + * @returns {any} + */ + get title () { + return this.getAttribute('title'); + } + + /** + * @function set + * @returns {void} + */ + set title (value) { + this.setAttribute('title', value); + } + /** + * @function get + * @returns {any} + */ + get width () { + return this.hasAttribute('width'); + } + /** + * @function set + * @returns {void} + */ + set width (value) { + this.setAttribute('width', value); + } + /** + * @function get + * @returns {any} + */ + get height () { + return this.hasAttribute('height'); + } + /** + * @function set + * @returns {void} + */ + set height (value) { + this.setAttribute('height', value); + } + /** + * @function get + * @returns {any} + */ + get save () { + return this.hasAttribute('save'); + } + /** + * @function set + * @returns {void} + */ + set save (value) { + this.setAttribute('save', value); + } + /** + * @function get + * @returns {any} + */ + get dialog () { + return this.hasAttribute('dialog'); + } + /** + * @function set + * @returns {void} + */ + set dialog (value) { + this.setAttribute('dialog', value); + } + /** + * @function get + * @returns {any} + */ + get embed () { + return this.hasAttribute('embed'); + } + /** + * @function set + * @returns {void} + */ + set embed (value) { + this.setAttribute('embed', value); + } + /** + * @function connectedCallback + * @returns {void} + */ + connectedCallback () { + const onChangeHandler = (ev) => { + if (!ev.target.selectedIndex) { + if (this.$canvasWidth.getAttribute('value') === 'fit') { + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasWidth.value = 100; + this.$canvasHeight.removeAttribute('disabled'); + this.$canvasHeight.value = 100; + } + } else if (ev.target.value === 'content') { + this.$canvasWidth.setAttribute('disabled', 'disabled'); + this.$canvasWidth.value = 'fit'; + this.$canvasHeight.setAttribute('disabled', 'disabled'); + this.$canvasHeight.value = 'fit'; + } else { + const dims = ev.target.value.split('x'); + this.$canvasWidth.value = dims[0]; + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasHeight.value = dims[1]; + this.$canvasHeight.removeAttribute('disabled'); + } + }; + const onSaveHandler = (ev) => { + let saveOpt = ''; + const w = this.$canvasWidth.value; + const h = this.$canvasHeight.value; + if (w !== 'fit' && !isValidUnit('width', w)) { + this.$canvasWidth.parentElement.classList.add('error'); + } else { + this.$canvasWidth.parentElement.classList.remove('error'); + } + if (h !== 'fit' && !isValidUnit('height', w)) { + this.$canvasHeight.parentElement.classList.add('error'); + } else { + this.$canvasHeight.parentElement.classList.remove('error'); + } + if (this.$imageOptEmbed.getAttribute('checked') === 'true') { + saveOpt = 'embed'; + } + if (this.$imageOptRef.getAttribute('checked') === 'true') { + saveOpt = 'ref'; + } + const closeEvent = new CustomEvent('change', { detail: { + title: this.$canvasTitle.value, + w: this.$canvasWidth.value, + h: this.$canvasHeight.value, + save: saveOpt, + dialog: 'close' + }}); + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasHeight.removeAttribute('disabled'); + this.$resolution.selectedIndex = 0; + this.dispatchEvent(closeEvent); + }; + const onCancelHandler = (ev) => { + const closeEvent = new CustomEvent('change', { detail: { + dialog: 'closed' + }}); + this.$canvasWidth.removeAttribute('disabled'); + this.$canvasHeight.removeAttribute('disabled'); + this.$resolution.selectedIndex = 0; + this.dispatchEvent(closeEvent); + }; + this.$resolution.addEventListener('change', onChangeHandler); + this.$saveBtn.addEventListener('click', onSaveHandler); + this.$cancelBtn.addEventListener('click', onCancelHandler); + this.$dialog.addEventListener('close', onCancelHandler); + this.eventlisten = true; + } +} + +// Register +customElements.define('se-img-prop-dialog', SeImgPropDialog); diff --git a/src/editor/dialogs/index.js b/src/editor/dialogs/index.js new file mode 100644 index 00000000..fe96b1e7 --- /dev/null +++ b/src/editor/dialogs/index.js @@ -0,0 +1 @@ +import './imagePropertiesDialog.js'; diff --git a/src/editor/index.html b/src/editor/index.html index 381caf75..505078e3 100644 --- a/src/editor/index.html +++ b/src/editor/index.html @@ -91,7 +91,6 @@ -
@@ -441,55 +440,6 @@
-
-
-
-
- - -
-
- Image Properties - -
- Canvas Dimensions - - - -
-
- Included Images - - -
-
-
-
diff --git a/src/editor/index.js b/src/editor/index.js index 3c578d3e..c29f2fa2 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -7,6 +7,7 @@ For default config and extensions (and available options) available to import './jquery.min.js'; import './jquery-ui/jquery-ui-1.8.17.custom.min.js'; import './components/index.js'; +import './dialogs/index.js'; import svgEditor from './svgedit.js'; // URL OVERRIDE CONFIG diff --git a/src/editor/svgedit.js b/src/editor/svgedit.js index 48cd897a..0bea6b1b 100644 --- a/src/editor/svgedit.js +++ b/src/editor/svgedit.js @@ -610,6 +610,10 @@ editor.init = () => { */ editor.storage = localStorage; } + // Image props dialog added to DOM + const newSeImgPropDialog = document.createElement('se-img-prop-dialog'); + newSeImgPropDialog.setAttribute('id', 'se-img-prop'); + document.body.append(newSeImgPropDialog); } catch (err) {} // get list of languages from options in the HTML @@ -2702,8 +2706,17 @@ editor.init = () => { setBackground(editor.pref('bkgd_color'), editor.pref('bkgd_url')); - $('#image_save_opts input').val([editor.pref('img_save')]); - + // update resolution option with actual resolution + const res = svgCanvas.getResolution(); + if (curConfig.baseUnit !== 'px') { + res.w = convertUnit(res.w) + curConfig.baseUnit; + res.h = convertUnit(res.h) + curConfig.baseUnit; + } + $('#se-img-prop').attr('dialog', 'close'); + $('#se-img-prop').attr('title', svgCanvas.getDocumentTitle()); + $('#se-img-prop').attr('width', res.w); + $('#se-img-prop').attr('height', res.h); + $('#se-img-prop').attr('save', editor.pref('img_save')); /** * @type {module} */ @@ -3775,7 +3788,7 @@ editor.init = () => { updateToolButtonState(); }; - $('#svg_docprops_container, #svg_prefs_container').draggable({ + $('#svg_prefs_container').draggable({ cancel: 'button,fieldset', containment: 'window' }).css('position', 'absolute'); @@ -3790,9 +3803,7 @@ editor.init = () => { const showDocProperties = function () { if (docprops) { return; } docprops = true; - - // This selects the correct radio button by using the array notation - $('#image_save_opts input').val([editor.pref('img_save')]); + const $imgDialog = document.getElementById('se-img-prop'); // update resolution option with actual resolution const res = svgCanvas.getResolution(); @@ -3800,12 +3811,11 @@ editor.init = () => { res.w = convertUnit(res.w) + curConfig.baseUnit; res.h = convertUnit(res.h) + curConfig.baseUnit; } - - $('#canvas_width').val(res.w); - $('#canvas_height').val(res.h); - $('#canvas_title').val(svgCanvas.getDocumentTitle()); - - $('#svg_docprops').show(); + $imgDialog.setAttribute('save', editor.pref('img_save')); + $imgDialog.setAttribute('width', res.w); + $imgDialog.setAttribute('height', res.h); + $imgDialog.setAttribute('title', svgCanvas.getDocumentTitle()); + $imgDialog.setAttribute('dialog', 'open'); }; /** @@ -3887,10 +3897,9 @@ editor.init = () => { * @returns {void} */ const hideDocProperties = function () { - $('#svg_docprops').hide(); - $('#canvas_width,#canvas_height').removeAttr('disabled'); - $('#resolution')[0].selectedIndex = 0; - $('#image_save_opts input').val([editor.pref('img_save')]); + const $imgDialog = document.getElementById('se-img-prop'); + $imgDialog.setAttribute('dialog', 'close'); + $imgDialog.setAttribute('save', editor.pref('img_save')); docprops = false; }; @@ -3907,39 +3916,26 @@ editor.init = () => { * * @returns {boolean} Whether there were problems saving the document properties */ - const saveDocProperties = function () { + const saveDocProperties = function (e) { // set title - const newTitle = $('#canvas_title').val(); - updateTitle(newTitle); - svgCanvas.setDocumentTitle(newTitle); - - // update resolution - const width = $('#canvas_width'), w = width.val(); - const height = $('#canvas_height'), h = height.val(); + const {title, w, h, save} = e.detail; + // set document title + svgCanvas.setDocumentTitle(title); if (w !== 'fit' && !isValidUnit('width', w)) { - width.parent().addClass('error'); /* await */ $.alert(uiStrings.notification.invalidAttrValGiven); return false; } - - width.parent().removeClass('error'); - if (h !== 'fit' && !isValidUnit('height', h)) { - height.parent().addClass('error'); /* await */ $.alert(uiStrings.notification.invalidAttrValGiven); return false; } - - height.parent().removeClass('error'); - if (!svgCanvas.setResolution(w, h)) { /* await */ $.alert(uiStrings.notification.noContentToFitTo); return false; } - // Set image save option - editor.pref('img_save', $('#image_save_opts :checked').val()); + editor.pref('img_save', save); updateCanvas(); hideDocProperties(); return true; @@ -4259,13 +4255,10 @@ editor.init = () => { svgCanvas.embedImage('images/logo.svg', function (datauri) { if (!datauri) { // Disable option - $('#image_save_opts [value=embed]').attr('disabled', 'disabled'); - $('#image_save_opts input').val(['ref']); + const $imgDialog = document.getElementById('se-img-prop'); editor.pref('img_save', 'ref'); - $('#image_opt_embed').css('color', '#666').attr( - 'title', - uiStrings.notification.featNotSupported - ); + $imgDialog.setAttribute('save', 'ref'); + $imgDialog.setAttribute('embed', 'one|' + uiStrings.notification.featNotSupported); } }); }, 1000); @@ -4491,27 +4484,10 @@ editor.init = () => { // // } // } - $('#resolution').change(function () { - const wh = $('#canvas_width,#canvas_height'); - if (!this.selectedIndex) { - if ($('#canvas_width').val() === 'fit') { - wh.removeAttr('disabled').val(100); - } - } else if (this.value === 'content') { - wh.val('fit').attr('disabled', 'disabled'); - } else { - const dims = this.value.split('x'); - $('#canvas_width').val(dims[0]); - $('#canvas_height').val(dims[1]); - wh.removeAttr('disabled'); - } - }); - // Prevent browser from erroneously repopulating fields $('input,select').attr('autocomplete', 'off'); const dialogSelectors = [ - '#tool_source_cancel', '#tool_docprops_cancel', '#tool_prefs_cancel', '.overlay' ]; /* eslint-disable jsdoc/require-property */ @@ -4640,6 +4616,13 @@ editor.init = () => { $id('tool_docprops').addEventListener('click', showDocProperties); $id('tool_editor_prefs').addEventListener('click', showPreferences); $id('tool_editor_homepage').addEventListener('click', openHomePage); + $id('se-img-prop').addEventListener('change', function (e) { + if (e.detail.dialog === 'closed') { + hideDocProperties(); + } else { + saveDocProperties(e); + } + }); const toolButtons = [ { @@ -4656,7 +4639,6 @@ editor.init = () => { {sel: dialogSelectors.join(','), fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, {sel: '#tool_source_save', fn: saveSourceEditor, evt: 'click'}, - {sel: '#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, {sel: '#tool_prefs_save', fn: savePreferences, evt: 'click'}, {sel: '#tool_node_link', fn: linkControlPoints, evt: 'click'}, {sel: '#tool_ungroup', fn: clickGroup, evt: 'click'},