diff --git a/src/editor/extensions/ext-connector/ext-connector.js b/src/editor/extensions/ext-connector/ext-connector.js index acdf2b41..22d161c1 100644 --- a/src/editor/extensions/ext-connector/ext-connector.js +++ b/src/editor/extensions/ext-connector/ext-connector.js @@ -640,13 +640,13 @@ export default { return {remove}; }, toolButtonStateUpdate (opts) { + const button = document.getElementById('mode_connect'); if (opts.nostroke) { - if ($('#mode_connect').hasClass('tool_button_current')) { + if (button.pressed === true) { svgEditor.clickSelect(); } } - $('#mode_connect') - .toggleClass('disabled', opts.nostroke); + button.disabled = opts.nostroke; } }; } diff --git a/src/editor/extensions/ext-grid/ext-grid.js b/src/editor/extensions/ext-grid/ext-grid.js index 666b1473..5d9f95a7 100644 --- a/src/editor/extensions/ext-grid/ext-grid.js +++ b/src/editor/extensions/ext-grid/ext-grid.js @@ -146,24 +146,10 @@ export default { updateGrid(svgCanvas.getZoom()); } $('#canvasGrid').toggle(showGrid); - $('#view_grid').toggleClass('push_button_pressed tool_button'); + document.getElementById('view_grid').pressed = showGrid; } - const buttons = [{ - id: 'view_grid', - icon: 'grid.png', - type: 'context', - panel: 'editor_panel', - events: { - click () { - svgEditor.curConfig.showGrid = showGrid = !showGrid; - gridUpdate(); - } - } - }]; return { name: strings.name, - svgicons: 'grid-icon.xml', - zoomChanged (zoom) { if (showGrid) { updateGrid(zoom); } }, @@ -172,9 +158,13 @@ export default { gridUpdate(); } }, - buttons: strings.buttons.map((button, i) => { - return Object.assign(buttons[i], button); - }) + events: { + id: 'view_grid', + click () { + svgEditor.curConfig.showGrid = showGrid = !showGrid; + gridUpdate(); + } + } }; } }; diff --git a/src/editor/extensions/ext-helloworld/ext-helloworld.js b/src/editor/extensions/ext-helloworld/ext-helloworld.js index 4c3d383b..89e583e8 100644 --- a/src/editor/extensions/ext-helloworld/ext-helloworld.js +++ b/src/editor/extensions/ext-helloworld/ext-helloworld.js @@ -33,33 +33,16 @@ export default { const svgCanvas = svgEditor.canvas; return { name: strings.name, - // For more notes on how to make an icon file, see the source of - // the helloworld-icon.xml - svgicons: 'helloworld-icon.xml', - - // Multiple buttons can be added in this array - buttons: [{ + events: [{ // Must match the icon ID in helloworld-icon.xml id: 'hello_world', - - // Fallback, e.g., for `file:///` access - icon: 'helloworld.png', - - // This indicates that the button will be added to the "mode" - // button panel on the left side - type: 'mode', - // Tooltip text title: strings.buttons[0].title, - - // Events - events: { - click () { - // The action taken when the button is clicked on. - // For "mode" buttons, any other button will - // automatically be de-pressed. - svgCanvas.setMode('hello_world'); - } + click () { + // The action taken when the button is clicked on. + // For "mode" buttons, any other button will + // automatically be de-pressed. + svgCanvas.setMode('hello_world'); } }], // This is triggered when the main mouse button is pressed down diff --git a/src/editor/extensions/ext-markers/ext-markers.js b/src/editor/extensions/ext-markers/ext-markers.js index e91a1d0e..6ee754a7 100644 --- a/src/editor/extensions/ext-markers/ext-markers.js +++ b/src/editor/extensions/ext-markers/ext-markers.js @@ -121,7 +121,7 @@ export default { function setIcon (pos, id) { if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; } const ci = '#' + idPrefix + pos + '_' + id.substr(1); - svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children()); + // svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children()); $(ci).addClass('current').siblings().removeClass('current'); } diff --git a/src/editor/extensions/ext-polygon/ext-polygon.js b/src/editor/extensions/ext-polygon/ext-polygon.js index ab5d9ab8..20f67ebf 100644 --- a/src/editor/extensions/ext-polygon/ext-polygon.js +++ b/src/editor/extensions/ext-polygon/ext-polygon.js @@ -33,22 +33,6 @@ export default { // edg = 0, // undoCommand = 'Not image'; started, newFO; - - // const ccZoom; - // const wEl, hEl; - // const wOffset, hOffset; - // const ccRBG; - // const ccOpacity; - // const brushW, brushH; - - // const ccDebug = document.getElementById('debugpanel'); - - /* const properlySourceSizeTextArea = function(){ - // TODO: remove magic numbers here and get values from CSS - const height = $('#svg_source_container').height() - 80; - $('#svg_source_textarea').css('height', height); - }; */ - /** * @param {boolean} on * @returns {void} @@ -102,55 +86,13 @@ export default { * @param {string} tex The itex text. * @returns {boolean} This function returns false if the set was unsuccessful, true otherwise. */ - /* - function setItexString(tex) { - const mathns = 'http://www.w3.org/1998/Math/MathML', - xmlnsns = 'http://www.w3.org/2000/xmlns/', - ajaxEndpoint = '../../itex'; - const elt = selElems[0]; - try { - const math = svgdoc.createElementNS(mathns, 'math'); - math.setAttributeNS(xmlnsns, 'xmlns', mathns); - math.setAttribute('display', 'inline'); - const semantics = document.createElementNS(mathns, 'semantics'); - const annotation = document.createElementNS(mathns, 'annotation'); - annotation.setAttribute('encoding', 'application/x-tex'); - annotation.textContent = tex; - const mrow = document.createElementNS(mathns, 'mrow'); - semantics.append(mrow, annotation); - math.append(semantics); - // make an AJAX request to the server, to get the MathML - $.post(ajaxEndpoint, {tex, display: 'inline'}, function(data){ - const children = data.documentElement.childNodes; - while (children.length > 0) { - mrow.append(svgdoc.adoptNode(children[0], true)); - } - svgCanvas.sanitizeSvg(math); - svgCanvas.call('changed', [elt]); - }); - elt.firstChild.replaceWith(math); - svgCanvas.call('changed', [elt]); - svgCanvas.clearSelection(); - } catch(e) { - console.log(e); - return false; - } - - return true; - } - */ - const buttons = [{ + const events = { id: 'tool_polygon', - icon: 'polygon.png', - type: 'mode', - position: 11, - events: { - click () { - svgCanvas.setMode('polygon'); - showPanel(true); - } + click () { + svgCanvas.setMode('polygon'); + showPanel(true); } - }]; + }; const contextTools = [{ type: 'input', panel: 'polygon_panel', @@ -164,11 +106,8 @@ export default { } }]; return { - newUI: true, name: strings.name, - buttons: strings.buttons.map((button, i) => { - return Object.assign(buttons[i], button); - }), + events, context_tools: strings.contextTools.map((contextTool, i) => { return Object.assign(contextTools[i], contextTool); }), diff --git a/src/editor/extensions/ext-shapes/ext-shapes.js b/src/editor/extensions/ext-shapes/ext-shapes.js index ae12d761..545140ab 100644 --- a/src/editor/extensions/ext-shapes/ext-shapes.js +++ b/src/editor/extensions/ext-shapes/ext-shapes.js @@ -7,23 +7,10 @@ * */ -const loadExtensionTranslation = async function (lang) { - let translationModule; - try { - translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`); - } catch (_error) { - // eslint-disable-next-line no-console - console.error(`Missing translation (${lang}) - using 'en'`); - translationModule = await import(`./locale/en.js`); - } - return translationModule.default; -}; - export default { name: 'shapes', - async init ({$}) { + init ({$}) { const svgEditor = this; - const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang); const canv = svgEditor.canvas; const svgroot = canv.getRootElem(); let lastBBox = {}; @@ -35,21 +22,15 @@ export default { let startX; let startY; - const buttons = [{ - id: 'tool_shapelib_show', - type: 'mode_flyout', - events: { - click () { - canv.setMode(modeId); - } + const events = { + id: 'tool_shapelib', + click () { + canv.setMode(modeId); } - }]; + }; return { - newUI: true, - buttons: strings.buttons.map((button, i) => { - return Object.assign(buttons[i], button); - }), + events, callback () { // should later register the event }, @@ -57,7 +38,7 @@ export default { const mode = canv.getMode(); if (mode !== modeId) { return undefined; } - const currentD = document.getElementById('tool_shapelib_show').dataset.draw; + const currentD = document.getElementById('tool_shapelib').dataset.draw; startX = opts.start_x; const x = startX; startY = opts.start_y; diff --git a/src/editor/images/grid.png b/src/editor/images/grid.png deleted file mode 100644 index 75e400ef..00000000 Binary files a/src/editor/images/grid.png and /dev/null differ diff --git a/src/editor/images/grid-icon.xml b/src/editor/images/grid.svg similarity index 77% rename from src/editor/images/grid-icon.xml rename to src/editor/images/grid.svg index 3ec53911..4a2167fa 100644 --- a/src/editor/images/grid-icon.xml +++ b/src/editor/images/grid.svg @@ -1,13 +1,3 @@ - - - @@ -25,6 +15,4 @@ - - - + \ No newline at end of file diff --git a/src/editor/index.html b/src/editor/index.html index 0c5b5057..1db526a3 100644 --- a/src/editor/index.html +++ b/src/editor/index.html @@ -96,6 +96,7 @@
+
@@ -299,7 +300,7 @@
- + @@ -308,13 +309,13 @@ - + - diff --git a/src/editor/svgedit.css b/src/editor/svgedit.css index ae37168c..b73b1a8f 100644 --- a/src/editor/svgedit.css +++ b/src/editor/svgedit.css @@ -535,7 +535,7 @@ div.toolset label span { margin-left: 5px; } -#tools_top input { +#tools_top se-input, se-spin-input { margin-top: 5px; height: 15px; } diff --git a/src/editor/svgedit.js b/src/editor/svgedit.js index 9a8a34bc..ca2fc448 100644 --- a/src/editor/svgedit.js +++ b/src/editor/svgedit.js @@ -20,7 +20,7 @@ import deparam from 'deparam'; import './touch.js'; import {NS} from '../common/namespaces.js'; -import {isWebkit, isChrome, isGecko, isIE, isMac, isTouch} from '../common/browser.js'; +import {isChrome, isGecko, isIE, isMac, isTouch} from '../common/browser.js'; // Until we split this into smaller files, this helps distinguish utilities // from local methods @@ -34,7 +34,6 @@ import SvgCanvas from '../svgcanvas/svgcanvas.js'; import Layer from '../common/layer.js'; import jQueryPluginJSHotkeys from './js-hotkeys/jquery.hotkeys.min.js'; -import jQueryPluginSVGIcons from './svgicons/jQuery.svgIcons.js'; import jQueryPluginJGraduate from './jgraduate/jQuery.jGraduate.js'; import jQueryPluginContextMenu from './contextmenu/jQuery.contextMenu.js'; import jQueryPluginJPicker from './jgraduate/jQuery.jPicker.js'; @@ -50,7 +49,7 @@ const {$q, $qq, $id} = Utils; const editor = {}; const $ = [ - jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate, + jQueryPluginJSHotkeys, jQueryPluginJGraduate, jQueryPluginContextMenu, jQueryPluginJPicker ].reduce((jq, func) => func(jq), jQuery); @@ -731,24 +730,6 @@ editor.init = () => { })(); setupCurPrefs(); - /** - * Called internally. - * @function module:SVGEditor.setIcon - * @param {string|Element|external:jQuery} elem - * @param {string|external:jQuery} iconId - * @param {Float} forcedSize Not in use - * @returns {void} - */ - const setIcon = editor.setIcon = function (elem, iconId, forcedSize) { - const icon = (typeof iconId === 'string') ? $.getSvgIcon(iconId, true) : iconId.clone(); - if (!icon) { - // Todo: Investigate why this still occurs in some cases - console.log('NOTE: Icon image missing: ' + iconId); // eslint-disable-line no-console - return; - } - $(elem).empty().append(icon); - }; - /** * @fires module:svgcanvas.SvgCanvas#event:ext_addLangData * @fires module:svgcanvas.SvgCanvas#event:ext_langReady @@ -847,8 +828,6 @@ editor.init = () => { } }; - const stateObj = {tool_scale: editor.tool_scale}; - /** * @type {string} */ @@ -869,87 +848,6 @@ editor.init = () => { return ''; }()); - /** - * Called internally. - * @function module:SVGEditor.setIconSize - * @param {module:SVGEditor.IconSize} size - * @returns {void} - */ - const setIconSize = editor.setIconSize = function (size) { - const selToscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,' + - ' #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,' + - ' #g_panel > *, #tool_font_size > *'; - - const elems = $(selToscale); - - let scale = 1; - if (typeof size === 'number') { - scale = size; - } else { - const iconSizes = {s: 0.75, m: 1, l: 1.25, xl: 1.5}; - scale = iconSizes[size]; - } - - stateObj.tool_scale = editor.tool_scale = scale; - - const hiddenPs = elems.parents(':hidden'); - hiddenPs.css('visibility', 'hidden').show(); - hiddenPs.css('visibility', 'visible').hide(); - // return; - - editor.pref('iconsize', size); - const $editDialog = document.getElementById('se-edit-prefs'); - $editDialog.setAttribute('iconsize', size); - - // Note that all rules will be prefixed with '#svg_editor' when parsed - const cssResizeRules = { - '#tools_top': { - left: 50 + $('#main_button').width(), - height: 72 - }, - '#tools_left': { - width: 31, - top: 74 - }, - 'div#workarea': { - left: 38, - top: 74 - } - }; - - let ruleElem = $('#tool_size_rules'); - if (!ruleElem.length) { - ruleElem = $('').appendTo('head'); - } else { - ruleElem.empty(); - } - - if (size !== 'm') { - let styleStr = ''; - $.each(cssResizeRules, function (selector, rules) { - selector = '#svg_editor ' + selector.replace(/,/g, ', #svg_editor'); - styleStr += selector + '{'; - $.each(rules, function (prop, values) { - let val; - if (typeof values === 'number') { - val = (values * scale) + 'px'; - } else if (values[size] || values.all) { - val = (values[size] || values.all); - } - styleStr += (prop + ':' + val + ';'); - }); - styleStr += '}'; - }); - // this.style[uaPrefix + 'Transform'] = 'scale(' + scale + ')'; - const prefix = '-' + uaPrefix.toLowerCase() + '-'; - styleStr += (selToscale + '{' + prefix + 'transform: scale(' + scale + ');}' + - ' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' + // Hack for markers - ' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + (1 / scale) + ');}' // Hack for sliders - ); - ruleElem.text(styleStr); - } - }; - /** * @name module:SVGEditor.canvas * @type {module:svgcanvas.SvgCanvas} @@ -966,7 +864,6 @@ editor.init = () => { const canvMenu = $('#cmenu_canvas'); const paintBox = {fill: null, stroke: null}; - let resizeTimer; let exportWindow = null, defaultImageURL = curConfig.imgPath + 'logo.svg', zoomInIcon = 'crosshair', @@ -1045,7 +942,6 @@ editor.init = () => { const selLayerNames = $('#selLayerNames').empty(); const drawing = svgCanvas.getCurrentDrawing(); const currentLayerName = drawing.getCurrentLayerName(); - const icon = $.getSvgIcon('eye'); let layer = svgCanvas.getCurrentDrawing().getNumLayers(); // we get the layers in the reverse z-order (the layer rendered on top is listed first) while (layer--) { @@ -1056,11 +952,6 @@ editor.init = () => { layerlist.append(layerTr.append(layerVis, layerName)); selLayerNames.append(''); } - if (icon !== undefined) { - const copy = icon.clone(); - $('td.layervis', layerlist).append(copy); - $.resizeSvgIcons({'td.layervis .svg_icon': 14}); - } // handle selection of layer $('#layerlist td.layername') .mouseup(function (evt) { @@ -1240,7 +1131,6 @@ editor.init = () => { if (changeElem) { svgCanvas.setStrokeAttr('stroke-' + pre, val); } - setIcon('#cur_' + pre, id, 20); $(opt).addClass('current').siblings().removeClass('current'); } @@ -1585,38 +1475,40 @@ editor.init = () => { * @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate * @returns {void} */ - const updateToolButtonState = function () { + const updateToolButtonState = () => { const bNoFill = (svgCanvas.getColor('fill') === 'none'); const bNoStroke = (svgCanvas.getColor('stroke') === 'none'); - const buttonsNeedingStroke = ['#tool_fhpath', '#tool_line']; + const buttonsNeedingStroke = ['tool_fhpath', 'tool_line']; const buttonsNeedingFillAndStroke = [ - '#tools_rect .tool_button', '#tools_ellipse .tool_button', - '#tool_text', '#tool_path' + 'tools_rect', 'tools_ellipse', + 'tool_text', 'tool_path' ]; if (bNoStroke) { buttonsNeedingStroke.forEach((btn) => { - if ($(btn).hasClass('tool_button_current')) { + // if btn is pressed, change to select button + if ($id(btn).pressed) { clickSelect(); } - $(btn).addClass('disabled'); + $(btn).disabled = true; }); } else { buttonsNeedingStroke.forEach((btn) => { - $(btn).removeClass('disabled'); + $id(btn).disabled = false; }); } if (bNoStroke && bNoFill) { buttonsNeedingFillAndStroke.forEach((btn) => { - if ($(btn).hasClass('tool_button_current')) { + // if btn is pressed, change to select button + if ($id(btn).pressed) { clickSelect(); } - $(btn).addClass('disabled'); + $(btn).disabled = true; }); } else { buttonsNeedingFillAndStroke.forEach((btn) => { - $(btn).removeClass('disabled'); + $id(btn).disabled = false; }); } @@ -1771,17 +1663,16 @@ editor.init = () => { } // Elements in this array cannot be converted to a path - const noPath = !['image', 'text', 'path', 'g', 'use'].includes(elname); - $('#tool_topath').toggle(noPath); - $('#tool_reorient').toggle(elname === 'path'); - $('#tool_reorient').toggleClass('disabled', angle === 0); + $id('tool_topath').style.display = ['image', 'text', 'path', 'g', 'use'].includes(elname) ? 'none' : 'block'; + $id('tool_reorient').style.display = (elname === 'path') ? 'block' : 'none'; + $id('tool_reorient').disabled = (angle === 0); } else { const point = path.getNodePoint(); $('#tool_add_subpath').pressed = false; $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); // Show open/close button based on selected point - setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); + // setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); if (point) { const segType = $('#seg_type'); @@ -2222,75 +2113,6 @@ editor.init = () => { paintBox.stroke.prep(); }; - /** - * @param {string} elemSel - * @param {string} listSel - * @param {external:jQuery.Function} callback - * @param {PlainObject} opts - * @param {boolean} opts.dropUp - * @param {boolean} opts.seticon - * @param {boolean} opts.multiclick - * @todo Combine this with `addDropDown` or find other way to optimize. - * @returns {void} - */ - const addAltDropDown = function (elemSel, listSel, callback, opts) { - const button = $(elemSel); - const {dropUp} = opts; - const list = $(listSel); - if (dropUp) { - $(elemSel).addClass('dropup'); - } - list.find('li').bind('mouseup', function (...args) { - if (opts.seticon) { - setIcon('#cur_' + button[0].id, $(this).children()); - $(this).addClass('current').siblings().removeClass('current'); - } - callback.apply(this, ...args); - }); - - let onButton = false; - $(window).mouseup(function (evt) { - if (!onButton) { - button.removeClass('down'); - list.hide(); - list.css({top: 0, left: 0}); - } - onButton = false; - }); - - // const height = list.height(); // Currently unused - button.bind('mousedown', function () { - const off = button.offset(); - if (dropUp) { - off.top -= list.height(); - off.left += 8; - } else { - off.top += button.height(); - } - list.offset(off); - - if (!button.hasClass('down')) { - list.show(); - onButton = true; - } else { - // CSS position must be reset for Webkit - list.hide(); - list.css({top: 0, left: 0}); - } - button.toggleClass('down'); - }).hover(function () { - onButton = true; - }).mouseout(function () { - onButton = false; - }); - - if (opts.multiclick) { - list.mousedown(function () { - onButton = true; - }); - } - }; - /** * @param {external:Window} win * @param {module:svgcanvas.SvgCanvas#event:extension_added} ext @@ -2302,7 +2124,6 @@ editor.init = () => { return undefined; } let cbCalled = false; - let resizeDone = false; if (ext.langReady) { if (editor.langChanged) { // We check for this since the "lang" pref could have been set by storage @@ -2310,23 +2131,6 @@ editor.init = () => { await ext.langReady({lang}); } } - /** - * Clear resize timer if present and if not previously performed, - * perform an icon resize. - * @returns {void} - */ - function prepResize () { - if (resizeTimer) { - clearTimeout(resizeTimer); - resizeTimer = null; - } - if (!resizeDone) { - resizeTimer = setTimeout(function () { - resizeDone = true; - setIconSize(editor.pref('iconsize')); - }, 50); - } - } /** * @@ -2339,8 +2143,6 @@ editor.init = () => { } }; - const btnSelects = []; - /** * @typedef {PlainObject} module:SVGEditor.ContextTool * @property {string} panel The ID of the existing panel to which the tool is being added. Required. @@ -2405,15 +2207,6 @@ editor.init = () => { // Creates the tool, hides & adds it, returns the select element /* const dropdown = */ $(html).appendTo(panel).children(); - - btnSelects.push({ - elem: ('#' + tool.id), - list: ('#' + tool.id + '_opts'), - title: tool.title, - callback: tool.events.change, - cur: ('#cur_' + tool.id) - }); - break; } case 'input': { html = '' + @@ -2440,184 +2233,10 @@ editor.init = () => { }); } - const {svgicons} = ext; - if (ext.buttons && !ext.newUI) { - const fallbackObj = {}, - altsObj = {}, - placementObj = {}; - - /** - * @typedef {GenericArray} module:SVGEditor.KeyArray - * @property {string} 0 The key to bind (on `keydown`) - * @property {boolean} 1 Whether to `preventDefault` on the `keydown` event - * @property {boolean} 2 Not apparently in use (NoDisableInInput) - */ - /** - * @typedef {string|module:SVGEditor.KeyArray} module:SVGEditor.Key - */ - /** - * @typedef {PlainObject} module:SVGEditor.Button - * @property {string} id A unique identifier for this button. If SVG icons are used, this must match the ID used in the icon file. Required. - * @property {"mode_flyout"|"mode"|"context"|"app_menu"} type Type of button. Required. - * @property {string} title The tooltip text that will appear when the user hovers over the icon. Required. - * @property {PlainObject|PlainObject<"click", external:jQuery.Function>} events DOM event names with associated functions. Example: `{click () { alert('Button was clicked') } }`. Click is used with `includeWith` and `type` of "mode_flyout" (and "mode"); any events may be added if `list` is not present. Expected. - * @property {string} panel The ID of the context panel to be included, if type is "context". Required only if type is "context". - * @property {string} icon The file path to the raster version of the icon image source. Required only if no `svgicons` is supplied from [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse}. - * @property {string} [svgicon] If absent, will utilize the button "id"; used to set "placement" on the `svgIcons` call - * @property {string} [list] Points to the "id" of a `context_tools` item of type "button-select" into which the button will be added as a panel list item - * @property {Integer} [position] The numeric index for placement; defaults to last position (as of the time of extension addition) if not present. For use with {@link http://api.jquery.com/eq/}. - * @property {boolean} [isDefault] Whether or not the button is the default. Used with `list`. - * @property {module:SVGEditor.Key} [key] The key to bind to the button - */ - // Add buttons given by extension - $.each(ext.buttons, function (i, /** @type {module:SVGEditor.Button} */ btn) { - let {id} = btn; - let num = i; - // Give button a unique ID - while ($('#' + id).length) { - id = btn.id + '_' + (++num); - } - - let icon; - if (!svgicons) { - icon = $( - '' + btn.title : '') +
-              '' - ); - } else { - fallbackObj[id] = btn.icon; - altsObj[id] = btn.title; - const svgicon = btn.svgicon || btn.id; - if (btn.type === 'app_menu') { - placementObj['#' + id + ' > div'] = svgicon; - } else { - placementObj['#' + id] = svgicon; - } - } - - let cls, parent; - - // Set button up according to its type - switch (btn.type) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - parent = '#tools_left'; - break; - case 'context': - cls = 'tool_button'; - parent = '#' + btn.panel; - // create the panel if it doesn't exist - if (!$(parent).length) { - $('
', {id: btn.panel}).appendTo('#tools_top'); - } - break; - case 'app_menu': - cls = ''; - parent = '#main_menu ul'; - break; - } - - const button = $((btn.list || btn.type === 'app_menu') ? '
  • ' : '
    ') - .attr('id', id) - .attr('title', btn.title) - .addClass(cls); - if (!btn.includeWith && !btn.list) { - if ('position' in btn) { - if ($(parent).children().eq(btn.position).length) { - $(parent).children().eq(btn.position).before(button); - } else { - $(parent).children().last().after(button); - } - } else { - button.appendTo(parent); - } - - if (btn.type === 'app_menu') { - button.append('
    ').append(btn.title); - } - } else if (btn.list) { - // Add button to list - button.addClass('push_button'); - $('#' + btn.list + '_opts').append(button); - if (btn.isDefault) { - $('#cur_' + btn.list).append(button.children().clone()); - const svgicon = btn.svgicon || btn.id; - placementObj['#cur_' + btn.list] = svgicon; - } - } - if (!svgicons) { - button.append(icon); - } - - if (!btn.list) { - // Add given events to button - $.each(btn.events, function (name, func) { - if (name === 'click' && btn.type === 'mode') { - // `touch.js` changes `touchstart` to `mousedown`, - // so we must map extension click events as well - if (isTouch() && name === 'click') { - name = 'mousedown'; - } - if (btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function () { - if (updateLeftPanel(button)) { - func(); - } - }); - } - if (btn.key) { - $(document).bind('keydown', btn.key, func); - if (btn.title) { - button.attr('title', btn.title + ' [' + btn.key + ']'); - } - } - } else { - button.bind(name, func); - } - }); - } - }); - $.each(btnSelects, function () { - addAltDropDown(this.elem, this.list, this.callback, {seticon: true}); - }); - - if (svgicons) { - return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new - $.svgIcons(`${curConfig.imgPath}${svgicons}`, { - w: 24, h: 24, - id_match: false, - no_img: (!isWebkit()), - fallback: fallbackObj, - placement: placementObj, - callback (icons) { - // Non-ideal hack to make the icon match the current size - // if (curPrefs.iconsize && curPrefs.iconsize !== 'm') { - if (editor.pref('iconsize') !== 'm') { - prepResize(); - } - runCallback(); - resolve(); - } - }); - }); - } - } - if (ext.buttons && ext.newUI) { - ext.buttons.forEach((btn) => { - // Set button up according to its type - switch (btn.type) { - case 'mode_flyout': - case 'mode': - $id(btn.id).addEventListener('click', () => { - if (updateLeftPanel(btn.id)) { - btn.events.click(); - } - }); - break; + if (ext.events) { + $id(ext.events.id).addEventListener('click', () => { + if (updateLeftPanel(ext.events.id)) { + ext.events.click(); } }); } @@ -3117,6 +2736,7 @@ editor.init = () => { } }); + /* addAltDropDown('#stroke_linecap', '#linecap_opts', function () { setStrokeOpt(this, true); }, {dropUp: true}); @@ -3129,6 +2749,7 @@ editor.init = () => { const letter = this.id.replace('tool_pos', '').charAt(0); svgCanvas.alignSelectedElements(letter, 'page'); }, {multiclick: true}); + */ // Unfocus text input when workarea is mousedowned. (function () { @@ -3261,8 +2882,8 @@ editor.init = () => { * @returns {void} */ const zoomImage = function (multiplier) { - const res = svgCanvas.getResolution(); - multiplier = multiplier ? res.zoom * multiplier : 1; + const resolution = svgCanvas.getResolution(); + multiplier = multiplier ? resolution.zoom * multiplier : 1; // setResolution(res.w * multiplier, res.h * multiplier, true); $id('zoom').value = (multiplier * 100).toFixed(1); svgCanvas.setZoom(multiplier); @@ -3735,11 +3356,6 @@ editor.init = () => { updateToolButtonState(); }; - /* $('#svg_prefs_container').draggable({ - cancel: 'button,fieldset', - containment: 'window' - }).css('position', 'absolute'); */ - let docprops = false; let preferences = false; @@ -3753,14 +3369,14 @@ editor.init = () => { const $imgDialog = document.getElementById('se-img-prop'); // update resolution option with actual resolution - const res = svgCanvas.getResolution(); + const resolution = svgCanvas.getResolution(); if (curConfig.baseUnit !== 'px') { - res.w = convertUnit(res.w) + curConfig.baseUnit; - res.h = convertUnit(res.h) + curConfig.baseUnit; + resolution.w = convertUnit(resolution.w) + curConfig.baseUnit; + resolution.h = convertUnit(resolution.h) + curConfig.baseUnit; } $imgDialog.setAttribute('save', editor.pref('img_save')); - $imgDialog.setAttribute('width', res.w); - $imgDialog.setAttribute('height', res.h); + $imgDialog.setAttribute('width', resolution.w); + $imgDialog.setAttribute('height', resolution.h); $imgDialog.setAttribute('title', svgCanvas.getDocumentTitle()); $imgDialog.setAttribute('dialog', 'open'); }; @@ -3855,7 +3471,7 @@ editor.init = () => { }; /** - * + * @param {Event} e * @returns {boolean} Whether there were problems saving the document properties */ const saveDocProperties = function (e) { @@ -3885,11 +3501,12 @@ editor.init = () => { /** * Save user preferences based on current values in the UI. + * @param {Event} e * @function module:SVGEditor.savePreferences * @returns {Promise} */ const savePreferences = editor.savePreferences = async function (e) { - const {lang, iconsize, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail; + const {lang, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail; // Set background setBackground(bgcolor, bgurl); @@ -3899,9 +3516,6 @@ editor.init = () => { await setLang(langParam, langData); } - // set icon size - setIconSize(iconsize); - // set grid setting curConfig.gridSnapping = gridsnappingon; curConfig.snappingStep = gridsnappingstep; @@ -4631,8 +4245,8 @@ editor.init = () => { // Tooltips not directly associated with a single function const keyAssocs = { - '4/Shift+4': '#tools_rect_show', - '5/Shift+5': '#tools_ellipse_show' + '4/Shift+4': '#tools_rect', + '5/Shift+5': '#tools_ellipse' }; return { diff --git a/src/editor/svgicons/jQuery.svgIcons.js b/src/editor/svgicons/jQuery.svgIcons.js deleted file mode 100644 index 9f9499c5..00000000 --- a/src/editor/svgicons/jQuery.svgIcons.js +++ /dev/null @@ -1,544 +0,0 @@ -/** - * @file SVG Icon Loader 2.0 - * - * jQuery Plugin for loading SVG icons from a single file - * - * Adds {@link external:jQuery.svgIcons}, {@link external:jQuery.getSvgIcon}, {@link external:jQuery.resizeSvgIcons} - * - * How to use: - -1. Create the SVG master file that includes all icons: - -The master SVG icon-containing file is an SVG file that contains -`` elements. Each `` element should contain the markup of an SVG -icon. The `` element has an ID that should -correspond with the ID of the HTML element used on the page that should contain -or optionally be replaced by the icon. Additionally, one empty element should be -added at the end with id "svg_eof". - -2. Optionally create fallback raster images for each SVG icon. - -3. Include the jQuery and the SVG Icon Loader scripts on your page. - -4. Run `$.svgIcons()` when the document is ready. See its signature - -5. To access an icon at a later point without using the callback, use this: - `$.getSvgIcon(id (string), uniqueClone (boolean))`; - -This will return the icon (as jQuery object) with a given ID. - -6. To resize icons at a later point without using the callback, use this: - `$.resizeSvgIcons(resizeOptions)` (use the same way as the "resize" parameter) - * - * @module jQuerySVGIcons - * @license MIT - * @copyright (c) 2009 Alexis Deveria - * {@link http://a.deveria.com} - * @example - $(function () { - $.svgIcons('my_icon_set.svg'); // The SVG file that contains all icons - // No options have been set, so all icons will automatically be inserted - // into HTML elements that match the same IDs. - }); - - * @example - $(function () { - // The SVG file that contains all icons - $.svgIcons('my_icon_set.svg', { - callback (icons) { // Custom callback function that sets click - // events for each icon - $.each(icons, function (id, icon) { - icon.click(function () { - alert('You clicked on the icon with id ' + id); - }); - }); - } - }); - }); - - * @example - $(function () { - // The SVGZ file that contains all icons - $.svgIcons('my_icon_set.svgz', { - w: 32, // All icons will be 32px wide - h: 32, // All icons will be 32px high - fallback_path: 'icons/', // All fallback files can be found here - fallback: { - '#open_icon': 'open.png', // The "open.png" will be appended to the - // HTML element with ID "open_icon" - '#close_icon': 'close.png', - '#save_icon': 'save.png' - }, - placement: {'.open_icon': 'open'}, // The "open" icon will be added - // to all elements with class "open_icon" - resize: { - '#save_icon .svg_icon': 64 // The "save" icon will be resized to 64 x 64px - }, - - callback (icons) { // Sets background color for "close" icon - icons.close.css('background', 'red'); - }, - - svgz: true // Indicates that an SVGZ file is being used - }); - }); -*/ - -// Todo: Move to own module (and have it import a modular base64 encoder) -import {encode64} from '../../common/utilities.js'; - -const isOpera = Boolean(window.opera); - -const fixIDs = function (svgEl, svgNum, force) { - const defs = svgEl.find('defs'); - if (!defs.length) return svgEl; - - const idElems = (isOpera) - ? defs.find('*').filter(function () { - return Boolean(this.id); - }) - : defs.find('[id]'); - - const allElems = svgEl[0].getElementsByTagName('*'), - len = allElems.length; - - idElems.each(function (i) { - const {id} = this; - /* - const noDupes = ($(svgdoc).find('#' + id).length <= 1); - if (isOpera) noDupes = false; // Opera didn't clone svgEl, so not reliable - if(!force && noDupes) return; - */ - const newId = 'x' + id + svgNum + i; - this.id = newId; - - const oldVal = 'url(#' + id + ')'; - const newVal = 'url(#' + newId + ')'; - - // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 - // svgEl.find('[fill="url(#' + id + ')"]').each(function() { - // this.setAttribute('fill', 'url(#' + newId + ')'); - // }).end().find('[stroke="url(#' + id + ')"]').each(function() { - // this.setAttribute('stroke', 'url(#' + newId + ')'); - // }).end().find('use').each(function() { - // if(this.getAttribute('xlink:href') == '#' + id) { - // this.setAttributeNS(xlinkns,'href','#' + newId); - // } - // }).end().find('[filter="url(#' + id + ')"]').each(function() { - // this.setAttribute('filter', 'url(#' + newId + ')'); - // }); - - for (i = 0; i < len; i++) { - const elem = allElems[i]; - if (elem.getAttribute('fill') === oldVal) { - elem.setAttribute('fill', newVal); - } - if (elem.getAttribute('stroke') === oldVal) { - elem.setAttribute('stroke', newVal); - } - if (elem.getAttribute('filter') === oldVal) { - elem.setAttribute('filter', newVal); - } - } - }); - return svgEl; -}; - -/** -* @callback module:jQuerySVGIcons.SVGIconsLoadedCallback -* @param {PlainObject} svgIcons IDs keyed to jQuery objects of images -* @returns {void} -*/ - -/** - * @function module:jQuerySVGIcons.jQuerySVGIcons - * @param {external:jQuery} $ Its keys include all icon IDs and the values, the icon as a jQuery object - * @returns {external:jQuery} The enhanced jQuery object -*/ -export default function jQueryPluginSVGIcons ($) { - const svgIcons = {}; - - /** - * Map of raster images with each key being the SVG icon ID - * to replace, and the value the image file name. - * @typedef {PlainObject} external:jQuery.svgIcons.Fallback - */ - /** - * Map of raster images with each key being the SVG icon ID - * whose `alt` will be set, and the value being the `alt` text. - * @typedef {PlainObject} external:jQuery.svgIcons.Alts - */ - /** - * @function external:jQuery.svgIcons - * @param {string} file The location of a local SVG or SVGz file - * @param {PlainObject} [opts] - * @param {Float} [opts.w] The icon widths - * @param {Float} [opts.h] The icon heights - * @param {external:jQuery.svgIcons.Fallback} [opts.fallback] - * @param {string} [opts.fallback_path] The path to use for all images - * listed under "fallback" - * @param {boolean} [opts.replace] If set to `true`, HTML elements will - * be replaced by, rather than include the SVG icon. - * @param {PlainObject} [opts.placement] Map with selectors - * for keys and SVG icon ids as values. This provides a custom method of - * adding icons. - * @param {PlainObject} [opts.resize] Map - * with selectors for keys and numbers as values. This allows an easy way to - * resize specific icons. - * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A - * function to call when all icons have been loaded. - * @param {boolean} [opts.id_match=true] Automatically attempt to match - * SVG icon ids with corresponding HTML id - * @param {boolean} [opts.no_img] Prevent attempting to convert the icon - * into an `` element (may be faster, help for browser consistency) - * @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and - * thus not to parse as XML. SVGZ files add compression benefits, but - * getting data from them fails in Firefox 2 and older. - * @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key - * being the SVG icon ID whose `alt` will be set, and the value being - * the `alt` text - * @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image. - * In case wish to ensure have one for accessibility - * @returns {void} - */ - $.svgIcons = function (file, opts = {}) { - const svgns = 'http://www.w3.org/2000/svg', - xlinkns = 'http://www.w3.org/1999/xlink', - iconW = opts.w || 24, - iconH = opts.h || 24; - let elems, svgdoc, testImg, - iconsMade = false, - dataLoaded = false, - loadAttempts = 0; - const // ua = navigator.userAgent, - // isSafari = (ua.includes('Safari/') && !ua.includes('Chrome/')), - dataPre = 'data:image/svg+xml;charset=utf-8;base64,'; - - let dataEl; - if (opts.svgz) { - dataEl = $('').appendTo('body').hide(); - try { - svgdoc = dataEl[0].contentDocument; - dataEl.load(getIcons); - getIcons(0, true); // Opera will not run "load" event if file is already cached - } catch (err1) { - useFallback(); - } - } else { - const parser = new DOMParser(); - $.ajax({ - url: file, - dataType: 'string', - success (data) { - if (!data) { - $(useFallback); - return; - } - svgdoc = parser.parseFromString(data, 'text/xml'); - $(function () { - getIcons('ajax'); - }); - }, - error (err) { - // TODO: Fix Opera widget icon bug - if (window.opera) { - $(function () { - useFallback(); - }); - } else if (err.responseText) { - svgdoc = parser.parseFromString(err.responseText, 'text/xml'); - - if (!svgdoc.childNodes.length) { - $(useFallback); - } - $(function () { - getIcons('ajax'); - }); - } else { - $(useFallback); - } - } - }); - } - - /** - * - * @param {"ajax"|0|void} evt - * @param {boolean} [noWait] - * @returns {void} - */ - function getIcons (evt, noWait) { - if (evt !== 'ajax') { - if (dataLoaded) return; - // Webkit sometimes says svgdoc is undefined, other times - // it fails to load all nodes. Thus we must make sure the "eof" - // element is loaded. - svgdoc = dataEl[0].contentDocument; // Needed again for Webkit - const isReady = (svgdoc && svgdoc.getElementById('svg_eof')); - if (!isReady && !(noWait && isReady)) { - loadAttempts++; - if (loadAttempts < 50) { - setTimeout(getIcons, 20); - } else { - useFallback(); - dataLoaded = true; - } - return; - } - dataLoaded = true; - } - - elems = $(svgdoc.firstChild).children(); // .getElementsByTagName('foreignContent'); - - if (!opts.no_img) { - const testSrc = dataPre + - 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zd' + - 'mciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; - - testImg = $(new Image()).attr({ - src: testSrc, - width: 0, - height: 0, - alt: opts.testIconAlt || 'icon' - }).appendTo('body') - .load(function () { - // Safari 4 crashes, Opera and Chrome don't - makeIcons(true); - }).error(function () { - makeIcons(); - }); - } else { - setTimeout(function () { - if (!iconsMade) makeIcons(); - }, 500); - } - } - - /** - * - * @param {external:jQuery} target - * @param {external:jQuery} icon A wrapped `defs` or Image - * @param {string} id SVG icon ID - * @param {boolean} setID Whether to set the ID attribute (with `id`) - * @returns {void} - */ - function setIcon (target, icon, id, setID) { - if (isOpera) icon.css('visibility', 'hidden'); - if (opts.replace) { - if (setID) icon.attr('id', id); - const cl = target.attr('class'); - if (cl) icon.attr('class', 'svg_icon ' + cl); - if (!target.alt) { - let alt = 'icon'; - if (opts.alts) { - alt = opts.alts[id] || alt; - } - icon.attr('alt', alt); - } - target.replaceWith(icon); - } else { - target.append(icon); - } - if (isOpera) { - setTimeout(function () { - icon.removeAttr('style'); - }, 1); - } - } - - let holder; - /** - * @param {external:jQuery} icon A wrapped `defs` or Image - * @param {string} id SVG icon ID - * @returns {void} - */ - function addIcon (icon, id) { - if (opts.id_match === undefined || opts.id_match !== false) { - setIcon(holder, icon, id, true); - } - svgIcons[id] = icon; - } - - /** - * - * @param {boolean} [toImage] - * @param {external:jQuery.svgIcons.Fallback} [fallback=false] - * @returns {void} - */ - function makeIcons (toImage = false, fallback = false) { - if (iconsMade) return; - if (opts.no_img) toImage = false; - - let tempHolder; - if (toImage) { - tempHolder = $(document.createElement('div')); - tempHolder.hide().appendTo('body'); - } - if (fallback) { - const path = opts.fallback_path || ''; - $.each(fallback, function (id, imgsrc) { - holder = $('#' + id); - let alt = 'icon'; - if (opts.alts) { - alt = opts.alts[id] || alt; - } - const icon = $(new Image()) - .attr({ - class: 'svg_icon', - src: path + imgsrc, - width: iconW, - height: iconH, - alt - }); - - addIcon(icon, id); - }); - } else { - const len = elems.length; - for (let i = 0; i < len; i++) { - const elem = elems[i]; - const {id} = elem; - if (id === 'svg_eof') break; - holder = $('#' + id); - const svgroot = document.createElementNS(svgns, 'svg'); - // Per https://www.w3.org/TR/xml-names11/#defaulting, the namespace for - // attributes should have no value. - svgroot.setAttribute('viewBox', [0, 0, iconW, iconH].join(' ')); - - let svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; - - // Make flexible by converting width/height to viewBox - const w = svg.getAttribute('width'); - const h = svg.getAttribute('height'); - svg.removeAttribute('width'); - svg.removeAttribute('height'); - - const vb = svg.getAttribute('viewBox'); - if (!vb) { - svg.setAttribute('viewBox', [0, 0, w, h].join(' ')); - } - - // Not using jQuery to be a bit faster - svgroot.setAttribute('xmlns', svgns); - svgroot.setAttribute('width', iconW); - svgroot.setAttribute('height', iconH); - svgroot.setAttribute('xmlns:xlink', xlinkns); - svgroot.setAttribute('class', 'svg_icon'); - - // Without cloning, Firefox will make another GET request. - // With cloning, causes issue in Opera/Win/Non-EN - if (!isOpera) svg = svg.cloneNode(true); - - svgroot.append(svg); - - let icon; - if (toImage) { - tempHolder.empty().append(svgroot); - const str = dataPre + encode64(unescape(encodeURIComponent( - new XMLSerializer().serializeToString(svgroot) - ))); - let alt = 'icon'; - if (opts.alts) { - alt = opts.alts[id] || alt; - } - icon = $(new Image()) - .attr({class: 'svg_icon', src: str, alt}); - } else { - icon = fixIDs($(svgroot), i); - } - addIcon(icon, id); - } - } - - if (opts.placement) { - $.each(opts.placement, function (sel, id) { - if (!svgIcons[id]) return; - $(sel).each(function (i) { - let copy = svgIcons[id].clone(); - if (i > 0 && !toImage) copy = fixIDs(copy, i, true); - setIcon($(this), copy, id); - }); - }); - } - if (!fallback) { - if (toImage) tempHolder.remove(); - if (dataEl) dataEl.remove(); - if (testImg) testImg.remove(); - } - if (opts.resize) $.resizeSvgIcons(opts.resize); - iconsMade = true; - - if (opts.callback) opts.callback(svgIcons); - } - - /** - * @returns {void} - */ - function useFallback () { - if (file.includes('.svgz')) { - const regFile = file.replace('.svgz', '.svg'); - if (window.console) { - console.log('.svgz failed, trying with .svg'); // eslint-disable-line no-console - } - $.svgIcons(regFile, opts); - } else if (opts.fallback) { - makeIcons(false, opts.fallback); - } - } - }; - - /** - * @function external:jQuery.getSvgIcon - * @param {string} id - * @param {boolean} uniqueClone Whether to clone - * @returns {external:jQuery} The icon (optionally cloned) - */ - $.getSvgIcon = function (id, uniqueClone) { - let icon = svgIcons[id]; - if (uniqueClone && icon) { - icon = fixIDs(icon, 0, true).clone(true); - } - return icon; - }; - - /** - * @typedef {GenericArray} module:jQuerySVGIcons.Dimensions - * @property {Integer} length 2 - * @property {Float} 0 Width - * @property {Float} 1 Height - */ - - /** - * If a Float is used, it will represent width and height. Arrays contain - * the width and height. - * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size - */ - - /** - * @function external:jQuery.resizeSvgIcons - * @param {PlainObject} obj Object with - * selectors as keys. The values are sizes. - * @returns {void} - */ - $.resizeSvgIcons = function (obj) { - // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead - const changeSel = !$('.svg_icon:first').length; - $.each(obj, function (sel, size) { - const arr = Array.isArray(size); - const w = arr ? size[0] : size, - h = arr ? size[1] : size; - if (changeSel) { - sel = sel.replace(/\.svg_icon/g, 'svg'); - } - $(sel).each(function () { - this.setAttribute('width', w); - this.setAttribute('height', h); - if (window.opera && window.widget) { - this.parentNode.style.width = w + 'px'; - this.parentNode.style.height = h + 'px'; - } - }); - }); - }; - return $; -}