Merge branch 'V7-preview' into issues/39

master
JFH 2021-01-19 19:39:14 +01:00 committed by GitHub
commit 1312f8229d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 664 additions and 10 deletions

View File

@ -1,6 +1,6 @@
/* eslint-disable node/no-unpublished-import */
import 'elix/define/MenuButton.js';
import 'elix/define/MenuItem.js';
import './sePlainMenuButton.js';
const template = document.createElement('template');
template.innerHTML = `

View File

@ -0,0 +1,34 @@
/* eslint-disable node/no-unpublished-import */
import {template} from 'elix/src/base/internal.js';
import {fragmentFrom} from 'elix/src/core/htmlLiterals.js';
import PlainButton from 'elix/src/plain/PlainButton.js';
/**
* @class SePlainBorderButton
* Button with a border in the Plain reference design system
*
* @inherits PlainButton
*/
class SePlainBorderButton extends PlainButton {
/**
* @function get
* @returns {PlainObject}
*/
get [template] () {
const result = super[template];
result.content.append(
fragmentFrom.html`
<style>
[part~="button"] {
background: #72797A;
border: 1px solid #ccc;
padding: 0.25em 0.5em;
}
</style>
`
);
return result;
}
}
export default SePlainBorderButton;

View File

@ -0,0 +1,21 @@
/* eslint-disable node/no-unpublished-import */
import PlainMenuButton from 'elix/src/plain/PlainMenuButton.js';
import {defaultState} from 'elix/src/base/internal.js';
import sePlainBorderButton from './sePlainBorderButton.js';
/**
* @class ElixMenuButton
*/
export default class ElixMenuButton extends PlainMenuButton {
/**
* @function get
* @returns {PlainObject}
*/
get [defaultState] () {
return Object.assign(super[defaultState], {
sourcePartType: sePlainBorderButton
});
}
}
customElements.define('elix-menu-button', ElixMenuButton);

View File

@ -42,7 +42,8 @@ export class SePromptDialog extends HTMLElement {
}
break;
default:
// console.log('unkonw attr for:', name, 'newValue =', newValue);
// eslint-disable-next-line no-console
console.error('unknown attr for:', name, 'newValue =', newValue);
break;
}
}

View File

@ -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');
}
@ -508,7 +508,7 @@ export default {
buttons.push({
id: idPrefix + pos + '_' + id,
svgicon: id,
icon: 'markers-' + id + '.png',
icon: id + '.svg',
title,
type: 'context',
events: {click: setArrowFromButton},
@ -565,7 +565,7 @@ export default {
return {
name: strings.name,
svgicons: 'markers-icons.xml',
svgicons: '',
callback () {
$('#marker_panel').addClass('toolset').hide();
},
@ -595,7 +595,6 @@ export default {
},
elementChanged (opts) {
// console.log('elementChanged',opts);
const elem = opts.elems[0];
if (elem && (
elem.getAttribute('marker-start') ||

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="m-30,-30l0,60l60,0l0,-60z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 331 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m-30,-30l0,60l60,0l0,-60z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m-20,50l40,-100"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 318 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="m-50,0l100,40l-30,-40l30,-40z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m-50,0l100,40l-30,-40l30,-40z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<circle stroke-width="10" stroke="#f9bc01" fill="#f9bc01" cy="0" cx="0" r="30"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<circle stroke-width="10" stroke="#f9bc01" fill="none" cy="0" cx="0" r="30"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 321 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="m-50,0l100,0"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 318 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m-20,-50l40,100"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 318 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="m50,0l-100,40l30,-40l-30,-40z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m50,0l-100,40l30,-40l-30,-40z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m-40,-20l80,0l-70,60l30,-80l30,80z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 337 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<text xml:space="preserve" text-anchor="middle" font-family="serif" font-size="120" y="40" x="0" stroke-width="0" stroke="#f9bc01" fill="#f9bc01">T</text>
</svg></svg>

After

Width:  |  Height:  |  Size: 392 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="M-30,30 L0,-30 L30,30 Z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 329 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="M-30,30 L0,-30 L30,30 Z"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 326 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="none" d="m0,-50l0,100"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg_icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-60 -60 120 120">
<path stroke-width="10" stroke="#f9bc01" fill="#f9bc01" d="m-30,30l60,-60m0,60l-60,-60"/>
</svg></svg>

After

Width:  |  Height:  |  Size: 333 B

View File

@ -352,7 +352,7 @@
<se-spin-input size="3" id="opacity" min=0 max=100 step=5 title="Change selected item opacity" src="./images/opacity.svg"></se-spin-input>
<se-palette id="palette"></se-palette>
</div> <!-- tools_bottom -->
<div id="option_lists" class="dropdown"></div>
</div>
</body>

View File

@ -722,5 +722,8 @@ ul li.current {
z-index: 20001;
}
/* ------------ */
.dropdown li.tool_button {
width: 24px;
}

View File

@ -17,7 +17,7 @@
*/
import './touch.js';
import {isChrome, isMac} from '../common/browser.js';
import {isChrome, isMac, isTouch} from '../common/browser.js';
import {convertUnit, isValidUnit} from '../common/units.js';
import SvgCanvas from '../svgcanvas/svgcanvas.js';
@ -77,6 +77,7 @@ class Editor extends EditorStartup {
* @name module:SVGthis.uiStrings
* @type {PlainObject}
*/
this.flyoutFuncs = {};
this.uiStrings = {};
this.svgCanvas = null;
this.isReady = false;
@ -839,6 +840,271 @@ class Editor extends EditorStartup {
this.updateTitle();
}
/**
* Makes sure the current selected paint is available to work with.
* @returns {void}
*/
/* prepPaints () {
paintBox.fill.prep();
paintBox.stroke.prep();
} */
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
setFlyoutPositions () {
$('.tools_flyout').each(function () {
const shower = $('#' + this.id + '_show');
const {left, top} = shower.offset();
const w = shower.outerWidth();
this.css({left: (left + w) * editor.tool_scale, top});
});
}
/**
*
* @returns {void}
*/
// eslint-disable-next-line class-methods-use-this
setFlyoutTitles () {
$('.tools_flyout').each(function () {
const shower = $('#' + this.id + '_show');
if (shower.data('isLibrary')) {
return;
}
const tooltips = this.children().map(function () {
return this.title;
}).get();
shower[0].title = tooltips.join(' / ');
});
}
/**
* @param {PlainObject<string, module:SVGEditor.ToolButton>} holders Key is a selector
* @returns {void}
*/
setupFlyouts (holders) {
const allHolders = {};
$.each(holders, function (holdSel, btnOpts) {
if (!allHolders[holdSel]) {
allHolders[holdSel] = [];
}
allHolders[holdSel].push(...btnOpts);
const buttons = $(holdSel).children().not('.tool_button_evt_handled');
const showSel = holdSel + '_show';
const shower = $(showSel);
let def = false;
buttons.addClass('tool_button tool_button_evt_handled')
.unbind('click mousedown mouseup') // may not be necessary
.each(function () {
// Get this button's options
const idSel = '#' + this.getAttribute('id');
const [i, opts] = Object.entries(btnOpts).find(([_, {sel}]) => {
return sel === idSel;
});
// Remember the function that goes with this ID
this.flyoutFuncs[opts.sel] = opts.fn;
if (opts.isDefault) { def = i; }
const flyoutAction = function (ev) {
let options = opts;
// Find the currently selected tool if comes from keystroke
if (ev.type === 'keydown') {
const flyoutIsSelected = $(options.parent + '_show').hasClass('tool_button_current');
const currentOperation = $(options.parent + '_show').attr('data-curopt');
Object.entries(holders[opts.parent]).some(([j, tool]) => {
if (tool.sel !== currentOperation) {
return false;
}
if (!ev.shiftKey || !flyoutIsSelected) {
options = tool;
} else {
// If flyout is selected, allow shift key to iterate through subitems
j = Number.parseInt(j);
// Use `allHolders` to include both extension `includeWith` and toolbarButtons
options = allHolders[opts.parent][j + 1] ||
holders[opts.parent][0];
}
return true;
});
}
if ($(this).hasClass('disabled')) { return false; }
/* if (toolButtonClick(showSel)) {
options.fn();
} */
const icon = (options.icon) ? $.getSvgIcon(options.icon, true) : $(options.sel).children().eq(0).clone();
icon[0].setAttribute('width', shower.width());
icon[0].setAttribute('height', shower.height());
shower.children(':not(.flyout_arrow_horiz)').remove();
shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode
return true;
};
$(this).mouseup(flyoutAction);
if (opts.key) {
$(document).bind('keydown', opts.key[0] + ' shift+' + opts.key[0], flyoutAction);
}
return true;
});
if (def) {
shower.attr('data-curopt', btnOpts[def].sel);
} else if (!shower.attr('data-curopt')) {
// Set first as default
shower.attr('data-curopt', btnOpts[0].sel);
}
let timer;
// Clicking the "show" icon should set the current mode
shower.mousedown(function (evt) {
if (shower.hasClass('disabled')) {
return false;
}
const holder = $(holdSel);
const pos = $(showSel).position();
const l = pos.left + 34;
const w = holder.width() * -1;
const time = holder.data('shown_popop') ? 200 : 0;
timer = setTimeout(function () {
// Show corresponding menu
if (!shower.data('isLibrary')) {
holder.css('left', w).show().animate({
left: l
}, 150);
} else {
holder.css('left', l).show();
}
holder.data('shown_popop', true);
}, time);
evt.preventDefault();
return true;
}).mouseup(function (evt) {
clearTimeout(timer);
/* const opt = $(this).attr('data-curopt');
// Is library and popped up, so do nothing
if (shower.data('isLibrary') && $(showSel.replace('_show', '')).is(':visible')) {
toolButtonClick(showSel, true);
return;
}
if (toolButtonClick(showSel) && this.flyoutFuncs[opt]) {
this.flyoutFuncs[opt]();
} */
});
// $('#tools_rect').mouseleave(function () { $('#tools_rect').fadeOut(); });
});
this.setFlyoutTitles();
// this.setFlyoutPositions();
}
/**
* @param {string} id
* @param {external:jQuery} child
* @returns {external:jQuery}
*/
// eslint-disable-next-line class-methods-use-this
makeFlyoutHolder (id, child) {
const div = $('<div>', {
class: 'tools_flyout',
id
}).appendTo('#svg_editor').append(child);
return div;
}
/**
* @function module:SVGEditor.setIcon
* @param {string|Element|external:jQuery} elem
* @param {string|external:jQuery} iconId
* @returns {void}
*/
setIcon (elem, iconId) {
// eslint-disable-next-line max-len
const icon = (typeof iconId === 'string') ? $('<img src="' + this.configObj.curConfig.imgPath + iconId + '">') : 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);
}
/**
* @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}
*/
addAltDropDown (elemSel, listSel, callback, opts) {
// eslint-disable-next-line no-shadow
const self = this;
const button = $(elemSel);
const {dropUp} = opts;
const list = $(listSel);
if (dropUp) {
$(elemSel).addClass('dropup');
}
list.find('li').bind('mouseup', function (...args) {
if (opts.seticon) {
self.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
@ -846,6 +1112,9 @@ class Editor extends EditorStartup {
* @returns {Promise<void>|void} Resolves to `undefined`
*/
async extAdded (win, ext) {
// eslint-disable-next-line no-shadow
const self = this;
const btnSelects = [];
if (!ext) {
return undefined;
}
@ -921,7 +1190,9 @@ class Editor extends EditorStartup {
break;
} case 'button-select': {
html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">' +
'<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>';
'<div id="cur_' + tool.id + '" class="icon_label"></div>' +
'<button><img class="svg_icon" src="./images/arrow_down.svg" alt="icon" width="7" height="7"></button>' +
'</div>';
const list = $('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists');
@ -931,6 +1202,13 @@ class Editor extends EditorStartup {
// 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 = '<label' + contId + '>' +
@ -956,7 +1234,274 @@ class Editor extends EditorStartup {
}
});
}
const {svgicons} = ext;
if (ext.buttons) {
const fallbackObj = {},
altsObj = {},
placementObj = {},
holders = {};
/**
* @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<string, external:jQuery.Function>|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 {PlainObject} [includeWith] Object with flyout menu data
* @property {boolean} [includeWith.isDefault] Indicates whether button is default in flyout list or not.
* @property {string} includeWith.button jQuery selector of the existing button to be joined. Example: '#tool_line'. Required if `includeWith` is used.
* @property {"last"|Integer} [includeWith.position] Position of icon in flyout list; will be added to end if not indicated. Integer is for use with {@link http://api.jquery.com/eq/}.
* @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 = $(
'<img src="' + self.configObj.curConfig.imgPath + btn.icon +
(btn.title ? '" alt="' + 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) {
$('<div>', {id: btn.panel}).appendTo('#tools_top');
}
break;
case 'app_menu':
cls = '';
parent = '#main_menu ul';
break;
}
// refData
let flyoutHolder, showBtn, refBtn;
const button = $((btn.list || btn.type === 'app_menu') ? '<li/>' : '<div/>')
.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 === 'mode_flyout') {
// Add to flyout menu / make flyout menu
// const opts = btn.includeWith;
// // opts.button, default, position
refBtn = $(button);
flyoutHolder = refBtn.parent();
// Create a flyout menu if there isn't one already
let tlsId;
if (!refBtn.parent().hasClass('tools_flyout')) {
// Create flyout placeholder
tlsId = refBtn[0].id.replace('tool_', 'tools_');
showBtn = refBtn.clone()
.attr('id', tlsId + '_show')
.append($('<div>', {class: 'flyout_arrow_horiz'}));
refBtn.before(showBtn);
// Create a flyout div
flyoutHolder = self.makeFlyoutHolder(tlsId, refBtn);
flyoutHolder.data('isLibrary', true);
showBtn.data('isLibrary', true);
}
// refData = Actions.getButtonData(opts.button);
placementObj['#' + tlsId + '_show'] = btn.id;
// TODO: Find way to set the current icon using the iconloader if this is not default
// Include data for extension button as well as ref button
/* curH = */ holders['#' + flyoutHolder[0].id] = [{
sel: '#' + id,
fn: btn.events.click,
icon: btn.id,
// key: btn.key,
isDefault: true
}]; // , refData
//
// // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'}
//
// const pos = ('position' in opts)?opts.position:'last';
// const len = flyoutHolder.children().length;
//
// // Add at given position or end
// if (!isNaN(pos) && pos >= 0 && pos < len) {
// flyoutHolder.children().eq(pos).before(button);
// } else {
// flyoutHolder.append(button);
// curH.reverse();
// }
} else if (btn.type === 'app_menu') {
button.append('<div>').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;
}
} else if (btn.includeWith) {
// Add to flyout menu / make flyout menu
const opts = btn.includeWith;
// opts.button, default, position
refBtn = $(opts.button);
flyoutHolder = refBtn.parent();
// Create a flyout menu if there isn't one already
let tlsId;
if (!refBtn.parent().hasClass('tools_flyout')) {
// Create flyout placeholder
tlsId = refBtn[0].id.replace('tool_', 'tools_');
showBtn = refBtn.clone()
.attr('id', tlsId + '_show')
.append($('<div>', {class: 'flyout_arrow_horiz'}));
refBtn.before(showBtn);
// Create a flyout div
flyoutHolder = self.makeFlyoutHolder(tlsId, refBtn);
}
// refData = Actions.getButtonData(opts.button);
if (opts.isDefault) {
placementObj['#' + tlsId + '_show'] = btn.id;
}
// TODO: Find way to set the current icon using the iconloader if this is not default
// Include data for extension button as well as ref button
/* const curH = */ holders['#' + flyoutHolder[0].id] = [{
sel: '#' + id,
fn: btn.events.click,
icon: btn.id,
key: btn.key,
isDefault: Boolean(btn.includeWith && btn.includeWith.isDefault)
}]; // , refData
// {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'}
const pos = ('position' in opts) ? opts.position : 'last';
const len = flyoutHolder.children().length;
// Add at given position or end
if (!isNaN(pos) && pos >= 0 && pos < len) {
flyoutHolder.children().eq(pos).before(button);
} else {
flyoutHolder.append(button);
// curH.reverse();
}
}
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 (toolButtonClick(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);
}
});
}
self.setupFlyouts(holders);
});
$.each(btnSelects, function () {
self.addAltDropDown(this.elem, this.list, this.callback, {seticon: true});
});
/* if (svgicons) {
return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new
$.svgIcons(`${this.configObj.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.events) {
this.leftPanelHandlers.add(ext.events.id, ext.events.click);
}