progress on spin button

master
JFH 2020-11-21 17:11:13 +01:00
parent 9b464b7a32
commit c8a2b70ed4
8 changed files with 24 additions and 389 deletions

View File

@ -74,7 +74,6 @@ class Dropdown extends ListComboBox {
*/
attributeChangedCallback (name, oldValue, newValue) {
if (oldValue === newValue) return;
console.log({this: this, name, oldValue, newValue});
switch (name) {
case 'title':
// this.$span.setAttribute('title', `${newValue} ${shortcut ? `[${shortcut}]` : ''}`);

View File

@ -242,7 +242,6 @@ export class ExplorerButton extends HTMLElement {
connectedCallback () {
// capture click event on the button to manage the logic
const onClickHandler = (ev) => {
console.log(ev.target);
ev.stopPropagation();
switch (ev.target.nodeName) {
case 'SE-EXPLORERBUTTON':

View File

@ -18,6 +18,9 @@ template.innerHTML = `
right: -4px;
position: relative;
}
elix-number-spin-box::part(spin-button) {
padding: 0px;
}
</style>
<img src="./images/logo.svg" alt="icon" width="12" height="12" />
<span id="label">label</span>
@ -47,7 +50,7 @@ export class SESpinInput extends HTMLElement {
* @returns {any} observed
*/
static get observedAttributes () {
return ['value', 'label', 'src', 'size'];
return ['value', 'label', 'src', 'size', 'min', 'max', 'step'];
}
/**
* @function attributeChangedCallback
@ -57,6 +60,7 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
attributeChangedCallback (name, oldValue, newValue) {
console.log(name, newValue);
if (oldValue === newValue) return;
switch (name) {
case 'src':
@ -64,7 +68,10 @@ export class SESpinInput extends HTMLElement {
this.$label.remove();
break;
case 'size':
this.$input.setAttribute('size', newValue);
// access to the underlying input box
this.$input.shadowRoot.getElementById('input').size = newValue;
// below seems mandatory to override the default width style that takes precedence on size
this.$input.shadowRoot.getElementById('input').style.width = 'unset';
break;
case 'step':
this.$input.setAttribute('step', newValue);
@ -155,11 +162,16 @@ export class SESpinInput extends HTMLElement {
* @returns {void}
*/
connectedCallback () {
this.addEventListener('change', (e) => {
this.$input.addEventListener('change', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
this.$input.addEventListener('click', (e) => {
e.preventDefault();
this.value = e.target.value;
this.dispatchEvent(this.$event);
});
this.dispatchEvent(this.$event);
}
}

View File

@ -150,7 +150,7 @@
<se-input id="elem_id" data-attr="id" size="10" label="id:" title="Identify the element"></se-input>
<se-input id="elem_class" data-attr="class" size="10" label="class:" title="Element class"></se-input>
</div>
<se-spin-input id="angle" min=-180 max=180 step=5 src="./images/angle.svg" title="Change rotation angle"></se-spin-input>
<se-spin-input size="3" id="angle" min=-180 max=180 step=5 src="./images/angle.svg" title="Change rotation angle"></se-spin-input>
<div class="toolset" id="tool_blur" title="Change gaussian blur value">
<label>
<span id="blurLabel" class="icon_label"></span>
@ -204,7 +204,7 @@
<se-input id="rect_width" data-attr="width" size="4" src="./images/width.svg" title="Change rectangle width"></se-input>
<se-input id="rect_height" data-attr="height" size="4" src="./images/height.svg" title="Change rectangle height"></se-input>
</div>
<se-spin-input id="rect_rx" min=0 max=1000 step=1 title="Change Rectangle Corner Radius" data-attr="Corner Radius" src="./images/c_radius.svg"></se-spin-input>
<se-spin-input id="rect_rx" min=0 max=1000 step=1 size="3" title="Change Rectangle Corner Radius" data-attr="Corner Radius" src="./images/c_radius.svg"></se-spin-input>
</div>
<div id="image_panel">
<div class="toolset">
@ -275,7 +275,7 @@
</ul>
</div>
</div>
<se-spin-input id="font_size" min=1 max=1000 step=1 title="Change Font Size" src="./images/fontsize.svg"></se-spin-input>
<se-spin-input size="2" id="font_size" min=1 max=1000 step=1 title="Change Font Size" src="./images/fontsize.svg"></se-spin-input>
<!-- Not visible, but still used -->
<input id="text" type="text" size="35" />
</div>
@ -375,7 +375,7 @@
<div id="stroke_bg"></div>
<div id="stroke_color" class="color_block" title="Change stroke color"></div>
</div>
<se-spin-input id="stroke_width" min=0 max=99 step=0.1 title="Change stroke width by 1, shift-click to change by 0.1"></se-spin-input>
<se-spin-input id="stroke_width" min=0 max=99 step=1 title="Change stroke width by 1"></se-spin-input>
<div id="toggle_stroke_tools" title="Show/hide more stroke tools"></div>
<label class="stroke_tool">
<select id="stroke_style" title="Change stroke dash style">

View File

@ -1,41 +0,0 @@
/*
Styles to make ordinary <INPUT type="text"/> look like a spinbutton/spinbox control.
Use with jQuery.SpinButton.js to provide the spin functionality by reacting to mouse etc.
(Requires a reference to the JQuery library found at http://code.jquery.com/)
(Hats-off to John Resig for creating the excellent JQuery library. It is fab.)
This control is achieved with no extra html markup whatsoever and uses unobtrusive javascript.
Written by George Adamson, Software Unity (george.jquery@softwareunity.com) September 2006.
Big improvements added by Mark Gibson, (mgibson@designlinks.net) September 2006.
Do contact me with comments and suggestions but please don't ask for support.
As much as I'd love to help with specific problems I have plenty to get on with already!
Go ahead and use it in your own projects. This code is provided 'as is'.
Sure I've tested in heaps of ways. Its good for me, but you use it at your own risk.
SoftwareUnity and I are certainly not responsible if your computer sets fire to the sofa,
hacks into the pentagon, hijacks a plane or gives you any kind of hassle whatsoever.
If you'd like your spin-button image in a different place then you'll need to alter both
the CSS below and the javascript isMouseOverUpDn() function to accommodate the new position.
You could even have left and right buttons either side of the textbox.
*/
INPUT.spin-button {
/* explicitly put padding for top/bottom/left in here so that Opera displays it better */
padding: 2px 20px 2px 2px;
background-repeat:no-repeat; /* Warning: Img may disappear in Firefox if you use 'background-attachment:fixed' ! */
background-position:100% 0%;
background-image:url('spinbtn_updn.png');
background-color:white; /* Needed for Opera */
}
INPUT.spin-button.up { /* Change button img when mouse is over the UP-arrow */
cursor:pointer;
background-position:100% -18px; /* 18px matches height of 2 visible buttons */
}
INPUT.spin-button.down { /* Change button img when mouse is over the DOWN-arrow */
cursor:pointer;
background-position:100% -36px; /* 36px matches height of 2x2 visible buttons */
}

View File

@ -1,328 +0,0 @@
/**
* SpinButton control.
*
* Adds bells and whistles to any ordinary textbox to
* make it look and feel like a SpinButton Control.
*
* Supplies {@link external:jQuery.fn.SpinButton}).
*
* Originally written by George Adamson, Software Unity (george.jquery@softwareunity.com) August 2006:
* - Added min/max options.
* - Added step size option.
* - Added bigStep (page up/down) option.
*
* Modifications made by Mark Gibson, (mgibson@designlinks.net) September 2006:
* - Converted to jQuery plugin.
* - Allow limited or unlimited min/max values.
* - Allow custom class names, and add class to input element.
* - Removed global vars.
* - Reset (to original or through config) when invalid value entered.
* - Repeat whilst holding mouse button down (with initial pause, like keyboard repeat).
* - Support mouse wheel in Firefox.
* - Fix double click in IE.
* - Refactored some code and renamed some vars.
*
* Modifications by Jeff Schiller, June 2009:
* - provide callback function for when the value changes based on the following
* {@link https://www.mail-archive.com/jquery-en@googlegroups.com/msg36070.html}.
*
* Modifications by Jeff Schiller, July 2009:
* - improve styling for widget in Opera.
* - consistent key-repeat handling cross-browser.
*
* Modifications by Alexis Deveria, October 2009:
* - provide "stepfunc" callback option to allow custom function to run when changing a value.
* - Made adjustValue(0) only run on certain keyup events, not all.
*
* Tested in IE6, Opera9, Firefox 1.5.
*
* | Version | Date | Author | Notes |
* |---------|------|--------|-------|
* | v1.0 | 11 Aug 2006 | George Adamson | First release |
* | v1.1 | Aug 2006 | George Adamson | Minor enhancements |
* | v1.2 | 27 Sep 2006 | Mark Gibson | Major enhancements |
* | v1.3a | 28 Sep 2006 | George Adamson | Minor enhancements |
* | v1.4 | 18 Jun 2009 | Jeff Schiller | Added callback function |
* | v1.5 | 06 Jul 2009 | Jeff Schiller | Fixes for Opera. |
* | v1.6 | 13 Oct 2009 | Alexis Deveria | Added stepfunc function |
* | v1.7 | 21 Oct 2009 | Alexis Deveria | Minor fixes.<br />Fast-repeat for keys and live updating as you type. |
* | v1.8 | 12 Jan 2010 | Benjamin Thomas | Fixes for mouseout behavior.<br />Added smallStep |
* | v1.9 | 20 May 2018 | Brett Zamir | Avoid SVGEdit dependency via `stateObj` config;<br />convert to ES6 module |
* .
*
* @module jQuerySpinButton
* @example
// Create group of settings to initialise spinbutton(s). (Optional)
const myOptions = {
min: 0, // Set lower limit.
max: 100, // Set upper limit.
step: 1, // Set increment size.
smallStep: 0.5, // Set shift-click increment size.
stateObj: {tool_scale: 1}, // Object to allow passing in live-updating scale
spinClass: mySpinBtnClass, // CSS class to style the spinbutton. (Class also specifies url of the up/down button image.)
upClass: mySpinUpClass, // CSS class for style when mouse over up button.
downClass: mySpinDnClass // CSS class for style when mouse over down button.
};
$(function () {
// Initialise INPUT element(s) as SpinButtons: (passing options if desired)
$('#myInputElement').SpinButton(myOptions);
});
*/
/**
* @function module:jQuerySpinButton.jQuerySpinButton
* @param {external:jQuery} $ The jQuery object to which to add the plug-in
* @returns {external:jQuery}
*/
export default function jQueryPluginSpinButton ($) {
/**
* @callback module:jQuerySpinButton.StepCallback
* @param {external:jQuery} thisArg Value of `this`
* @param {Float} i Value to adjust
* @returns {Float}
*/
/**
* @callback module:jQuerySpinButton.ValueCallback
* @param {external:jQuery.fn.SpinButton} thisArg Spin Button; check its `value` to see how it was changed.
* @returns {void}
*/
/**
* @typedef {PlainObject} module:jQuerySpinButton.SpinButtonConfig
* @property {Float} min Set lower limit
* @property {Float} max Set upper limit.
* @property {Float} step Set increment size.
* @property {module:jQuerySpinButton.StepCallback} stepfunc Custom function to run when changing a value; called with `this` of object and the value to adjust and returns a float.
* @property {module:jQuerySpinButton.ValueCallback} callback Called after value adjusted (with `this` of object)
* @property {Float} smallStep Set shift-click increment size.
* @property {PlainObject} stateObj Object to allow passing in live-updating scale
* @property {Float} stateObj.tool_scale
* @property {string} spinClass CSS class to style the spinbutton. (Class also specifies url of the up/down button image.)
* @property {string} upClass CSS class for style when mouse over up button.
* @property {string} downClass CSS class for style when mouse over down button.
* @property {Float} page Value to be adjusted on page up/page down
* @property {Float} reset Reset value when invalid value entered
* @property {Float} delay Millisecond delay
* @property {Float} interval Millisecond interval
*/
/**
* @function external:jQuery.fn.SpinButton
* @param {module:jQuerySpinButton.SpinButtonConfig} cfg
* @returns {external:jQuery}
*/
$.fn.SpinButton = function (cfg) {
cfg = cfg || {};
/**
*
* @param {Element} el
* @param {"offsetLeft"|"offsetTop"} prop
* @returns {Integer}
*/
function coord (el, prop) {
const b = document.body;
let c = el[prop];
while ((el = el.offsetParent) && (el !== b)) {
if (!$.browser.msie || (el.currentStyle.position !== 'relative')) {
c += el[prop];
}
}
return c;
}
return this.each(function () {
this.repeating = false;
// Apply specified options or defaults:
// (Ought to refactor this some day to use $.extend() instead)
this.spinCfg = {
// min: cfg.min ? Number(cfg.min) : null,
// max: cfg.max ? Number(cfg.max) : null,
min: !isNaN(Number.parseFloat(cfg.min)) ? Number(cfg.min) : null, // Fixes bug with min:0
max: !isNaN(Number.parseFloat(cfg.max)) ? Number(cfg.max) : null,
step: cfg.step ? Number(cfg.step) : 1,
stepfunc: cfg.stepfunc || false,
page: cfg.page ? Number(cfg.page) : 10,
upClass: cfg.upClass || 'up',
downClass: cfg.downClass || 'down',
reset: cfg.reset || this.value,
delay: cfg.delay ? Number(cfg.delay) : 500,
interval: cfg.interval ? Number(cfg.interval) : 100,
_btn_width: 20,
_direction: null,
_delay: null,
_repeat: null,
callback: cfg.callback || null
};
// if a smallStep isn't supplied, use half the regular step
this.spinCfg.smallStep = cfg.smallStep || this.spinCfg.step / 2;
this.adjustValue = function (i) {
let v;
if (isNaN(this.value)) {
v = this.spinCfg.reset;
} else if (typeof this.spinCfg.stepfunc === 'function') {
v = this.spinCfg.stepfunc(this, i);
} else {
// weirdest JavaScript bug ever: 5.1 + 0.1 = 5.199999999
v = Number((Number(this.value) + Number(i)).toFixed(5));
}
if (this.spinCfg.min !== null) { v = Math.max(v, this.spinCfg.min); }
if (this.spinCfg.max !== null) { v = Math.min(v, this.spinCfg.max); }
this.value = v;
if (typeof this.spinCfg.callback === 'function') {
this.spinCfg.callback(this);
}
};
$(this)
.addClass(cfg.spinClass || 'spin-button')
.mousemove(function (e) {
// Determine which button mouse is over, or not (spin direction):
const x = e.pageX || e.x;
const y = e.pageY || e.y;
const el = e.target;
const scale = cfg.stateObj.tool_scale || 1;
const height = $(el).height() / 2;
const direction =
(x > coord(el, 'offsetLeft') +
el.offsetWidth * scale - this.spinCfg._btn_width)
? ((y < coord(el, 'offsetTop') + height * scale) ? 1 : -1)
: 0;
if (direction !== this.spinCfg._direction) {
// Style up/down buttons:
switch (direction) {
case 1: // Up arrow:
$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass);
break;
case -1: // Down arrow:
$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);
break;
default: // Mouse is elsewhere in the textbox
$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
}
// Set spin direction:
this.spinCfg._direction = direction;
}
})
.mouseout(function () {
// Reset up/down buttons to their normal appearance when mouse moves away:
$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);
this.spinCfg._direction = null;
window.clearInterval(this.spinCfg._repeat);
window.clearTimeout(this.spinCfg._delay);
})
.mousedown(function (e) {
if (e.button === 0 && this.spinCfg._direction !== 0) {
// Respond to click on one of the buttons:
const stepSize = e.shiftKey ? this.spinCfg.smallStep : this.spinCfg.step;
const adjust = () => {
this.adjustValue(this.spinCfg._direction * stepSize);
};
adjust();
// Initial delay before repeating adjustment
this.spinCfg._delay = window.setTimeout(() => {
adjust();
// Repeat adjust at regular intervals
this.spinCfg._repeat = window.setInterval(adjust, this.spinCfg.interval);
}, this.spinCfg.delay);
}
})
.mouseup(function (e) {
// Cancel repeating adjustment
window.clearInterval(this.spinCfg._repeat);
window.clearTimeout(this.spinCfg._delay);
})
.dblclick(function (e) {
if ($.browser.msie) {
this.adjustValue(this.spinCfg._direction * this.spinCfg.step);
}
})
.keydown(function (e) {
// Respond to up/down arrow keys.
switch (e.keyCode) {
case 38: this.adjustValue(this.spinCfg.step); break; // Up
case 40: this.adjustValue(-this.spinCfg.step); break; // Down
case 33: this.adjustValue(this.spinCfg.page); break; // PageUp
case 34: this.adjustValue(-this.spinCfg.page); break; // PageDown
}
})
/*
http://unixpapa.com/js/key.html describes the current state-of-affairs for
key repeat events:
- Safari 3.1 changed their model so that keydown is reliably repeated going forward
- Firefox and Opera still only repeat the keypress event, not the keydown
*/
.keypress(function (e) {
if (this.repeating) {
// Respond to up/down arrow keys.
switch (e.keyCode) {
case 38: this.adjustValue(this.spinCfg.step); break; // Up
case 40: this.adjustValue(-this.spinCfg.step); break; // Down
case 33: this.adjustValue(this.spinCfg.page); break; // PageUp
case 34: this.adjustValue(-this.spinCfg.page); break; // PageDown
}
// we always ignore the first keypress event (use the keydown instead)
} else {
this.repeating = true;
}
})
// clear the 'repeating' flag
.keyup(function (e) {
this.repeating = false;
switch (e.keyCode) {
case 38: // Up
case 40: // Down
case 33: // PageUp
case 34: // PageDown
case 13: this.adjustValue(0); break; // Enter/Return
}
})
.bind('mousewheel', function (e) {
// Respond to mouse wheel in IE. (It returns up/dn motion in multiples of 120)
if (e.wheelDelta >= 120) {
this.adjustValue(this.spinCfg.step);
} else if (e.wheelDelta <= -120) {
this.adjustValue(-this.spinCfg.step);
}
e.preventDefault();
})
.change(function (e) {
this.adjustValue(0);
});
if (this.addEventListener) {
// Respond to mouse wheel in Firefox
this.addEventListener('DOMMouseScroll', function (e) {
if (e.detail > 0) {
this.adjustValue(-this.spinCfg.step);
} else if (e.detail < 0) {
this.adjustValue(this.spinCfg.step);
}
e.preventDefault();
});
}
});
};
return $;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 B

View File

@ -36,7 +36,6 @@ 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 jQueryPluginSpinButton from './spinbtn/jQuery.SpinButton.js';
import jQueryPluginContextMenu from './contextmenu/jQuery.contextMenu.js';
import jQueryPluginJPicker from './jgraduate/jQuery.jPicker.js';
import jQueryPluginDBox from '../svgcanvas/dbox.js';
@ -52,7 +51,7 @@ const editor = {};
const $ = [
jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate,
jQueryPluginSpinButton, jQueryPluginContextMenu, jQueryPluginJPicker
jQueryPluginContextMenu, jQueryPluginJPicker
].reduce((jq, func) => func(jq), jQuery);
const homePage = 'https://github.com/SVG-Edit/svgedit';
@ -64,7 +63,7 @@ const homePage = 'https://github.com/SVG-Edit/svgedit';
/**
* @type {Float}
*/
editor.tool_scale = 1; // Dependent on icon size, so any use to making configurable instead? Used by `jQuery.SpinButton.js`
editor.tool_scale = 1;
/**
* @type {Integer}
*/
@ -2336,7 +2335,7 @@ editor.init = () => {
};
/**
* @type {module:jQuerySpinButton.ValueCallback}
* @type {module}
*/
const changeZoom = (value) => {
switch (value) {
@ -2548,7 +2547,6 @@ editor.init = () => {
* @property {string|Integer} [colnum] Added as part of the option list class.
* @property {string} [label] Label associated with the tool, visible in the UI
* @property {Integer} [size] Value of the "size" attribute of the tool input
* @property {module:jQuerySpinButton.SpinButtonConfig} [spindata] When added to a tool of type "input", this tool becomes a "spinner" which allows the number to be in/decreased.
*/
if (ext.context_tools) {
$.each(ext.context_tools, function (i, tool) {
@ -2623,10 +2621,6 @@ editor.init = () => {
// Add to given tool.panel
const inp = $(html).appendTo(panel).find('input');
if (tool.spindata) {
inp.SpinButton(tool.spindata);
}
if (tool.events) {
$.each(tool.events, function (evt, func) {
inp.bind(evt, func);
@ -2919,7 +2913,7 @@ editor.init = () => {
$('#image_save_opts input').val([editor.pref('img_save')]);
/**
* @type {module:jQuerySpinButton.ValueCallback}
* @type {module}
*/
const changeRectRadius = function (e) {
svgCanvas.setRectRadius(e.target.value);