diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 56bc599..b98e54a 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -344,6 +344,19 @@ input[type=range]:disabled { flex: 1; } +.webrx-actual-freq .input-group { + display: flex; + flex-direction: row; +} + +.webrx-actual-freq .input-group > * { + flex: 0 0 auto; +} + +.webrx-actual-freq .input-group input { + flex: 1 0 auto; +} + .webrx-actual-freq input { font-family: 'roboto-mono'; width: 0; diff --git a/htdocs/lib/FrequencyDisplay.js b/htdocs/lib/FrequencyDisplay.js index aecc03f..777b975 100644 --- a/htdocs/lib/FrequencyDisplay.js +++ b/htdocs/lib/FrequencyDisplay.js @@ -71,14 +71,21 @@ TuneableFrequencyDisplay.prototype = new FrequencyDisplay(); TuneableFrequencyDisplay.prototype.setupElements = function() { FrequencyDisplay.prototype.setupElements.call(this); this.input = $(''); - this.input.hide(); - this.element.append(this.input); + this.prefixInput = $(''); + this.prefixInput.append($('Hz')); + this.prefixInput.append($.map(this.prefixes, function(e, p) { + return $('' + p + 'Hz'); + })); + this.inputGroup = $(''); + this.inputGroup.append([this.input, this.prefixInput]); + this.inputGroup.hide(); + this.element.append(this.inputGroup); }; TuneableFrequencyDisplay.prototype.setupEvents = function() { var me = this; - me.element.on('wheel', function(e){ + me.displayContainer.on('wheel', function(e){ e.preventDefault(); e.stopPropagation(); @@ -93,26 +100,59 @@ TuneableFrequencyDisplay.prototype.setupEvents = function() { }); var submit = function(){ - var freq = parseInt(me.input.val()); + var exponent = parseInt(me.prefixInput.val()); + var freq = parseFloat(me.input.val()) * 10 ** exponent; if (!isNaN(freq)) { me.element.trigger('frequencychange', freq); } - me.input.hide(); + me.inputGroup.hide(); me.displayContainer.show(); }; - me.input.on('blur', submit).on('keyup', function(e){ + $inputs = $.merge($(), me.input); + $inputs = $.merge($inputs, me.prefixInput); + $inputs.on('blur', function(e){ + if ($inputs.toArray().indexOf(e.relatedTarget) >= 0) { + return; + } + submit(); + }); + me.input.on('keydown', function(e){ if (e.keyCode == 13) return submit(); if (e.keyCode == 27) { - me.input.hide(); + me.inputGroup.hide(); me.displayContainer.show(); + return; } + var c = String.fromCharCode(e.which); + Object.entries(me.prefixes).forEach(function(e) { + if (e[0].toUpperCase() == c) { + me.prefixInput.val(e[1]); + return submit(); + } + }) }); - me.input.on('click', function(e){ + var currentExponent; + me.prefixInput.on('change', function() { + var newExponent = me.prefixInput.val(); + delta = currentExponent - newExponent; + if (delta >= 0) { + me.input.val(parseFloat(me.input.val()) * 10 ** delta); + } else { + // should not be necessary to handle this separately, but floating point precision in javascript + // does not handle this well otherwise + me.input.val(parseFloat(me.input.val()) / 10 ** -delta); + } + currentExponent = newExponent; + me.input.focus(); + }); + $inputs.on('click', function(e){ e.stopPropagation(); }); me.element.on('click', function(){ - me.input.val(me.frequency); - me.input.show(); + currentExponent = me.exponent; + me.input.val(me.frequency / 10 ** me.exponent); + me.prefixInput.val(me.exponent); + me.inputGroup.show(); me.displayContainer.hide(); me.input.focus(); });