diff --git a/src/Makefile b/src/Makefile index c245a53..de34531 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,6 +23,7 @@ JSSRC= \ data/model/Realm.js \ data/model/Certificates.js \ data/model/ACME.js \ + form/BandwidthSelector.js \ form/DisplayEdit.js \ form/ExpireDate.js \ form/IntegerField.js \ diff --git a/src/form/BandwidthSelector.js b/src/form/BandwidthSelector.js new file mode 100644 index 0000000..ce941cd --- /dev/null +++ b/src/form/BandwidthSelector.js @@ -0,0 +1,154 @@ +Ext.define('Proxmox.form.SizeField', { + extend: 'Ext.form.FieldContainer', + alias: 'widget.pmxSizeField', + + mixins: ['Proxmox.Mixin.CBind'], + + viewModel: { + data: { + unit: 'MiB', + unitPostfix: '', + }, + formulas: { + unitlabel: (get) => get('unit') + get('unitPostfix'), + }, + }, + + emptyText: '', + + layout: 'hbox', + defaults: { + hideLabel: true, + }, + + units: { + 'B': 1, + 'KiB': 1024, + 'MiB': 1024*1024, + 'GiB': 1024*1024*1024, + 'TiB': 1024*1024*1024*1024, + 'KB': 1000, + 'MB': 1000*1000, + 'GB': 1000*1000*1000, + 'TB': 1000*1000*1000*1000, + }, + + // display unit (TODO: make (optionally) selectable) + unit: 'MiB', + unitPostfix: '', + + // use this if the backend saves values in another unit tha bytes, e.g., + // for KiB set it to 'KiB' + backendUnit: undefined, + + // allow setting 0 and using it as a submit value + allowZero: false, + + emptyValue: null, + + items: [ + { + xtype: 'numberfield', + cbind: { + name: '{name}', + emptyText: '{emptyText}', + allowZero: '{allowZero}', + emptyValue: '{emptyValue}', + }, + minValue: 0, + step: 1, + submitLocaleSeparator: false, + fieldStyle: 'text-align: right', + flex: 1, + enableKeyEvents: true, + setValue: function(v) { + if (!this._transformed) { + let fieldContainer = this.up('fieldcontainer'); + let vm = fieldContainer.getViewModel(); + let unit = vm.get('unit'); + + v /= fieldContainer.units[unit]; + v *= fieldContainer.backendFactor; + + this._transformed = true; + } + + if (Number(v) === 0 && !this.allowZero) { + v = undefined; + } + + return Ext.form.field.Text.prototype.setValue.call(this, v); + }, + getSubmitValue: function() { + let v = this.processRawValue(this.getRawValue()); + v = v.replace(this.decimalSeparator, '.'); + + if (v === undefined || v === '') { + return this.emptyValue; + } + + if (Number(v) === 0) { + return this.allowZero ? 0 : null; + } + + let fieldContainer = this.up('fieldcontainer'); + let vm = fieldContainer.getViewModel(); + let unit = vm.get('unit'); + + v = parseFloat(v) * fieldContainer.units[unit]; + v /= fieldContainer.backendFactor; + + return String(Math.floor(v)); + }, + listeners: { + // our setValue gets only called if we have a value, avoid + // transformation of the first user-entered value + keydown: function() { this._transformed = true; }, + }, + }, + { + xtype: 'displayfield', + name: 'unit', + submitValue: false, + padding: '0 0 0 10', + bind: { + value: '{unitlabel}', + }, + listeners: { + change: (f, v) => { + f.originalValue = v; + }, + }, + width: 40, + }, + ], + + initComponent: function() { + let me = this; + + me.unit = me.unit || 'MiB'; + if (!(me.unit in me.units)) { + throw "unknown unit: " + me.unit; + } + + me.backendFactor = 1; + if (me.backendUnit !== undefined) { + if (!(me.unit in me.units)) { + throw "unknown backend unit: " + me.backendUnit; + } + me.backendFactor = me.units[me.backendUnit]; + } + + me.callParent(arguments); + + me.getViewModel().set('unit', me.unit); + me.getViewModel().set('unitPostfix', me.unitPostfix); + }, +}); + +Ext.define('Proxmox.form.BandwidthField', { + extend: 'Proxmox.form.SizeField', + alias: 'widget.pmxBandwidthField', + + unitPostfix: '/s', +});